What python-specific antipatterns do you know?
Could you also give an example, please.
What python-specific antipatterns do you know?
Could you also give an example, please.
Mutable default arguments in functions or methods, like
def test(elem, start_list=[]):
start_list.append(elem)
return start_list
print test(1)
print test(2)
creates the output
[1]
[1, 2]
which is generally not what you want.
Mixing tabs and spaces.
I would say that programming in Python as if it were some other language is an "anti-pattern" i see quite often.
For example, for Java/C# refugees it is using classes for everything:
class Util():
@staticmethod
def foo():
...
# this should be just a function;
# it can be placed in 'util' module
def foo():
...
Another case:
class Pair():
def __init__(self, first, second):
...
pairs = [Pair(1, 2), Pair(3, 4)]
# usually built-in tuple is enough
pairs = [(1, 2), (3, 4)]
YES:
def safe_divide_2(x, y):
try:
return x/y
except ZeroDivisionError:
print "Divide-by-0 attempt detected"
return None
NO:
def safe_divide_1(x, y):
if y==0:
print "Divide-by-0 attempt detected"
return None
else:
return x/y
YES:
def double_list(items):
return [item * 2 for item in items]
NO:
def double_list(items):
doubled_items=[]
for item in items:
doubled_items.append(item*2)
return doubled_items
YES:
def gen():
for i in range(10):
yield i
for number in gen():
print i #prints 0-9
NO:
#list comprehension would be used here, but I did a for loop for clarity
def gen():
numlist=[]
for i in range(10):
numlist.append(i)
return numlist
for number in gen():
print i #prints 0-9
Inappropriate use of isinstance
.
People coming from static language backgrounds often completely miss the simplicity and flexibility of Python's dynamic polymorphism (aka duck typing).
This answer to another question provides a helpful discussion on Python polymorphism ignorance.
It's mentioned as part of nikow's answer but I thought it deserved a post of its own.
for i in xrange(len(something)):
workwith = something[i]
# do things with workwith...
From vartec's answer, but I think it's good (bad?) enough to deserve its own answer.
Not using python functions ;)
value = 0
for car in cars:
value += car.value
return value
# instead, do
return sum(car.value for car in cars)
Using Java-style getters and setters for every field:
def get_field(self):
return self.field
def set_field(self, val):
self.field = val
It's usually better just to access the field directly, and for more advanced usage you can smoothly transition to using property()
.
The Decorate-Sort-Undecorate idiom in later versions of Python where you can just use the key parameter.
deco = [(key(item), i, item) for i, item in enumerate(items)]
deco.sort()
final = [item for _, _, item in deco]
versus:
final = sorted(items, key=key)
Using positional arguments to fill keyword parameters.
e.g. given:
def foo(x, a=1, b=2):
# etc
calling it as:
foo(14, 21)
This always bugs me, though maybe it's because I have a short memory and without the clue of the keyword (a=21
) I forget what the argument means.
This is particularly prevalent in wxPython code.
Using map() or a list comprehension to perform a repeated operation on a sequence of items, instead of a for loop:
map(list.sort, list_of_lists)
[ lst.sort() for lst in list_of_lists ]
The telltale sign is that these statements create a list that is not assigned to anything. Why not just make your intent clear, that you want to iterate over a sequence and apply an operation to each item:
for lst in list_of_lists:
lst.sort()