Подтвердить что ты не робот

Дополнительные параметры Python

Ребята, я недавно запустил python и запутался с необязательными параметрами, скажем, у меня есть такая программа:

class B:
   pass

class A:
    def __init__(self, builds = B()):
        self.builds = builds

Если я создаю A дважды

b = A()
c = A()

и распечатать свои сборки

print b.builds
print c.builds

Я обнаружил, что они используют точно такой же объект,

<__main__.B instance at 0x68ee0>
<__main__.B instance at 0x68ee0>

Но это не то, что я хочу, так как если b изменило какое-то внутреннее состояние сборки, то в объекте c также будет изменено.

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

4b9b3361

Ответ 1

Вам нужно понять, как работают значения по умолчанию, чтобы эффективно использовать их.

Функции - это объекты. Таким образом, у них есть атрибуты. Итак, если я создам эту функцию:

>>> def f(x, y=[]):
        y.append(x)
        return y

Я создал объект. Вот его атрибуты:

>>> dir(f)
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',   
'__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__',    
'__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', 
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 
'func_name']

Один из них - func_defaults. Это звучит многообещающе, что там?

>>> f.func_defaults
([],)

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

Это приводит к некоторому довольно противоречивому поведению, если вы думаете, что f добавляет элемент в список, возвращая список, содержащий только этот элемент, если список не указан:

>>> f(1)
[1]
>>> f(2)
[1, 2]

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

>>> x = f(3)
>>> y = f(4)
>>> x == y
True
>>> x
[1, 2, 3, 4]
>>> x.append(5)
>>> f(6)
[1, 2, 3, 4, 5, 6]

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

>>>def g(x, y=None):
       if y==None:
           y = []
       y.append(x)
       return y

Ответ 2

вам нужно сделать следующее:

class A:
    def __init__(self, builds=None):
        if builds is None:
            builds = B()
        self.builds = builds

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

Ответ 3

Да; параметры по умолчанию оцениваются только в момент определения функции.

Одним из возможных решений было бы иметь параметр class, а не экземпляр, a la

def foo(blah, klass = B):
    b = klass()
    # etc