Это фактически не имеет ничего общего с значениями по умолчанию, кроме того, что часто возникает неожиданное поведение при записи функций с изменяемыми значениями по умолчанию.
>>> def foo(a):
a.append(5)
print a
>>> a = [5]
>>> foo(a)
[5, 5]
>>> foo(a)
[5, 5, 5]
>>> foo(a)
[5, 5, 5, 5]
>>> foo(a)
[5, 5, 5, 5, 5]
В этом нет значений по умолчанию код, но вы получаете точно такую же проблему.
Проблема в том, что foo
является изменением изменчивой переменной, переданной от вызывающего, когда вызывающий объект не ожидает этого , Код, подобный этому, был бы хорош, если бы функция была вызвана как-то вроде append_5
; то вызывающий абонент будет вызывать функцию, чтобы изменить значение, которое они передают, и поведение будет ожидаться. Но такая функция вряд ли примет аргумент по умолчанию и, вероятно, не вернет список (поскольку у вызывающего уже есть ссылка на этот список, тот, который он только что передал).
Ваш оригинал foo
с аргументом по умолчанию не должен изменять a
, был ли он явно передан или получил значение по умолчанию. Ваш код должен оставлять изменчивые аргументы отдельно, если из контекста / имени / документации не ясно, что аргументы должны быть изменены. Использование измененных значений, передаваемых в качестве аргументов, таких как локальные временные файлы, является крайне плохой идеей, независимо от того, находимся ли мы на Python или нет, и есть ли задействованные аргументы по умолчанию.
Если вам нужно разрушить локальное временное в процессе вычисления чего-то, и вам нужно начать свою манипуляцию из значения аргумента, вам нужно сделать копию.
Короткий ответ: нет способа добавления настраиваемых атрибутов к связанным методам.
Дальнейший ответ следует.
В Python есть объекты функции и объектов . Когда вы определяете класс, оператор def
создает объект функции функции , который живет в пространстве имен класса:
>>> class c:
... def m(self):
... pass
...
>>> c.m
<function m at 0x025FAE88>
Объекты функции имеют специальный атрибут __dict__
, который может содержать пользовательские атрибуты:
>>> c.m.i = 0
>>> c.m.__dict__
{'i': 0}
Объектами метода являются разные звери. Это крошечные объекты, содержащие ссылку на соответствующий объект функции (__func__
) и один на свой объект-хост (__self__
):
>>> c().m
<bound method c.m of <__main__.c object at 0x025206D0>>
>>> c().m.__self__
<__main__.c object at 0x02625070>
>>> c().m.__func__
<function m at 0x025FAE88>
>>> c().m.__func__ is c.m
True
Объекты метода предоставляют специальный __getattr__
, который пересылает атрибут доступа к объекту функции:
>>> c().m.i
0
Это также относится к свойству __dict__
:
>>> c().m.__dict__['a'] = 42
>>> c.m.a
42
>>> c().m.__dict__ is c.m.__dict__
True
Атрибуты настройки следуют правилам по умолчанию, хотя, и поскольку они не имеют собственных __dict__
, невозможно установить произвольные атрибуты.
Это похоже на пользовательские классы, определяющие слоты __slots__
и no __dict__
при попытке установить несуществующий слот поднимает значение AttributeError
(дополнительную информацию см. в документах __slots__
):
>>> class c:
... __slots__ = ('a', 'b')
...
>>> x = c()
>>> x.a = 1
>>> x.b = 2
>>> x.c = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'c' object has no attribute 'c'
Q: «Есть ли способ установить атрибут для метода таким образом, чтобы он существовал только в одном экземпляре, а не для каждого экземпляра класса?»
A: Да:
class c:
def m(self):
print(type(c.m))
setattr(c.m, 'i', 0)
print(type(self))
setattr(self, 'i', 0)
Статическая переменная в функциях в столбце, на который вы ссылаетесь, не полезна для методов. Он устанавливает атрибут функции, чтобы этот атрибут был доступен при следующем вызове функции, поэтому вы можете сделать счетчик или еще что-то.
Но методы имеют связанный с ними экземпляр объекта (self). Следовательно, вам не нужно устанавливать атрибуты метода, так как вы просто можете установить его на экземпляр вместо этого. Это действительно то, для чего предназначен экземпляр.
Сообщение, на которое вы ссылаетесь, показывает, как создать функцию со статической переменной. Я бы сказал, что в Python это будет ошибочным. Вместо этого посмотрите на этот ответ: Что такое эквивалент Python для статических переменных внутри функции?
Это способ сделать это на Python таким образом, который ясен и легко понятен , Вы используете класс и делаете его вызываемым. Установка атрибутов на функциях возможна, и есть, вероятно, случаи, когда это хорошая идея, но в целом это просто путает людей.