如何捕获特定的名称分配?
How to catch a particular name assignment?
(基于):
当设置对象的 attribute
时,可以覆盖对象的 __setattr__
魔术方法以获得额外的指令。如:
class MyClass(object):
def __init__(self, attribute=None):
object.__init__(self)
self.attribute = attribute
def __setattr__(self, name, value):
self.__dict__[name] = value
if name == 'attribute':
print("attribute's value is modified to {}.".format(
self.attribute))
if __name__ == '__main__':
my_obj = MyClass(True)
while True:
my_obj.attribute = input()
- 如何捕捉当前脚本中的特定名称分配
不使用 类(特别是用更多的方法调用方法
说明)?
def b_is_modified():
print("b is modified!")
if __name__ == '__main__':
a = 3
b = 4
b = 5
b
赋值时如何调用b_is_modified
?
基于:
它不能被抓到(至少在python级别)。
简单名称分配 (b = 4
) 与对象属性分配 (object.b = 5
) 相反,是语言本身的 基础 操作。它不是根据可以覆盖的较低级别操作来实现的。赋值只是是.
我认为 Nae 的另一个回答总结了这一点;我不知道 Python 语言中有任何检测分配的内置机制,所以如果你想要一个类似中断的事件系统在分配时触发,我不知道它是否可行。
但是,您似乎下定决心要找到一种“检测”分配的方法,所以我想描述一种可能会让您更接近于没有的方法。
内置函数globals()
和locals()
分别在全局和局部范围内创建变量字典。 (除了 vars()
之外,还进一步解释了 here)。
值得注意的一点是,如果从函数内部调用,locals()
的行为会有所不同:
If locals()
is called inside a function it constructs a dictionary of the function namespace as of that moment and returns it -- any further name assignments are not reflected in the returned dictionary, and any assignments to the dictionary are not reflected in the actual local namespace
If locals()
is called outside a function it returns the actual dictionary that is the current namespace. Further changes to the namespace are reflected in the dictionary, and changes to the dictionary are reflected in the namespace:
这是检测变量变化的“hacky”方法:
def b_is_modified():
print("b is modified!")
if __name__ == '__main__':
old = locals().get('b')
a = 3
b = 4
b = 5
new = locals().get('b')
if id(new) != id(old) and new is not None:
b_is_modified()
这只不过是一种(混淆?)检查 b
的值是否已从执行中的一个点更改为另一个点的方法,并且没有回调事件或触发操作检测到它。但是,如果您想扩展这种方法,请继续阅读。
答案的其余部分解释了如何通过将 b
重写为类似以下内容来检查 b
中的更改:
if __name__ == '__main__':
monitor = ScopeVariableMonitor(locals())
a = 3
b = 4
monitor.compare_and_update() # Detects creation of a and b
b = 5
monitor.compare_and_update() # Detects changes to b
以下将“检测”变量的任何更改,我还提供了一个在函数内部使用它的示例,以重申字典 return 来自 locals()
不更新。
ScopeVariableMonitor
-class只是一个例子,把代码合并到一个地方。本质上,它是比较 update()
s.
之间变量的存在和值的变化
class ScopeVariableMonitor:
def __init__(self, scope_vars):
self.scope_vars = scope_vars # Save a locals()-dictionary instance
self.old = self.scope_vars.copy() # Make a shallow copy for later comparison
def update(self, scope_vars=None):
scope_vars = scope_vars or self.scope_vars
self.old = scope_vars.copy() # Make new shallow copy for next time
def has_changed(self, var_name):
old, new = self.old.get(var_name), self.scope_vars.get(var_name)
print('{} has changed: {}'.format(var_name, id(old) != id(new)))
def compare_and_update(self, var_list=None, scope_vars=None):
scope_vars = scope_vars or self.scope_vars
# Find new keys in the locals()-dictionary
new_variables = set(scope_vars.keys()).difference(set(self.old.keys()))
if var_list:
new_variables = [v for v in new_variables if v in var_list]
if new_variables:
print('\nNew variables:')
for new_variable in new_variables:
print(' {} = {}'.format(new_variable, scope_vars[new_variable]))
# Find changes of values in the locals()-dictionary (does not handle deleted vars)
changed_variables = [var_name for (var_name, value) in self.old.items() if
id(value) != id(scope_vars[var_name])]
if var_list:
changed_variables = [v for v in changed_variables if v in var_list]
if changed_variables:
print('\nChanged variables:')
for var in changed_variables:
print(' Before: {} = {}'.format(var, self.old[var]))
print(' Current: {} = {}\n'.format(var, scope_vars[var], self.old[var]))
self.update()
“有趣”的部分是 compare_and_update()
方法,如果提供了变量名称列表,例如['a', 'b']
,它只会查找对变量的更改。 scope_vars
-参数在函数范围内时是必需的,但在全局范围内不是;出于上述原因。
def some_function_scope():
print('\n --- Now inside function scope --- \n')
monitor = ScopeVariableMonitor(locals())
a = 'foo'
b = 42
monitor.compare_and_update(['a', 'b'], scope_vars=locals())
b = 'bar'
monitor.compare_and_update(scope_vars=locals())
if __name__ == '__main__':
monitor = ScopeVariableMonitor(locals())
var_list = ['a', 'b']
a = 5
b = 10
c = 15
monitor.compare_and_update(var_list=var_list)
print('\n *** *** *** \n') # Separator for print output
a = 10
b = 42
c = 100
d = 1000
monitor.has_changed('b')
monitor.compare_and_update()
some_function_scope()
输出:
New variables:
a = 5
b = 10
*** *** ***
b has changed: True
New variables:
d = 1000
Changed variables:
Before: b = 10
Current: b = 42
Before: a = 5
Current: a = 10
Before: c = 15
Current: c = 100
--- Now inside function scope ---
New variables:
a = foo
b = 42
Changed variables:
Before: b = 42
Current: b = bar
结论
我的回答只是一种更通用的做法:
b = 1
old_b = b
# ...
if b != old_b:
print('b has been assigned to')
来自 locals()
的字典将包含 所有 变量,包括函数和 classes;不仅仅是像 a
、b
和 c
.
这样的“简单”变量
在上面的实现中,“旧”值和“新”值之间的检查是通过将之前的 shallow 副本的 id()
与 id()
的当前值。这种方法允许比较任何值,因为 id()
将 return 虚拟内存地址,但这远不是一个好的、通用的比较方案。
我很好奇你想要实现什么以及为什么要检测作业:如果你分享你的目标,那么也许我可以想出另一种方式来以另一种方式实现它。
(基于
当设置对象的 attribute
时,可以覆盖对象的 __setattr__
魔术方法以获得额外的指令。如:
class MyClass(object):
def __init__(self, attribute=None):
object.__init__(self)
self.attribute = attribute
def __setattr__(self, name, value):
self.__dict__[name] = value
if name == 'attribute':
print("attribute's value is modified to {}.".format(
self.attribute))
if __name__ == '__main__':
my_obj = MyClass(True)
while True:
my_obj.attribute = input()
- 如何捕捉当前脚本中的特定名称分配 不使用 类(特别是用更多的方法调用方法 说明)?
def b_is_modified():
print("b is modified!")
if __name__ == '__main__':
a = 3
b = 4
b = 5
b
赋值时如何调用b_is_modified
?
基于
它不能被抓到(至少在python级别)。
简单名称分配 (b = 4
) 与对象属性分配 (object.b = 5
) 相反,是语言本身的 基础 操作。它不是根据可以覆盖的较低级别操作来实现的。赋值只是是.
我认为 Nae 的另一个回答总结了这一点;我不知道 Python 语言中有任何检测分配的内置机制,所以如果你想要一个类似中断的事件系统在分配时触发,我不知道它是否可行。
但是,您似乎下定决心要找到一种“检测”分配的方法,所以我想描述一种可能会让您更接近于没有的方法。
内置函数globals()
和locals()
分别在全局和局部范围内创建变量字典。 (除了 vars()
之外,还进一步解释了 here)。
值得注意的一点是,如果从函数内部调用,locals()
的行为会有所不同:
If
locals()
is called inside a function it constructs a dictionary of the function namespace as of that moment and returns it -- any further name assignments are not reflected in the returned dictionary, and any assignments to the dictionary are not reflected in the actual local namespaceIf
locals()
is called outside a function it returns the actual dictionary that is the current namespace. Further changes to the namespace are reflected in the dictionary, and changes to the dictionary are reflected in the namespace:
这是检测变量变化的“hacky”方法:
def b_is_modified():
print("b is modified!")
if __name__ == '__main__':
old = locals().get('b')
a = 3
b = 4
b = 5
new = locals().get('b')
if id(new) != id(old) and new is not None:
b_is_modified()
这只不过是一种(混淆?)检查 b
的值是否已从执行中的一个点更改为另一个点的方法,并且没有回调事件或触发操作检测到它。但是,如果您想扩展这种方法,请继续阅读。
答案的其余部分解释了如何通过将 b
重写为类似以下内容来检查 b
中的更改:
if __name__ == '__main__':
monitor = ScopeVariableMonitor(locals())
a = 3
b = 4
monitor.compare_and_update() # Detects creation of a and b
b = 5
monitor.compare_and_update() # Detects changes to b
以下将“检测”变量的任何更改,我还提供了一个在函数内部使用它的示例,以重申字典 return 来自 locals()
不更新。
ScopeVariableMonitor
-class只是一个例子,把代码合并到一个地方。本质上,它是比较 update()
s.
class ScopeVariableMonitor:
def __init__(self, scope_vars):
self.scope_vars = scope_vars # Save a locals()-dictionary instance
self.old = self.scope_vars.copy() # Make a shallow copy for later comparison
def update(self, scope_vars=None):
scope_vars = scope_vars or self.scope_vars
self.old = scope_vars.copy() # Make new shallow copy for next time
def has_changed(self, var_name):
old, new = self.old.get(var_name), self.scope_vars.get(var_name)
print('{} has changed: {}'.format(var_name, id(old) != id(new)))
def compare_and_update(self, var_list=None, scope_vars=None):
scope_vars = scope_vars or self.scope_vars
# Find new keys in the locals()-dictionary
new_variables = set(scope_vars.keys()).difference(set(self.old.keys()))
if var_list:
new_variables = [v for v in new_variables if v in var_list]
if new_variables:
print('\nNew variables:')
for new_variable in new_variables:
print(' {} = {}'.format(new_variable, scope_vars[new_variable]))
# Find changes of values in the locals()-dictionary (does not handle deleted vars)
changed_variables = [var_name for (var_name, value) in self.old.items() if
id(value) != id(scope_vars[var_name])]
if var_list:
changed_variables = [v for v in changed_variables if v in var_list]
if changed_variables:
print('\nChanged variables:')
for var in changed_variables:
print(' Before: {} = {}'.format(var, self.old[var]))
print(' Current: {} = {}\n'.format(var, scope_vars[var], self.old[var]))
self.update()
“有趣”的部分是 compare_and_update()
方法,如果提供了变量名称列表,例如['a', 'b']
,它只会查找对变量的更改。 scope_vars
-参数在函数范围内时是必需的,但在全局范围内不是;出于上述原因。
def some_function_scope():
print('\n --- Now inside function scope --- \n')
monitor = ScopeVariableMonitor(locals())
a = 'foo'
b = 42
monitor.compare_and_update(['a', 'b'], scope_vars=locals())
b = 'bar'
monitor.compare_and_update(scope_vars=locals())
if __name__ == '__main__':
monitor = ScopeVariableMonitor(locals())
var_list = ['a', 'b']
a = 5
b = 10
c = 15
monitor.compare_and_update(var_list=var_list)
print('\n *** *** *** \n') # Separator for print output
a = 10
b = 42
c = 100
d = 1000
monitor.has_changed('b')
monitor.compare_and_update()
some_function_scope()
输出:
New variables:
a = 5
b = 10
*** *** ***
b has changed: True
New variables:
d = 1000
Changed variables:
Before: b = 10
Current: b = 42
Before: a = 5
Current: a = 10
Before: c = 15
Current: c = 100
--- Now inside function scope ---
New variables:
a = foo
b = 42
Changed variables:
Before: b = 42
Current: b = bar
结论
我的回答只是一种更通用的做法:
b = 1
old_b = b
# ...
if b != old_b:
print('b has been assigned to')
来自 locals()
的字典将包含 所有 变量,包括函数和 classes;不仅仅是像 a
、b
和 c
.
在上面的实现中,“旧”值和“新”值之间的检查是通过将之前的 shallow 副本的 id()
与 id()
的当前值。这种方法允许比较任何值,因为 id()
将 return 虚拟内存地址,但这远不是一个好的、通用的比较方案。
我很好奇你想要实现什么以及为什么要检测作业:如果你分享你的目标,那么也许我可以想出另一种方式来以另一种方式实现它。