Вопрос по python – Распространенные подводные камни в Python [дубликаты]

75

Possible Duplicate:
Python 2.x gotcha’s and landmines

Сегодня меня снова укусили изменчивые аргументы по умолчанию после многих лет. Я обычно не использую изменяемые аргументы по умолчанию, если в этом нет необходимости, но, думаю, со временем я об этом забыл. Сегодня в приложении я добавил tocElements = [] в список аргументов функции генерации PDF, а теперь "Оглавление". становится все длиннее и длиннее после каждого вызова & quot; генерировать pdf & quot ;. :)

Что еще я должен добавить в свой список вещей, которых ДОЛЖЕН избегать?

Always import modules the same way, e.g. from y import x and import x are treated as different modules.

Do not use range in place of lists because range() will become an iterator anyway, the following will fail:

myIndexList = [0, 1, 3]
isListSorted = myIndexList == range(3)  # will fail in 3.0
isListSorted = myIndexList == list(range(3))  # will not

Same thing can be mistakenly done with xrange:

myIndexList == xrange(3)

Be careful catching multiple exception types:

try:
    raise KeyError("hmm bug")
except KeyError, TypeError:
    print TypeError

This prints "hmm bug", though it is not a bug; it looks like we are catching exceptions of both types, but instead we are catching KeyError only as variable TypeError, use this instead:

try:
    raise KeyError("hmm bug")
except (KeyError, TypeError):
    print TypeError
Использоватьrange() как список в Python 2.x. Это скрипт для 2to3, чтобы преобразовать его вlist(range()) в Python 3.x jfs
stackoverflow.com/questions/530530/… - не является ли этот вопрос оригинальным? zeroDivisible
Меня больше интересовали вещи, которых ДОЛЖНЫ избегать, похоже, есть только один кандидат Anurag Uniyal
@Narek: Что такое «нормальный»? язык программирования? Esteban Küber
Я рекомендую использовать Pylint, он ловит много этих ошибок. Я использую его интегрированный с затмением (pydev). monkut

Ваш Ответ

29   ответов
4

и одна из самых больших ошибок, которые я совершил, - это постоянное использование индекса C ++ / C # для & quot; петля. У Python есть цикл типа (i; i & lt; length; i ++), и на то есть веская причина - в большинстве случаев существуют лучшие способы сделать то же самое.

Пример: У меня был метод, который перебирает список и возвращает индексы выбранных элементов:

for i in range(len(myList)):
    if myList[i].selected:
        retVal.append(i)

Вместо этого в Python есть списки, которые решают ту же проблему более элегантно и легко читаемым способом:

retVal = [index for index, item in enumerate(myList) if item.selected]
3

odd = lambda x : bool(x % 2)
numbers = range(10)
for i in range(len(numbers)):
    if odd(numbers[i]):
        del numbers[i]

Одним из распространенных предложений для обхода этой проблемы является перебор списка в обратном порядке:

for i in range(len(numbers)-1,0,-1):
    if odd(numbers[i]):
        del numbers[i]

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

numbers[:] = [n for n in numbers if not odd(n)]
11

Mix tab and spaces when indenting.

Действительно, это убийца. Поверь мне.In particular, если это работает.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
25

def foo(bar=[]):
    bar.append('baz')
    return bar

Значение по умолчанию оценивается только один раз, а не каждый раз, когда вызывается функция. Повторные звонки наfoo() вернется['baz'], ['baz', 'baz'], ['baz', 'baz', 'baz'], ...

Если вы хотите изменить строку, сделайте что-то вроде этого:

def foo(bar=None):
    if bar is None:
        bar = []

    bar.append('baz')
    return bar

Или, если вы хотите, чтобы аргументы были окончательными:

def foo(bar=[]):
    not_bar = bar[:]

    not_bar.append('baz')
    return not_bar
Error: User Rate Limit Exceededstackoverflow.com/questions/959113/…
Error: User Rate Limit Exceeded
21

является ли это распространенной ошибкой, но, хотя в Python нет операторов увеличения и уменьшения, допускаются двойные знаки, поэтому

++i

а также

--i

является синтаксически правильным кодом, но не делает ничего «полезного» или что вы можете ожидать.

Error: User Rate Limit ExceedednotError: User Rate Limit Exceeded--iError: User Rate Limit Exceeded-(-i) == iError: User Rate Limit Exceeded---i = -iError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededdocs.python.org/reference/…)
33

у вас может возникнуть желание напечатать что-то вроде этого:

>>> a=[[1,2,3,4,5]]*4

