(参见下面编辑中的最后一个问题。原始标题是为什么 static var in static var is ok but static method not ok in Python?)
原帖:我有一个与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 将其视为 namespace 的建议确实有帮助。然而现在我意识到我的测试用例太简单了。失败的是由于某种原因初始化列表/字典:
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
s 不可调用。他们是descriptors通过点( .
)访问时返回可调用对象。在类主体执行之后之前,类不存在。同时,它是一个命名空间,类似于模块,但作用域规则略有不同。主体执行后, namespace 被转储到类对象的 __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
,或者它需要另一个参数。但是我们还没有提供它的类或实例。)
What failed was initializing a list/dictionary for some reason:
这是由于我之前提到的“范围规则略有不同”。
推导式的编译方式类似于生成器——包含 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))
记住我说过主体命名空间被丢弃。通常,方法在类体执行后调用。因此,方法被编译为查找未在全局命名空间中本地定义的名称,而不是可能不再存在的临时类体命名空间。如果需要,可以将此临时命名空间保存在某处,例如,
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__
中,因此它们可用作属性):
class A:
@staticmethod
def f(a): return a*a
lst = [2, 3, 4]
A.lst2 = [A.f(v) for v in A.lst]
关于python - 静态变量中使用的理解看不到局部函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60918643/