我正在开发一个程序,希望不时报告特定变量的状态,但是,我不一定知道我需要先验哪些变量。我研究过的其他程序(在C ++中)使用注册系统,在该系统中,相关变量一次在中央输出处理器中注册,然后在需要报告程序状态时,中央模块从输出变量中收集数据并将其写入输出文件。因此,程序流程将是这样的。
示例MyModule.py
from OutputProcessor import OutputProcessor
class MyClass():
def __init__(self):
op = OutputProcessor()
# variable I want to report
self.foo = None
# register with output processor
op.register_output_variable(self.foo, "Foo")
def calc_foo(self, bar, rand):
self.foo = bar ** rand
示例OutputProcessor.py
class OutputProcessor(object):
# list or dict object containing the name and link information to variables of interest
output_vars_data = []
def __init__(self):
pass
def register_output_variable(self, var, name):
OutputProcessor.output_vars_data.append({"link address": id(var), "name": name})
def report_output(self):
for data in OutputProcessor.output_vars_data:
self.write_to_output_file(data)
def write_to_output_file(self, data):
# write all of the data to the output file here
pass
示例Main.py
import random
from MyClass import MyClass
from OutputProcessor import OutputProcessor as OP
if __name__ == "__main__":
cls_instance = MyClass()
for i in range(100):
cls_instance.calc_foo(i, random.randint(1, 10))
OP().report_output()
我的第一个问题:这是否可能或可行?第二,如果是这样,我将如何去做?需要处理一些细微差别,例如如何处理报告相同变量的同一类的多个实例,但这似乎是一个小问题。有没有一种方法可以实现这一点,这样我就可以始终获取变量的当前值,而不仅仅是它的旧版本?
有什么想法或建议吗?
答案 0 :(得分:2)
除了代码中的范围界定问题外,确实要记住一个问题。 Python通过将名称绑定到引用来完成所有工作。您有兴趣获取分配给名称的值,而不是分配给注册时可能已绑定到的引用的值。这有点像C和C ++中的指向指针的指针。
要跟踪任意名称,还需要跟踪其包含的名称空间。这样,您可以使用通用函数getattr
来获取名称的最新值。命名空间可以是任何实例(模块和类也是实例)。
您的注册方法需要跟踪包含感兴趣的名称,名称本身以及您想要将其显示为的键的对象:
op.register_output_variable(self, 'foo', "Foo")
管理器类可以将值存储在字典中。我建议使用tuple
或collections.namedtuple
来代替“嵌套字典”来容纳“指针”:
def register_output_variable(self, inst, attr, key):
self.output_vars_data[key] = (inst, attr)
输出变量时,请执行类似的操作
for key, spec in self.output_vars_data.items():
print(key, '=', getattr(*spec))
这是为您提供一种通过名称而不是引用来引用对象属性的方法。如果您设置x.a = 1
,注册x.a
,然后再进行x.a += 1
,则希望获得2
作为您的值。要记住的重要一点是,x.a
将绑定到其他引用,因为整数在Python中是不可变的。通过将x
注册为名称空间,并将'a'
注册为名称,可以完全绕开它。
您可以通过添加一种方法来进一步概括,该方法用于注册可索引元素,例如列表的元素和字典的值。您将注册实例和索引/键,而不是实例和属性名称。看看operator.attrgetter
和operator.itemgetter
以获得更多想法。
这只是一个广泛的建议。它不能解决您使用的静态,类和实例名称空间不一致的情况。