我有一个与Refering to static methods from static variables密切相关的Python问题,但不完全相同。因此,代码在其中引用静态方法静态变量,例如
class A:
@staticmethod
def f(a):
return a*a
v = f(2) # A.f(2) does not work either
是无效的(据我所知,在没有@staticmethod的情况下也是如此)。精细。但是,可以毫无问题地引用另一个静态变量:
class A:
i = 2
v = i * i # not using A.i here
print(A.v) # gives 4
这里对静态变量和静态方法进行不同处理的背后原理是什么?如果有问题,我正在尝试使用Python 3.6。
编辑:
gilch提出的将其视为名称空间的建议确实有帮助。现在,我意识到我的测试用例太简单了。失败是由于某种原因初始化列表/字典:
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外部定义,则最后两行都可以使用。因此,这可能是范围问题...
因为staticmethod
不可调用。当通过点(descriptors)访问时,它们是.
返回可调用对象。类不存在直到类主体执行after为止。同时,它是一个名称空间,类似于模块,但作用域规则略有不同。主体执行后,名称空间将转储到对象objet的__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命名空间中本地定义的名称,而不是可能不再存在的temporary类主体命名空间。如果需要,可以将这个临时名称空间保存在某个地方,例如,
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]