Is there a more efficient one liner to initialize a variable based on a condition?
Can the atype
variable be initialized via a one lin开发者_运维百科er ?
def detect(dt,result):
""" prints the type of date """
atype = 'unknown'
if 'greg' in result:
atype = 'Gregorian'
elif 'eth' in result:
atype = 'Ethiopian'
print '%s is in %s format.' % (dt,atype)
You could use a pair of conditional expressions — and no parenthesis are necessary at all; just like Python knows that 1 + 2 + 3
should be done reasonably from left-to-right, so conditional expressions can be written with one clause after another without any fear of the interpreter getting confused. Line breaks and indentation are important for readability, however, so I generally do something like this:
atype = ('Gregorian' if 'greg' in result
else 'Ethiopian' if 'eth' in result
else 'unknown')
This form of indentation is not only the one that most editors will produce in any case if you press "enter" before each else
, but it makes a great deal of visual sense to me when I come back later and read my own, or someone else's, code — which is, after all, a big reason we use Python, right? :)
Edit: Of course I realize that this is a one-liner only in the sense that Python sees the continued line as a single line of code; so I guess my answer is that your program would seem a bit dense to me as one physical line of Python, but works quite nicely to my eyes if written as one logical line of Python!
Edit: One further note: of course, I recognize that my code snippet violates PEP-8, which says to end continued lines with operators — so PEP-8 would have me move the else
words up to the ends of the previous lines. I can only say that this is one of the rules of PEP-8 that I disagree with, which I regularly break, and that therefore I produce more readable code as a result. I think my difference with PEP-8 on this point comes from having a math typesetting background, and, as Donald Knuth emphasizes in the TeXBook, “displayed formulas always break before binary operations and relations” (p.195).
Not sure if this is meaningful and readable...
atype = 'Gregorian' if 'greg' in result else ('Ethiopian' if 'eth' in result else 'unknown')
Personally, on a forum, I propose
def detect(dt,result):
""" prints the type of date """
style = 'Gregorian' if 'greg' in result else\
'Ethiopian' if 'eth' in result else\
'unknown'
print '%s is in %s format.' % (dt,style)
and in the secret of my codes where nobody will come to see if I respect the Zen of Python, I would do in fact:
def detect(dt,result):
""" prints the type of date """
print dt + ' is in %s format.'\
% \
'Gregorian' if 'greg' in result else\
'Ethiopian' if 'eth' in result else\
'unknown'
I measured execution's times: the second runs in 89 % of the time of the first
.
EDIT 1
The test I conducted didn't satisfy me, in the end, because it isn't fair to compare a program in which an assignement is done (style = etc) to a program in which there is no equivalent assignement.
So I tested again, with modified codes.To accentuate the influence of differences between the codes, I added some lines of conditions.
I ran the following programs separately (to avoid possible persistence of objects that would be reassigned without having to be re-created; I don't precisely know what happens in the memory and the object model of Python, and if it may happen in fact; but I sometimes observe strange phenomenons when I measure execution's time. So I take no risk, I separate the codes)
first program
from time import clock
A=[]
for repeat in xrange(5000):
def detect(dt,result):
if 'greg' in result:
h = '%s is in %s format.' % (dt,'Gregorian')
elif 'eth' in result:
h = '%s is in %s format.' % (dt,'Ethiopian')
elif 'ame' in result:
h = '%s is in %s format.' % (dt,'American')
elif 'rus' in result:
h = '%s is in %s format.' % (dt,'Russian')
elif 'egyp' in result:
h = '%s is in %s format.' % (dt,'Egyptian')
else:
h = '%s is in unknown format.' % dt
te = clock()
for i in xrange(10000):
detect('zozo',' he is egyptolog')
A.append(clock() - te)
print min(A)
second program
from time import clock
B=[]
for repeat in xrange(5000):
def detect(dt,result):
x = '%s is in %s format.' % (dt,'Gregorian' if 'greg' in result else\
'Ethiopian' if 'eth' in result else\
'American' if 'ame' in result else\
'Russian' if 'rus' in result else\
'Egyptian' if 'egyp' in result else\
'unknown')
te = clock()
for i in xrange(10000):
detect('zozo',' he is egyptolog')
B.append(clock() - te)
print min(B)
third program
from time import clock
C = []
for repeat in xrange(1000):
def detect(dt,result):
y = dt + ' is in %s format.'\
% \
'Gregorian' if 'greg' in result else\
'Ethiopian' if 'eth' in result else\
'American' if 'ame' in result else\
'Russian' if 'rus' in result else\
'Egyptian' if 'egyp' in result else\
'unknown'
te = clock()
for i in xrange(10000):
detect('zozo',' he is egyptolog')
C.append(clock() - te)
print min(C)
.
I obtained
0.0198832 seconds
0,019962 seconds
0,012664 seconds
Conclusions:
there is no difference between the way of writing the code with if-elif-else conditions or with if-else-else-else successive conditions.
Then, even if the second manner isn't so atrocious than delnan think, it is slightly less immediately understandable, so I finally find that the first manner of writing is better than the second one because of the perfect readibility, without loosing any amount of performance.
Use of if-else-else is interesting and the only solution in certain cases, when it is impossible to use if-elif-else, for exemple in a list comprehension or to write a lambda function.
this time, my code runs in 64 % the time of the two other execution's times. The more there are conditions to examine, the faster is my code
If someone is concerned by performance, this solution is the one to use. If not, a succession of if-elif-else conditions appears to me the best choice.
.
EDIT 2
@eat,
Suppose that a list of one million elements, like this one
li = [('greg','Gregorian'),('eth','Ethiopian')]
has been recorded in serialized format with cPickle. Then the code will be:
import cPickle
with open('trynewline.txt','r') as f:
li = cPickle.load(f)
def detect(dt,result):
for a,b in li:
if a in result:
return '%s is in %s format.' % (dt,b)
else:
return '%s is in unknown format.' % dt
or
import cPickle
with open('trynewline.txt','r') as f:
li = cPickle.load(f)
def detect(dt,result):
ha = [ b for a,b in li if a in result]
y = dt + ' is in %s format.'\
% (ha[0] if ha else 'unknown')
That's all. Anyway, the data contained in li must come from somewhere. It can be automatically produced; or it is manually produced. If it is manually produced and nobody created before me, I will be obliged to write manually the one million conditions myself. And if it is you that will have to write the code, you will do that also. I don't see how you could avoid it with your dictionary.
Yep, Python's variable's scope is a bit different than in other programming languages. So,
if 'greg' in result:
atype = 'Gregorian'
print(atype)
Will do just fine. Also
if 'greg' in result: atype = 'Gregorian'
print(atype)
Will work, unless it's a Python shell (you have to execute the whole script)
But anyway, it's a bad practice to make very long, condition-dependent variable initializations.
actually strange but..it's just a different way to do it..I think it is easier to extend, but i guess there is a better way ;)
import operator as op
import functools as fc
atype = {'greg':'Gregorian', 'eth':'Ethiopian'}.get(filter(fc.partial(op.contains, ('greg', 'eth')), res)[0], 'unknown')
Although there's a separate line to set up a dictionary, here's an a one-liner (spread over two for readability):
typemap = {'greg': 'Gregorian', 'eth': 'Ethiopian'}
atype = ([typemap[frag] for frag in typemap if frag in result][0]
if any(frag in result for frag in typemap) else 'unknown')
精彩评论