静态变量中使用的理解看不到局部函数? [英] comprehension used in static variable cannot see local function?

查看:49
本文介绍了静态变量中使用的理解看不到局部函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(请参见下面的EDIT的最后一个问题.原始标题为为什么static var中的static var可以,但是Python中的static方法不能?)

(See final question at EDIT below. The original title was Why static var in static var is ok but static method not ok in Python?)

原始帖子:我有一个与

Original post: I have a Python question much related to Refering to static methods from static variables but not exactly the same. So code where one refers to a static method in a static variable, e.g.,

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

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

是无效的(据我所知,在没有@staticmethod的情况下也是如此).美好的.但是,可以毫无问题地引用另一个静态变量:

is invalid (and as far as I can tell same holds without @staticmethod as well). Fine. Yet, one can refer to another static variable without any problem:

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

print(A.v)    # gives 4

此处对静态变量和静态方法进行不同处理的背后原理是什么?如果有问题,我正在尝试使用Python 3.6.

What is the rationale behind the different treatment of a static variable and a static method here? I am trying from Python 3.6, if it matters.

gilch提出的将其视为命名空间的建议确实有帮助.现在,我意识到我的测试用例太简单了.失败的原因是出于某种原因初始化列表/字典:

The suggestion by gilch to think of it as a namespace indeed helps. Now I realize that my test case was too simplistic, however. What failed was initializing a list/dictionary for some reason:

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外部定义,则最后两行都可以使用.因此,这可能是范围问题...

Of course, the last two lines both work if f is defined outside A. So this may be a question of scope somehow...

推荐答案

因为 staticmethod 是不可调用的.它们是描述符,当通过点进行访问时,它们会返回可调用项(.).类不存在,直到类主体执行之后.同时,它是一个名称空间,类似于一个模块,但作用域规则稍有不同.主体执行后,名称空间将转储到类对象的 __ dict __ 中并被丢弃.所以这是有效的.

Because staticmethods are not callable. They're descriptors that return a callable when accessed through a dot (.). The class doesn't exist until after the class body executes. In the meantime, it's a namespace, similar to a module, but with slightly different scoping rules. After the body executes, the namespace is dumped into the class object's __dict__ and is discarded. So this works.

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 ,或者它需要另一个参数.但是我们还没有一个类或实例可以提供它.)

The ellipsis doesn't mean anything. @staticmethod's __get__() doesn't use its argument. (It can't be None, or it expects another argument. But we have neither a class nor an instance to give it yet.)

由于某种原因而失败的是初始化列表/字典:

What failed was initializing a list/dictionary for some reason:

这是由于我之前提到的略有不同的作用域规则".

This is due to the "slightly different scoping rules" that I mentioned earlier.

理解就像生成器一样进行编译-包含 yield 的函数.所以这会因为类似的原因而失败:

Comprehensions are compiled like generators -- functions that contain a yield. So this would fail for similar reasons:

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 命名空间中本地定义的名称,而不是可能不再存在的 temporary 类主体命名空间.如果需要,可以将这个临时命名空间保存在某处,例如,

Remember that I said the body namespace is discarded. Usually, methods are called after the class body has executed. So methods are compiled to look up names that aren't defined locally in the global namespace, instead of the temporary class body namespace that probably doesn't exist anymore. It is possible to save this temporary namespace somewhere if you need it, for example,

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]


您也可以采用老式的方式来避免编译生成器:


You could also do the comprehensions the old-fashioned way to avoid compiling generators:

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使用):


Or you could wait until after you have a class object to work with (the temporary namespace has been dumped into the object's __dict__ at this point, so they're available as attrs):

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

A.lst2 = [A.f(v) for v in A.lst]

这篇关于静态变量中使用的理解看不到局部函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