[英]using nonlocal or global inside a class body
在 python 中,在类中使用import
语句来定义刚刚从其他模块中窃取的类变量是有效的:
class CustomMath:
from math import pi
assert isinstance(CustomMath.pi, float) # passes
使用非常令人困惑的语句x=x
引用类的全局变量也是有效的
x = 1
class Test:
# this loads the global variable x and stores in in the class scope
x = x
assert Test.x == 1 # passes
但是,如果我使用函数生成类,是否有类似的方法将变量从函数参数复制到类主体?
我想要这种性质的东西:
def generate_meta_options(model, design):
class Meta:
# copy the nonlocal variable model to this scope
# but this isn't valid syntax
model = (nonlocal model)
design = translate_old_design_spec_to_new_format((nonlocal design))
return Meta
参数名称很重要,因为它是通过关键字而不是按顺序传递的generate_meta_options(design="A", model=Operation)
并且类中的名称必须相同,我找到了通过为所有变量设置别名的解决方法的输入,但这有点烦人
def generate_meta_options_works(model, design):
_model = model
_design = design
class Meta:
model = _model
design = translate_old_design_spec_to_new_format(_design)
return Meta
使用nonlocal
关键字有没有更好的方法来实现这一点? 似乎python确实允许在类中使用nonlocal
和global
变量,但变量未保留在类中,所以我无法想象它的用例。
gl = 'this is defined globally'
def nonlocal_in_class_test():
lo = 'this is defined locally'
class Test:
nonlocal lo
global gl
lo = 'foo'
gl = 'bar'
assert lo == 'foo' # passes
assert gl == 'bar' # passes
assert hasattr(Test, 'lo') or hasattr(Test, 'gl'), 'lo nor gl was put in the class scope' # fails
我确定我使用的库只需要一个带有属性查找的对象,这样我就可以远离类,但是我见过的每个示例都使用类(我怀疑是因为继承多个配置是自然的)所以我很犹豫要不要这样做路线。
从不同的模块复制变量比在上述范围内复制一个变量更容易,这似乎真的很奇怪,所以我想我会问,有没有办法将变量从nonlocal
范围复制到类中属性而不创建具有不同名称的单独变量?
作为切线,是否有在类主体中使用nonlocal
或global
关键字有用的情况? 我认为它没有用,但也没有理由做额外的工作来禁止它。
nonlocal
在任何情况下都不起作用,因为在nonlocal
适用的情况下,变量只有一个作用域(函数nonlocal
变量,与类定义作用域略有不同); 通过尝试使用nonlocal
,你会说model
从来都不是类定义范围的一部分,只是来自它之外的东西。
我个人更喜欢你的有点hacky的重新分配,所以_model
外的_model
和类内的model
不冲突,但如果你讨厌它,有一个选项可以直接访问正在进行的类的命名空间, vars()
(或locals()
; 在这种情况下,两者是等价的,但我不认为类范围是本地的,即使它们的行为很像)。
因为作用域并不是真正的函数作用域,你实际上可以通过vars
/ locals
的dict
改变它,让你想要的结果看起来像:
def generate_meta_options(model, design):
class Meta:
vars().update(
model=model,
design=translate_old_design_spec_to_new_format(design)
)
return Meta
使用dict.update
的关键字参数传递形式意味着代码甚至看起来更像是正常的赋值。 如果您在类定义中更早(查看外部作用域)或稍后(查看新定义的名称)使用这些名称,Python 不会抱怨:
def generate_meta_options(model, design):
print("Before class, in function:", model, design) # Sees arguments
class Meta:
print("Inside class, before redefinition:", model, design) # Sees arguments
vars().update(
model=model,
design=design+1
)
print("Inside class, after redefinition:", model, design) # Sees class attrs
print("After class, in function:", model, design) # Sees arguments
return Meta
MyMeta = generate_meta_options('a', 1)
print(MyMeta.model, MyMeta.design)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.