И, конечно же, это даст вам то, что вы ожидаете, когда вы смотрите на это

>>> from pprint import pprint
>>> pprint(a)

[[1, 2, 3, 4, 5],
 [1, 2, 3, 4, 5],
 [1, 2, 3, 4, 5],
 [1, 2, 3, 4, 5]]

Но не ожидайте, что элементы вашего населения будут отдельными объектами:

>>> a[0][0] = 2
>>> pprint(a)

[[2, 2, 3, 4, 5],
 [2, 2, 3, 4, 5],
 [2, 2, 3, 4, 5],
 [2, 2, 3, 4, 5]]

Если это не то, что вам нужно ...

Стоит упомянуть обходной путь:

a = [[1,2,3,4,5] for _ in range(4)]
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededignoredError: User Rate Limit Exceeded
Error: User Rate Limit Exceededstackoverflow.com/q/240178/190597
6

X and Y or Z для встроенной логики.

Если вы не можете на 100% всегда гарантировать, чтоY будет истинным значением, даже если ваш код изменится через 18 месяцев, вы настроите себя на неожиданное поведение.

К счастью, в более поздних версиях вы можете использоватьY if X else Z.

Error: User Rate Limit Exceeded(X and [y] or [z])[0]
Error: User Rate Limit Exceedednot notError: User Rate Limit Exceeded
7
don't write large output messages to standard output strings are immutable - build them not using "+" operator but rather using str.join() function. read those articles: python gotchas things to avoid Gotchas for Python users Python Landmines

этот вопрос является дубликатом.

Error: User Rate Limit Exceededstr.joinError: User Rate Limit Exceededstr.formatError: User Rate Limit Exceeded
6

чтобы ваше приложение или скрипт были готовы и их было легче конвертировать в Python 3.

8

re и использование полного подхода регулярных выражений для сопоставления / преобразования строк, когда это совершенно хорошостроковые методы существуют для каждой обычной операции (например, использование заглавных букв, простое сопоставление / поиск).

Error: User Rate Limit Exceeded
7

%s Форматер в сообщениях об ошибках. Почти в любых обстоятельствах%r должен быть использован.

Например, представьте код, подобный следующему:

try:
    get_person(person)
except NoSuchPerson:
    logger.error("Person %s not found." %(person))

Напечатал эту ошибку:

ERROR: Person wolever not found.

Невозможно сказать, является лиperson переменная это строка"wolever"Строка Юникодаu"wolever" или экземплярPerson класс (который имеет__str__ определяется какdef __str__(self): return self.name). Тогда как, если%r было бы три разных сообщения об ошибках:

...
logger.error("Person %r not found." %(person))

Будет производить гораздо более полезные ошибки:

ERROR: Person 'wolever' not found.
ERROR: Person u'wolever' not found.
ERROR: Person  not found.

Еще одна веская причина для этого заключается в том, что пути намного проще копировать / вставлять. Представить:

try:
    stuff = open(path).read()
except IOError:
    logger.error("Could not open %s" %(path))

Еслиpath являетсяsome path/with 'strange' "characters"сообщение об ошибке будет:

ERROR: Could not open some path/with 'strange' "characters"

Который трудно визуально разобрать и трудно скопировать / вставить в оболочку.

Тогда как, если%r используется, ошибка будет:

ERROR: Could not open 'some path/with \'strange\' "characters"'

Легко визуально разбирать, легко копировать-вставлять, все вокруг лучше.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded.formatError: User Rate Limit ExceededreprError: User Rate Limit ExceededstrError: User Rate Limit Exceeded{0!r}Error: User Rate Limit Exceeded{0}.
2

default arguments are evaluated once:

def x(a, l=[]):
    l.append(a)
    return l

print x(1)
print x(2)

печатает:

[1]
[1, 2]

то есть вы всегда получаете один и тот же список.

17

прежде чем заглядывать в стандартную библиотеку. Например, написать это:

def repeat_list(items):
    while True:
        for item in items:
            yield item

Когда вы можете просто использовать это:

from itertools import cycle

Примеры часто пропускаемых модулей (помимоitertools) включают:

optparse for creating command line parsers ConfigParser for reading configuration files in a standard manner tempfile for creating and managing temporary files shelve for storing Python objects to disk, handy when a full fledged database is overkill
Error: User Rate Limit Exceeded
28

которые терпят неудачу очень неясными способами

Using mutable default arguments.

Leading zeroes mean octal. 09 is a very obscure syntax error in Py,thon 2.x

Misspelling overridden method names in a superclass or subclass. The superclass misspelling mistake is worse, because none of the subclasses override it correctly.

