如何在 class 中注入代码并在运行时为 class 字段赋值?
How to inject code in class and assign values to class fields at runtime?
我有一个 BatchJob 规范文件 (batch.spec),如下所示:
python = <<EOF
def foo():
return f"foo: I am {self.name}"
def bar():
return f"bar: I am {self.name}"
EOF
<batch>
name p&l_calculator
exec echo %foo()%
</batch>
我正在使用 https://github.com/etingof/apacheconfig
将此文件转换为 python 字典
from apacheconfig import *
with make_loader() as loader:
config = loader.load('batch.spec')
# Print content of python dict
for key, value in config.items():
print(key, value)
# output from print statement above
# python
# def foo():
# return f"foo: I am {self.name}"
#
# def bar():
# return f"bar: I am {self.name}"
# batch {'name': 'p&l_calculator', 'exec': 'echo %foo()%'}
现在我正在将这个 python 字典转换为 BatchJobSpec 对象,如下所示:
class BatchJobSpec:
def __init__(self, pythoncode , batch):
self.pythoncode = pythoncode
self.name = batch.get("name")
self.exec = batch.get("exec")
batchjobspec = BatchJobSpec(config.get("python"), config.get("batch"))
如果我打印 batchjobspec 字段,那么我会得到类似下面的内容
print(batchjobspec.pythoncode)
print(batchjobspec.name)
print(batchjobspec.exec)
# Output from above print statements
# def foo():
# return f"foo: I am {self.name}"
#
# def bar():
# return f"bar: I am {self.name}"
# p&l_calculator
# echo %foo()%
问题: 我想在尝试访问它时插入 "batchjobspec.exec" 的值,即它不应该是 "echo %foo()%" 但它应该是 "echo foo: I am p&l_calculator"。
即以某种方式在 getter 字段中,我想检查是否有 "% %" 语法。如果是,并且如果“% %”中的内容包含可调用对象,那么我想调用该可调用对象并将从可调用对象返回的值附加到相应字段的值。我想我也必须让这些可调用对象在 BatchJobSpec dict 中可用。
Comment: I have foo as well as bar. exec(str) will execute both
在您的 self.pythoncode
中,您有像 def foo():
这样的函数定义。因此 exec
不会 执行 而是 定义 本地命名空间中的这些函数。要 执行 这些函数作为 class methode
,您必须创建一个 attribute
,在 class
本身中引用这些局部函数。
在这个例子中,函数名是预先知道的
class BatchJobSpec:
def __init__(self, pythoncode , batch):
self.pythoncode = pythoncode
self.name = batch['name']
self._exec = ['for', 'bar']
self.exec()
要使 self
在本地名称空间中可见,请定义 locals_
字典。
exec
字符串 self.pythoncode
导致将对函数的引用插入 locals_
。要将这些本地引用用作 class methode
并使其持久化,请使用 self.__setattr__(...
.
def exec(self):
locals_ = {'self': self}
exec(self.pythoncode, locals_)
for attrib in self._exec:
print('__setattr__({})'.format(attrib))
self.__setattr__(attrib, locals_[attrib])
用法:不同的python format
语法,因为我使用python 3.5
python = """
def foo():
return 'foo: I am {name}'.format(name=self.name)
def bar():
return 'bar: I am {name}'.format(name=self.name)
"""
if __name__ == "__main__":
batchjobspec = BatchJobSpec(config.get("python"), config.get("batch"))
print('echo {}'.format(batchjobspec.foo()))
print('echo {}'.format(batchjobspec.bar()))
Output:
__setattr__(foo)
__setattr__(bar)
echo foo: I am p&l_calculator
echo bar: I am p&l_calculator
Question I want the value of "batchjobspec.exec" to be interpolated when I try to access it
将您的 class BatchJobSpec
更改为:
class BatchJobSpec:
def __init__(self, pythoncode , batch):
self.pythoncode = pythoncode
self.name = batch.get("name")
self._exec = batch.get("exec")
@property
def exec(self):
to_exec = 'foo'
self.__setattr__(to_exec, lambda : exec('print("Hello world")'))
self.foo()
return None
我有一个 BatchJob 规范文件 (batch.spec),如下所示:
python = <<EOF
def foo():
return f"foo: I am {self.name}"
def bar():
return f"bar: I am {self.name}"
EOF
<batch>
name p&l_calculator
exec echo %foo()%
</batch>
我正在使用 https://github.com/etingof/apacheconfig
将此文件转换为 python 字典from apacheconfig import *
with make_loader() as loader:
config = loader.load('batch.spec')
# Print content of python dict
for key, value in config.items():
print(key, value)
# output from print statement above
# python
# def foo():
# return f"foo: I am {self.name}"
#
# def bar():
# return f"bar: I am {self.name}"
# batch {'name': 'p&l_calculator', 'exec': 'echo %foo()%'}
现在我正在将这个 python 字典转换为 BatchJobSpec 对象,如下所示:
class BatchJobSpec:
def __init__(self, pythoncode , batch):
self.pythoncode = pythoncode
self.name = batch.get("name")
self.exec = batch.get("exec")
batchjobspec = BatchJobSpec(config.get("python"), config.get("batch"))
如果我打印 batchjobspec 字段,那么我会得到类似下面的内容
print(batchjobspec.pythoncode)
print(batchjobspec.name)
print(batchjobspec.exec)
# Output from above print statements
# def foo():
# return f"foo: I am {self.name}"
#
# def bar():
# return f"bar: I am {self.name}"
# p&l_calculator
# echo %foo()%
问题: 我想在尝试访问它时插入 "batchjobspec.exec" 的值,即它不应该是 "echo %foo()%" 但它应该是 "echo foo: I am p&l_calculator"。
即以某种方式在 getter 字段中,我想检查是否有 "% %" 语法。如果是,并且如果“% %”中的内容包含可调用对象,那么我想调用该可调用对象并将从可调用对象返回的值附加到相应字段的值。我想我也必须让这些可调用对象在 BatchJobSpec dict 中可用。
Comment: I have foo as well as bar. exec(str) will execute both
在您的 self.pythoncode
中,您有像 def foo():
这样的函数定义。因此 exec
不会 执行 而是 定义 本地命名空间中的这些函数。要 执行 这些函数作为 class methode
,您必须创建一个 attribute
,在 class
本身中引用这些局部函数。
在这个例子中,函数名是预先知道的
class BatchJobSpec: def __init__(self, pythoncode , batch): self.pythoncode = pythoncode self.name = batch['name'] self._exec = ['for', 'bar'] self.exec()
要使
self
在本地名称空间中可见,请定义locals_
字典。
exec
字符串self.pythoncode
导致将对函数的引用插入locals_
。要将这些本地引用用作class methode
并使其持久化,请使用self.__setattr__(...
.def exec(self): locals_ = {'self': self} exec(self.pythoncode, locals_) for attrib in self._exec: print('__setattr__({})'.format(attrib)) self.__setattr__(attrib, locals_[attrib])
用法:不同的python
format
语法,因为我使用python 3.5python = """ def foo(): return 'foo: I am {name}'.format(name=self.name) def bar(): return 'bar: I am {name}'.format(name=self.name) """ if __name__ == "__main__": batchjobspec = BatchJobSpec(config.get("python"), config.get("batch")) print('echo {}'.format(batchjobspec.foo())) print('echo {}'.format(batchjobspec.bar()))
Output:
__setattr__(foo) __setattr__(bar) echo foo: I am p&l_calculator echo bar: I am p&l_calculator
Question I want the value of "batchjobspec.exec" to be interpolated when I try to access it
将您的 class BatchJobSpec
更改为:
class BatchJobSpec:
def __init__(self, pythoncode , batch):
self.pythoncode = pythoncode
self.name = batch.get("name")
self._exec = batch.get("exec")
@property
def exec(self):
to_exec = 'foo'
self.__setattr__(to_exec, lambda : exec('print("Hello world")'))
self.foo()
return None