写了一个辅助函数来包装简单的对象构造函数并使它们可以作为标签访问,但我要么有一个错误,要么编写构造函数是因为闭包导致了冲突
import yaml
from yaml.constructor import ConstructorError
def add_init_constuctors(*klasses, loader=yaml.SafeLoader):
for klass in klasses:
name = klass.__name__
def constructor(loader, node):
try:
fields = loader.construct_mapping(node)
except ConstructorError:
fields = {}
return klass(**fields)
yaml.add_constructor(
f"!{name}",
constructor,
Loader=loader,
)
print(f"added !{name}")
print(yaml.load(f"!{name}", Loader=loader))
print(
[
(klass.__name__, yaml.load(f"!{klass.__name__}", Loader=loader))
for klass in klasses
]
)
class A(dict):
def __repr__(self):
return "A()"
class B(dict):
def __repr__(self):
return "B()"
if __name__ == "__main__":
add_init_constuctors(A, B)
运行这段代码输出
added !A
A()
added !B
B()
[('A', B()), ('B', B())]
如您所见,当添加 A
时它会正确加载,但是一旦添加了 B
标签,就会尝试访问 A
返回 B
构造函数
我希望,即使它们包含在范围内,闭包中定义的函数也会保留在构造函数标签中并且是正确的/可访问的。
最佳答案
发生这种情况是因为您的内部函数在 klass
变量上有一个闭包,即每当 constructor
执行时,它会查找 current 的值klass
,不是添加构造函数时的那个。
解决此问题的最简单方法是在函数中生成构造函数(我删除了 sklearn
内容,因为它与问题无关):
import yaml
from yaml.constructor import ConstructorError
class A(dict):
def __repr__(self):
return "A()"
class B(dict):
def __repr__(self):
return "B()"
def gen_constructor(klass):
def ret(loader, node):
try:
fields = loader.construct_mapping(node)
except ConstructorError:
fields = {}
return klass(**fields)
return ret
def add_init_constuctors(*klasses, loader=yaml.SafeLoader):
for klass in klasses:
name = klass.__name__
yaml.add_constructor(
f"!{name}",
gen_constructor(klass),
Loader=loader,
)
print(f"added !{name}")
print(yaml.load(f"!{name}", Loader=loader))
print(
[
(klass.__name__, yaml.load(f"!{klass.__name__}", Loader=loader))
for klass in klasses
]
)
if __name__ == "__main__":
add_init_constuctors(A, B)
现在,res
捕获函数gen_constructor
的参数klass
,而不是klass
中的变量添加初始化构造函数
。因此,输出是:
added !A
A()
added !B
B()
[('A', A()), ('B', B())]
关于python - 我的标签是否过载,或者这是将构造函数添加到 yaml 配置或其他内容的范围问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74910887/