python 3.6 декоратор для статической переменной внутри метода класса [duplicate]

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

>>> 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 или нет, и есть ли задействованные аргументы по умолчанию.

Если вам нужно разрушить локальное временное в процессе вычисления чего-то, и вам нужно начать свою манипуляцию из значения аргумента, вам нужно сделать копию.

14
задан Lightness Races in Orbit 2 November 2011 в 18:24
поделиться

2 ответа

Короткий ответ: нет способа добавления настраиваемых атрибутов к связанным методам.

Дальнейший ответ следует.

В 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'
26
ответ дан Ferdinand Beyer 21 August 2018 в 08:55
поделиться
  • 1
    Я получаю следующее (немного другое) поведение: & gt; & gt; & gt; & gt; & gt; print m.m & lt; unbound method c.m & gt; & gt; & gt; & gt; & gt; print c.m .__ func__ & lt; функция m при 0x025FAE88 & gt; – jimifiki 30 July 2012 в 13:39
  • 2
    @jimifiki На самом деле вы не получаете различного поведения , а просто разных строковых представлений. Я предполагаю, что вы используете Python 2. Мои примеры кода были выполнены с Python 3. – Ferdinand Beyer 10 June 2015 в 08:35

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 таким образом, который ясен и легко понятен , Вы используете класс и делаете его вызываемым. Установка атрибутов на функциях возможна, и есть, вероятно, случаи, когда это хорошая идея, но в целом это просто путает людей.

1
ответ дан Community 21 August 2018 в 08:55
поделиться
Другие вопросы по тегам:

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