Записки программиста, обо всем и ни о чем. Но, наверное, больше профессионального.

2014-07-21

10 распространенных ошибок

На Топтале (toptal.com) есть подборка статей типа «10 наиболее распространенных ошибок у программеров на Х», где Х — некий язык программирования.
Нас, конечно, в первую очередь интересует Python

Далее я кратенько пройдусь по списку.

1. дефолтные значения аргументов
>>> def foo(bar=[]):        # bar is optional and defaults to [] if not specified
...    bar.append("baz")    # but this line could be problematic, as we'll see...
...    return bar
попробуйте вызвать функцию подряд несколько раз без параметра.
Фишка в том, что дефолтная переменная инициируется только один раз а не при каждом вызове.
Ну не знаю кто как, а нас учили, что писать во входные параметры — не православно. Посему на эти грабли я никогда не наступал.

2. переменные класса
>>> class A(object):
...     x = 1
...
>>> class B(A):
...     pass
...
>>> class C(A):
...     pass
...
>>> print A.x, B.x, C.x
1 1 1
>>> B.x = 2
>>> print A.x, B.x, C.x
1 2 1
>>> A.x = 3
>>> print A.x, B.x, C.x
3 2 3
What the $%#!&?? We only changed A.x. Why did C.x change too?
По моему тут всё очевидно, класс С наследует переменную от А. Опять же, нас учили использовать конструкторы при работе с классами, поэтому эти грабли тоже мне не знакомы.

3. параметры при отлове иксепшенов
>>> try:
...     l = ["a", "b"]
...     int(l[2])
... except ValueError, IndexError:  # To catch both exceptions, right?
...     pass
...
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
IndexError: list index out of range
чиста проблема с синтаксисом, см.документацию.
Правильный способ указать несколько отлавливаемых иксепшенов
>>> try:
...     l = ["a", "b"]
...     int(l[2])
... except (ValueError, IndexError) as e:  
...     pass
Должен признаться, грешен. Я, ленивая обезьяна, обычно отлавливаю одно наиболее общее исключение, хотя это и не православно. Зато работает. Грабли мимо.

4. запись в глобальные переменные
>>> x = 10
>>> def foo():
...     x += 1
...     print x
...
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'x' referenced before assignment
читать можно, писать уже не получается. Во первых, писать в глобальные переменные — mauvais ton, простите мой французский. Во вторых, учим матчасть, ключевое слово global. Обратно мимо.

5. перебирая список менять его
>>> numbers = [n for n in range(10)]
>>> for i in range(len(numbers)):
...     if odd(numbers[i]):
...         del numbers[i]  # BAD: Deleting item from a list while iterating over it
...
Traceback (most recent call last):
     File "<stdin>", line 2, in <module>
IndexError: list index out of range
Без комментариев. Что-то я начал раздражаться, что это за грабли они выкапывают?
Ну это вообще ни в какие ворота. Где они находят таких программистов? Руки за это отрывать сразу. Детский сад какой-то. Если это одна из наиболее частых ошибок программистов на Топтале, то не желаю иметь с ними никаких программистских дел.

6. позднее связывание
>>> def create_multipliers():
...     return [lambda x : i * x for i in range(5)]
>>> for multiplier in create_multipliers():
...     print multiplier(2)
...
You might expect the following output:
0
2
4
6
8

But you actually get:
8
8
8
8
8
На момент вызова лямбдоидов, переменная i уже посчитана и заново не высчитывается.
Как-то мне не попадались такие случаи. Можеть быть потому, что я лямбды не слишком уважаю? Опять же, зачем генерировать список, когда можно генерировать итератор?
Вообще, подтверждаю потенциальные грабли, увлекшись можно и наступить.

7. циклические зависимости в модулях
# In a.py:
import b
def f():
    return b.x
print f()

# And in b.py:
import a
x = 1
def g():
    print a.f()
Теоретически, такое случается. Если уж это произошло, следует разобраться с архитектурой, дизайном и прочей декомпозицией. Что-то тут не так. Надо переделать. А если переделывать лень, делайте импорт внутри функции, это спасет нерадивую обезьяну.
Не грабли это а грязный дизайн.

8. использование имен зарезервированных стандартными библиотеками.
Опять же, мойте руки перед едой и чистите зубы после простые правила гигиены позволяют избегать такой напасти. Неймспейсы, префиксы и постфиксы, не поддавайтесь соблазну использовать общеупотребимые имена типа «count», «len» и проч. Если кто на эти грабли и наступает, то только новичок.

9. разница между Python 2 и Python 3
например, области видимости
import sys

def bar(i):
    if i == 1:
        raise KeyError(1)
    if i == 2:
        raise ValueError(2)