Python Design Gotchas

Spending time on introspection (e.g. trying to automatically determine types or superclass identity or other stuff). First, it's obvious from reading the source. More importantly, time spent on weird Python introspection usually indicates a fundamental failure to grasp polymorphism. 80% of the Python introspection questions on SO are failure to get Polymorphism.

Spending time on code golf. Just because your mental model of your application is four keywords ("do", "what", "I", "mean"), doesn't mean you should build a hyper-complex introspective decorator-driven framework to do that. Python allows you to take DRY to a level that is silliness. The rest of the Python introspection questions on SO attempts to reduce complex problems to code golf exercises.

Monkeypatching.

Failure to actually read through the standard library, and reinventing the wheel.

Conflating interactive type-as-you go Python with a proper program. While you're typing interactively, you may lose track of a variable and have to use globals(). Also, while you're typing, almost everything is global. In proper programs, you'll never "lose track of" a variable, and nothing will be global.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Anurag Uniyal
3

как проверяется наличие «отсутствующего» quot; case приводит к различиям при передаче пустого списка:

def func1(toc=None):
    if not toc:
        toc = []
    toc.append('bar')

def func2(toc=None):
    if toc is None:
        toc = []
    toc.append('bar')

def demo(toc, func):
    print func.__name__
    print '  before:', toc
    func(toc)
    print '  after:', toc

demo([], func1)
demo([], func2)

Вот результат:

func1
  before: []
  after: []
func2
  before: []
  after: ['bar']
Error: User Rate Limit Exceededis NoneError: User Rate Limit ExceedednotError: User Rate Limit Exceeded
10
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Anurag Uniyal
3
my_variable = <something>
...
my_varaible = f(my_variable)
...
use my_variable and thinking it contains the result from f, and not the initial value

что во втором назначении вы неправильно написали имя переменной и создали новое.

Error: User Rate Limit ExceededbreakfastError: User Rate Limit Exceededspam()Error: User Rate Limit Exceededeggs()Error: User Rate Limit Exceeded[spam(), eggs()]Error: User Rate Limit Exceeded"spam".
Error: User Rate Limit Exceededperson = "joe"; person = get_person_by_name(person)Error: User Rate Limit Exceededperson_name = "joe"; person = get_person_by_name(person_name)
3

don't be afraid of whitespace.

Когда вы показываете кому-то кусок кода Python, они впечатляются, пока вы не скажете им, что ониhave правильно сделать отступ По некоторым причинам большинство людей считают, что язык не должен навязывать им определенный стиль, в то время как все они, тем не менее, будут отступать от кода.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
13

аторов.

Кроме того, это всегда хорошо, чтобы не использоватьfrom somemodule import *.

Error: User Rate Limit Exceededfrom ... import *Error: User Rate Limit Exceeded
1
Promiscuous Exception Handling

что я вижу удивительное количество в производственном коде, и это заставляет меня съеживаться.

try:
    do_something() # do_something can raise a lot errors e.g. files, sockets
except:
    pass # who cares we'll just ignore it

Было ли исключение то, которое вы хотите подавить, или оно более серьезное? Но есть и более тонкие случаи. Это может заставить вас вырвать волосы, пытаясь понять.

try: 
    foo().bar().baz()
except AttributeError: # baz() may return None or an incompatible *duck type*
    handle_no_baz() 

Проблема в том, что foo или baz тоже могут быть виновниками. Я думаю, что это может быть более коварным в том, что этоidiomatic python где вы проверяете ваши типы для правильных методов. Но у каждого вызова метода есть шанс вернуть что-то неожиданное и подавить ошибки, которые должны вызывать исключения.

Знание того, какие исключения может вызвать метод, не всегда очевидно. Например, urllib и urllib2 используют сокет, который имеет свои собственные исключения, которые просачиваются вверх и назад по уродливой голове, когда вы меньше всего этого ожидаете.

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

4
import this    


Явное лучше, чем неявное.
Простое лучше, чем сложное.
Сложный лучше, чем сложный.
Квартира лучше, чем вложенная.
Разреженный лучше, чем плотный.
Читаемость имеет значение.
Особые случаи не настолько особенные, чтобы нарушать правила.
Хотя практичность превосходит чистоту.
Ошибки никогда не должны проходить бесшумно.
Если явно не молчать.
Перед лицом двусмысленности откажитесь от соблазна гадать.
Должен быть один - и желательно только один - очевидный способ сделать это.
Хотя этот способ может быть неочевидным на первый взгляд, если только вы не голландец.
Сейчас лучше, чем никогда.
Хотя никогда не бывает лучше, чемright сейчас.
Если реализацию трудно объяснить, это плохая идея.
Если реализацию легко объяснить, это может быть хорошей идеей.
Пространства имен - это одна из отличных идей - давайте сделаем больше таких!

