Влияет ли dict.update на argspec функции? - PullRequest
4 голосов
/ 28 апреля 2010
import inspect
class Test:
  def test(self, p, d={}):
    d.update(p)
    return d
print inspect.getargspec(getattr(Test, 'test'))[3]
print Test().test({'1':True})
print inspect.getargspec(getattr(Test, 'test'))[3]

Я ожидаю, что argspec для Test.test не изменится, но из-за dict.update это изменится. Почему?

Ответы [ 2 ]

5 голосов
/ 28 апреля 2010

Потому что диктовки - это изменчивые объекты. Когда вы звоните d.update(p), вы фактически изменяете экземпляр по умолчанию. Это общий улов; в частности, никогда не следует использовать изменяемый объект в качестве значения по умолчанию в списке аргументов.

Лучший способ сделать это следующим образом:

class Test:
    def test(self, p, d = None):
        if d is None:
            d = {}
        d.update(p)
        return d
2 голосов
/ 28 апреля 2010

Аргумент по умолчанию в Python - это любой объект, который был установлен при определении функции, даже если вы установили изменяемый объект. Этот вопрос должен объяснить, что это значит и почему Python является таким вопросом Наименьшее удивление в Python: изменяемый аргумент по умолчанию .

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

>>> def f(xs=[]):
...   xs.append(5)
...   print xs
... 
>>> f()
[5]
>>> f()
[5, 5]

Самый простой способ обойти это - установить действительный аргумент по умолчанию None, а затем просто проверить None и указать значение по умолчанию в функции, например:

>>> def f(xs=None):
...   if xs is None:
...     xs = []
...   xs.append(5)
...   print xs
... 
>>> f()
[5]
>>> f()
[5]
...