def bad():
    e = None
    try:
        bar(int(sys.argv[1]))
    except KeyError as e:
        print('key error')
    except ValueError as e:
        print('value error')
    print(e)

bad()
В Python 2 это работает как и ожидается. В третьем мы получим
UnboundLocalError: local variable 'e' referenced before assignment
Честно говоря, называть ошибками программиста то, что в Python 3 не работает код написанный для Python 2, это наглость. Но в данном конкретном случае мы наблюдаем опять нарушение гигиены. Для доступа к содержимому иксепшенов снаружи их блока необходимо сохранить значение во внешней переменной. И не называть ее тем же именем. Все таки, опыт написания программ на C/C++ сильно помогает не ходить по таким «граблям», поверьте. А лучше проверьте на себе.

10. порядок уничтожения объектов
import foo
class Bar(object):
        ...
    def __del__(self):
        foo.cleanup(self.myhandle)
при завершении интерпретатора он сначала зачистит глобальные объекты, поэтому foo.cleanup страшно обломается.
Теоретически, я могу представить себе ситуацию, когда в деструкторе надо вызвать внешний модуль. С другой стороны, нафига нужен деструктор, срабатывающий при закрытии интерпретатора? Все ресурсы будут освобождены по любому. В целом, настолько редкая ситуация, что мне ни разу не попадалась. Но, теоретически, может. Потенциальные грабли для меня №2.


Общий вывод: тесты, тесты и еще раз тесты. Не думайте, что вы знаете как работает ваша программа. Только тесты могут доказать, что работает она как задумано.


Ну и, конечно, надо себя похвалить — я крут. Из 10 популярных граблей мне грозят только 2 штуки и то очень потенциально.


original post http://vasnake.blogspot.com/2014/07/10.html

Комментариев нет:

Отправить комментарий

Архив блога

Ярлыки

linux (241) python (191) citation (186) web-develop (170) gov.ru (159) video (124) бытовуха (115) sysadm (100) GIS (97) Zope(Plone) (88) бурчалки (84) Book (83) programming (82) грабли (77) Fun (76) development (73) windsurfing (72) Microsoft (64) hiload (62) internet provider (57) opensource (57) security (57) опыт (55) movie (52) Wisdom (51) ML (47) driving (45) hardware (45) language (45) money (42) JS (41) curse (40) bigdata (39) DBMS (38) ArcGIS (34) history (31) PDA (30) howto (30) holyday (29) Google (27) Oracle (27) tourism (27) virtbox (27) health (26) vacation (24) AI (23) Autodesk (23) SQL (23) humor (23) Java (22) knowledge (22) translate (20) CSS (19) cheatsheet (19) hack (19) Apache (16) Klaipeda (15) Manager (15) web-browser (15) Никонов (15) functional programming (14) happiness (14) music (14) todo (14) PHP (13) course (13) scala (13) weapon (13) HTTP. Apache (12) SSH (12) frameworks (12) hero (12) im (12) settings (12) HTML (11) SciTE (11) USA (11) crypto (11) game (11) map (11) HTTPD (9) ODF (9) Photo (9) купи/продай (9) benchmark (8) documentation (8) 3D (7) CS (7) DNS (7) NoSQL (7) cloud (7) django (7) gun (7) matroska (7) telephony (7) Microsoft Office (6) VCS (6) bluetooth (6) pidgin (6) proxy (6) Donald Knuth (5) ETL (5) NVIDIA (5) Palanga (5) REST (5) bash (5) flash (5) keyboard (5) price (5) samba (5) CGI (4) LISP (4) RoR (4) cache (4) car (4) display (4) holywar (4) nginx (4) pistol (4) spark (4) xml (4) Лебедев (4) IDE (3) IE8 (3) J2EE (3) NTFS (3) RDP (3) holiday (3) mount (3) Гоблин (3) кухня (3) урюк (3) AMQP (2) ERP (2) IE7 (2) NAS (2) Naudoc (2) PDF (2) address (2) air (2) british (2) coffee (2) fitness (2) font (2) ftp (2) fuckup (2) messaging (2) notify (2) sharepoint (2) ssl/tls (2) stardict (2) tests (2) tunnel (2) udev (2) APT (1) Baltic (1) CRUD (1) Canyonlands (1) Cyprus (1) DVDShrink (1) Jabber (1) K9Copy (1) Matlab (1) Portugal (1) VBA (1) WD My Book (1) autoit (1) bike (1) cannabis (1) chat (1) concurrent (1) dbf (1) ext4 (1) idioten (1) join (1) krusader (1) license (1) life (1) migration (1) mindmap (1) navitel (1) pneumatic weapon (1) quiz (1) regexp (1) robot (1) science (1) seaside (1) serialization (1) shore (1) spatial (1) tie (1) vim (1) Науру (1) крысы (1) налоги (1) пианино (1)