import not_this

Напишите некрасивый код.
Написать неявный код.
Написать сложный код.
Напишите вложенный код.
Напишите плотный код.
Написать нечитаемый код.
Напишите особые случаи.
Стремитесь к чистоте.
Игнорировать ошибки и исключения.
Напишите оптимальный код перед выпуском.
Каждой реализации нужна блок-схема.
Не используйте пространства имен.

Error: User Rate Limit Exceeded
4

что наличие многопоточного приложения Python и компьютера с поддержкой SMP (например, оснащенного многоядерным процессором) даст вам преимущество введения истинного параллелизма в ваше приложение. Скорее всего, это не из-за GIL (Global Interpreter Lock), который синхронизирует ваше приложение на уровне интерпретатора байт-кода.

Есть некоторые обходные пути, такие как использование преимущества SMP путем помещения параллельного кода в вызовы C API или использование нескольких процессов (вместо потоков) через оболочки (например, как тот, который доступен вhttp://www.parallelpython.org) но если вам нужна истинная многопоточность в Python, следует взглянуть на такие вещи, как Jython, IronPython и т. д. (GIL является функцией интерпретатора CPython, поэтому другие реализации не затрагиваются).

В соответствии с Python 3000 FAQ (доступно на Artima) выше все еще стоит даже для последних версий Python.

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
4

NOT чтобы:

use deprecated modules (use warnings for them)

overuse classes and inheritance (typical of static languages legacy maybe)

explicitly use declarative algorithms (as iteration with for vs use of itertools)

reimplement functions from the standard lib, "because I don't need all of those features"

using features for the sake of it (reducing compatibility with older Python versions)

using metaclasses when you really don't have to and more generally make things too "magic"

avoid using generators

(more personal) try to micro-optimize CPython code on a low-level basis. Better spend time on algorithms and then optimize by making a small C shared lib called by ctypes (it's so easy to gain 5x perf boosts on an inner loop)

use unnecessary lists w,hen iterators would suffice

code a project directly for 3.x before the libs you need are all available (this point may be a bit controversial now!)

3

который почти так же плох, как изменяемые аргументы по умолчанию: значения по умолчанию, которые не являютсяNone.

Рассмотрим функцию, которая будет готовить еду:

def cook(breakfast="spam"):
    arrange_ingredients_for(breakfast)
    heat_ingredients_for(breakfast)
    serve(breakfast)

Потому что он определяет значение по умолчанию дляbreakfastдля какой-либо другой функции невозможно сказать «готовить завтрак по умолчанию»; без особого случая:

def order(breakfast=None):
    if breakfast is None:
        cook()
    else:
        cook(breakfast)

Однако этого можно избежать, еслиcook используемыйNone в качестве значения по умолчанию:

def cook(breakfast=None):
    if breakfast is None:
        breakfast = "spam"

def order(breakfast=None):
    cook(breakfast)

Хорошим примером этого является ошибка Джанго#6988, Модуль кэширования в Django имеет функцию «сохранить в кэш»; функция, которая выглядела так:

def set(key, value, timeout=0):
    if timeout == 0:
        timeout = settings.DEFAULT_TIMEOUT
    _caching_backend.set(key, value, timeout)

Но для memcached серверной части тайм-аут0 означает «никогда не истекает» & # x2026; Который, как вы видите, будет невозможно определить.

Error: User Rate Limit Exceeded Anurag Uniyal
1

что и у stdlib. Это почти всегда делается случайно (как сообщается вэтот вопрос), но обычно приводит к загадочным сообщениям об ошибках.

11

зрения стиля, это ошибка с точки зрения скорости, потому что многие функциональные инструменты оптимизированы в C.

Это самый распространенный пример:

temporary = []
for item in itemlist:
    temporary.append(somefunction(item))
itemlist = temporary

Правильный способ сделать это:

itemlist = map(somefunction, itemlist)

Как правильно сделать это:

itemlist = [somefunction(x) for x in itemlist]

И если вам нужны только обработанные элементы, доступные по одному, а не все сразу, вы можете сэкономить память и повысить скорость, используя итеративные эквиваленты.

# itertools-based iterator
itemiter = itertools.imap(somefunction, itemlist)
# generator expression-based iterator
itemiter = (somefunction(x) for x in itemlist)
4

++n а также--n может работать не так, как ожидалось людьми из C или Java.

++n является положительным положительным числом, которое простоn.

--n отрицательно от отрицательного числа, которое простоn.

13

то поймите, что переменные, объявленные в определении класса, являются статическими. Вы можете инициализировать нестатические элементы вinit метод.

Пример:

class MyClass:
  static_member = 1

  def __init__(self):
    self.non_static_member = random()
69

Don't use index to loop over a sequence

Don 't:

for i in range(len(tab)) :
    print tab[i]

Делать :

for elem in tab :
    print elem

For автоматизирует большинство итерационных операций для вас.

использованиеenumerate если вам действительно нужен и индекс, и элемент.

for i, elem in enumerate(tab):
     print i, elem

Be careful when using "==" to check against True or False

if (var == True) :
    # this will execute if var is True or 1, 1.0, 1L

if (var != True) :
    # this will execute if var is neither True nor 1

if (var == False) :
    # this will execute if var is False or 0 (or 0.0, 0L, 0j)

if (var == None) :
    # only execute if var is None

if var :
    # execute if var is a non-empty string/list/dictionary/tuple, non-0, etc

if not var :
    # execute if var is "", {}, [], (), 0, None, etc.

if var is True :
    # only execute if var is boolean True, not 1

if var is False :
    # only execute if var is boolean False, not 0

if var is None :
    # same as var == None

Do not check if you can, just do it and handle the error

Pythonistas обычно говорят, что «проще просить прощения, чем разрешения».

Don 't:

if os.path.isfile(file_path) :
    file = open(file_path)
else :
    # do something

Делать :

try :
    file =  open(file_path)
except OSError as e:
    # do something

Или еще лучше с Python 2.6+ / 3:

with open(file_path) as file :

Это намного лучше, потому что это намного более обобщенно. Вы можете применить & quot; попробовать / кроме & quot; почти что угодно. Вам не нужно заботиться о том, что делать, чтобы предотвратить это, просто об ошибке, которой вы рискуете.

Do not check against type

Python динамически типизирован, поэтому проверка типа приводит к потере гибкости. Вместо этого используйте утку, проверяя поведение. Например, вы ожидаете строку в функции, затем используете str () для преобразования любого объекта в строку. Вы ожидаете список, используйте list () для преобразования любого итерируемого в списке.

Don 't:

def foo(name) :
    if isinstance(name, str) :
        print name.lower()

def bar(listing) :
    if isinstance(listing, list) :
        listing.extend((1, 2, 3))
        return ", ".join(listing)

Делать :

def foo(name) :
    print str(name).lower()

def bar(listing) :
    l = list(listing)
    l.extend((1, 2, 3))
    return ", ".join(l)

Используя последний способ, foo примет любой объект. Бар будет принимать строки, кортежи, наборы, списки и многое другое. Дешевый СУХОЙ :-)

Don't mix spaces and tabs

Просто не надо. Вы бы плакали.

Use object as first parent

Это сложно, но это будет кусать вас по мере роста вашей программы. В Python 2.x есть старые и новые классы. Старые, ну, старые. Им не хватает некоторых функций, и они могут вести себя неловко с наследованием. Для использования любой ваш класс должен иметь «новый стиль». Для этого сделайте так, чтобы он наследовал от & quot; объекта & quot; :

Don 't:

class Father :
    pass

class Child(Father) :
    pass

Делать :

class Father(object) :
    pass


class Child(Father) :
    pass

В Python 3.x все классы имеют новый стиль, поэтому вы можете объявитьclass Father: Это хорошо.

Don't initialize class attributes outside the __init__ method

Люди, пришедшие с других языков, находят это заманчивым, потому что вы выполняете свою работу на Java или PHP. Вы пишете имя класса, затем перечисляете свои атрибуты и даете им значение по умолчанию. Кажется, это работает в Python, однако, это не работает так, как вы думаете.

При этом будут настроены атрибуты класса (статические атрибуты), а затем, когда вы попытаетесь получить атрибут объекта, он даст вам его значение, если только он не пуст. В этом случае он вернет атрибуты класса.

Это подразумевает две большие опасности:

If the class attribute is changed, then the initial value is changed. If you set a mutable object as a default value, you'll get the same object shared across instances.

Не делайте (если вы не хотите статического):

class Car(object):
    color = "red"
    wheels = [wheel(), Wheel(), Wheel(), Wheel()]

Делать :

class Car(object):
    def __init__(self):
        self.color = "red"
        self.wheels = [wheel(), Wheel(), Wheel(), Wheel()]
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы