Mmm... you should always use 'if x is not None:' imo. It's very common for libraries to make values evaluate to False, and very easy to get bugs if you just lazily test with 'if x'. Sqlalchemy springs to mind immediately as one of the common ones where using any() and if x: is a reeeeeallly bad idea; there are plenty of others. I'm pretty skpetical about modifying your coding behavior based on what libraries you happ…
It depends. If you're checking to see if that value is None, then yes - you should check that. If you're merely checking if the value is truthy, then using "if x:" is completely legitimate.
Anti-Patterns in Python Programming
131–140 of 242 posts
Re: Anti-Patterns in Python Programming
#132Earlier quoted context omitted.
I'm not a Python expert, but iirc from various blog posts the "l" variable does not get reset between function calls which will cause undesired behavior. So calling the function 3 times without argument would produce a list of size 1,2, and 3 with the third call rather than 3 lists of size 1. Can any Python guru's confirm?
Yes, that's correct. The default value is only interpreted once, when the `def` statement is called. After that point, it's completely mutable. You have to see Python functions as objects and default parameter values as object variables.
Re: Anti-Patterns in Python Programming
#133I always struggle to understand why a list comprehension alist = [foo(word) for word in words] is considered more Pythonic than map alist = map(foo, words)
List comprehensions are more flexible and easier to read in the non-trivial case. Sure in the trivial case you show a map might be considered neater, but just adding a filter is enough to make the list comprehension more readable in my mind. Python's lambda syntax also makes using maps and filters quite ugly. Compare: alist = [x**2 for x in mylist if x%3==0] to alist = map(lambda x: x**2,filter(lambda x: x%3==0, myli…
Re: Anti-Patterns in Python Programming
#134Point 3 of the iteration part is not good advice. With [1:] you're making a copy of the list just to iterate over it...
Re: Anti-Patterns in Python Programming
#135The more frequent and dangerous pitfalls are, in my humble opinion: - Bare except: statements (that catches everything , even Ctrl-C) - Mutables as default function/method arguments - Wildcard imports!
Couldn't agree more! One of my all time new python interview questions gets a surprisingly large number of developers. Given a function like: def append_one(l=[]): l.append(1) return l What does this return each time? >>> append_one() >>> append_one() >>> append_one()
Re: Anti-Patterns in Python Programming
#136Earlier quoted context omitted.
I do that all the time in the interpreter, especially when slicing pandas DataFrame objects, e.g.: df_subset = df['date buyer nwidgets'.split()] That is far easier to type than the explicit list, with all its punctuation. Now, it's definitely weird that they did a `split(" ")` rather than just using the default, but the idea is the same. I do try to strip stuff like that out before I put it into a script, replacing i…
It's not weird, it's wrong: In [1]: "a string r".split(" ") Out[1]: ['a', '', '', '', 'string', '', '', '', '', 'r'] In [2]: "a string r".split() Out[2]: ['a', 'string', 'r']
>>> filter(None, " quick hack for split".split(" "))
['quick', 'hack', 'for', 'split']Re: Anti-Patterns in Python Programming
#137Earlier quoted context omitted.
Depends on how you want to program: imperative vs functional. Personally I think list comprehensions are the most beautiful part of Python, though sometimes I use map() when I'm trying to be explicitly functional (I realize it's allegedly slower, etc). Generally I think list comprehensions are cleaner and allow you to write purer functions with fewer mutable variables. I disagree that deeply nested for loops are nece…
Map is not allegedly slower, it is demonstrably slower. $ python -mtimeit -s'nums=range(10)' 'map(lambda i: i + 3, nums)' 1000000 loops, best of 3: 1.61 usec per loop $ python -mtimeit -s'nums=range(10)' '[i + 3 for i in nums]' 1000000 loops, best of 3: 0.722 usec per loop Function calls have overhead in python, list comprehensions are implemented knowing this fact and avoiding it so the heavy lifting ultimately happ…
$ python -mtimeit -s'nums=range(10)' '[str(i) for i in nums]' 100000 loops, best of 3: 2.57 usec per loop
$ python -mtimeit -s'nums=range(10)' 'map(str, nums)' 1000000 loops, best of 3: 1.88 usec per loop
$ python -mtimeit -s'nums=range(10)' 'import math' '[math.sqrt(i) for i in nums]' 100000 loops, best of 3: 3.25 usec per loop
$ python -mtimeit -s'nums=range(10)' 'import math' 'map(math.sqrt, nums)' 100000 loops, best of 3: 2.55 usec per loop
Re: Anti-Patterns in Python Programming
#138The only thing I disagree with is "use nested comprehensions" thing. In my mind: x = [letter for word in words for letter in word] is inside-out or backwards or backwards. I want the nested for being the less specific case: x = [letter for letter in word for word in words] makes more sense in my mind. (It's also my first answer to the "what're some warts in the your language of choice).
I'm in the camp that if your list comp needs more than one for clause, it's complicated enough to be broken out into actual for loop.
Re: Anti-Patterns in Python Programming
#139Earlier quoted context omitted.
I'm not a Python expert, but iirc from various blog posts the "l" variable does not get reset between function calls which will cause undesired behavior. So calling the function 3 times without argument would produce a list of size 1,2, and 3 with the third call rather than 3 lists of size 1. Can any Python guru's confirm?
The expression presented in the parameter list is only evaluated once, and that is when the method is defined. The confusion is that people assume the expression is evaluated every time the method is called.
Because that's how it works in a lot of other languages, such as Ruby and Javascript.
Re: Anti-Patterns in Python Programming
#140Earlier quoted context omitted.
It has something to do with mutability, because if an object is immutable, the behavior of Python matches what the naive developer expects. It's only mutable objects that break those expectations. Don't even get into unexpected behavior in classes: In [1]: class A(object): ...: l = [] ...: In [2]: a, b = A(), A() In [3]: a.l.append("Something") In [4]: a.l Out[4]: ['Something'] In [5]: b.l Out[5]: ['Something'] In [6…
> if an object is immutable, the behavior of Python matches what the naive developer expects If the object was immutable then append wouldn't work. That's hardly matching expectations.
I guess the clarification to what I was saying is that, in the simple case (integers, strings, None) the objects are immutable. It's only getting into cases where the value of the object itself is mutable, that you run into issues. If all objects (or all objects 'allowed' as default values) were immutable, then this behavior would not trigger.
So saying that mutability has nothing to do with it isn't entirely true. It's the immutability of the types of values used in most simple cases that hides this issue from developers until they run into a more complex case.