понимание, используемое в переменной stati c, не может видеть локальную функцию? - PullRequest
2 голосов
/ 29 марта 2020

(См. Последний вопрос в разделе РЕДАКТИРОВАТЬ ниже. Оригинальное название было Почему stati c var in stati c var в порядке, но stati c метод не в порядке в Python? )

Исходное сообщение: У меня есть Python вопрос, очень связанный с Относительно методов stati c от stati c переменных , но не совсем то же самое. Так что код, где каждый ссылается на метод stati c в переменной stati c, например,

class A:
   @staticmethod
   def f(a):
      return a*a

   v = f(2)    # A.f(2) does not work either

, недопустим (и, насколько я могу судить, то же самое верно и без @staticmethod). Хорошо. Тем не менее, можно без каких-либо проблем ссылаться на другую переменную stati c:

class A:
   i = 2
   v = i * i    # not using A.i here

print(A.v)    # gives 4

В чем смысл различий в обработке переменной stati c и метода stati c здесь? Я пытаюсь из Python 3.6, если это имеет значение.

РЕДАКТИРОВАТЬ:

Предложение Гилха думать об этом как о пространстве имен действительно помогает. Однако теперь я понимаю, что мой тестовый пример был слишком упрощенным c. По какой-то причине не удалось инициализировать список / словарь:

class A:
   def f(a):  return a*a

   i = f(2)                           #works, indeed
   lst = [2, 3, 4]
   lst2 = [ v*v for v in lst]         #works
   lst3 = [ f(v) for v in lst]        #fails??
   dct =  { f(v) : v for v in lst }   #fails??

Конечно, обе последние строки работают, если f определено за пределами A. Так что это может как-то зависеть от области видимости ...

1 Ответ

3 голосов
/ 29 марта 2020

Потому что staticmethod s не могут быть вызваны. Это дескрипторы , которые возвращают вызываемый объект при доступе через точку (.). Класс не существует до тех пор, пока после не выполнится тело класса. В то же время это пространство имен, похожее на модуль, но с немного другими правилами области видимости. После выполнения тела пространство имен сбрасывается в __dict__ объекта класса и отбрасывается. Так что это работает.

class A:
    def f(a): return a*a
    v = f(2)
    f = staticmethod(f)

>>> A.v
4
>>> A.f(2)
4

Это также работает

class A:
    @staticmethod
    def f(a): return a*a
    v = f.__get__(...)(2)

Многоточие ничего не значит. @staticmethod __get__() не использует свой аргумент. (Это не может быть None, или он ожидает другого аргумента. Но у нас пока нет ни класса, ни экземпляра, чтобы дать его.)


Не удалось инициализировать список / словарь по какой-то причине:

Это связано с "немного другими правилами определения области действия", о которых я упоминал ранее.

Понимания компилируются как генераторы - функции, содержащие yield , Так что это не получится по тем же причинам:

class A:
    def f(a): return a*a
    xs=[2,3,4]
    def comp(it):
        for i in it:
            yield f(i)
    ys=list(comp(xs))

Помните, что я сказал, что пространство имен тела отбрасывается. Обычно методы вызываются после выполнения тела класса. Таким образом, методы компилируются для поиска имен, которые не определены локально в пространстве имен global , вместо пространства имен тела класса временного , которое, вероятно, больше не существует. Можно сохранить это временное пространство имен где-нибудь, если оно вам понадобится, например,

class A:
    def f(a): return a*a
    lst=[2,3,4]
    global ns
    ns = locals()
    lst2=[ns['f'](v) for v in lst]

>>> A.lst2
[4, 9, 16]

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

class A:
    def f(a): return a*a
    lst=[2,3,4]
    lst2=[]
    for v in lst: lst2.append(f(v))
    dct={}
    for v in lst: dct[f(v)] = v

Или вы можете подождать, пока у вас не появится объект класса для работы (временное пространство имен было сброшено в __dict__ объекта, поэтому они доступны как attrs):

class A:
    @staticmethod
    def f(a):  return a*a
    lst = [2, 3, 4]

A.lst2 = [A.f(v) for v in A.lst]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...