有一个简单的类,我想用不同的方法在字典中静态存储一些函数:
import os, sys
class ClassTest():
testFunc = {}
def registerClassFunc(self,funcName):
ClassTest.testFunc[funcName] = eval(funcName)
@classmethod
def registerClassFuncOnClass(cls,funcName):
cls.testFunc[funcName] = eval(funcName)
@staticmethod
def registerClassFuncFromStatic(funcName):
ClassTest.testFunc[funcName] = eval(funcName)
一些示例方法:
def user_func():
print("I run therefore I am self-consistent")
def user_func2():
print("I am read therefore I am interpreted")
def user_func3():
print("I am registered through a meta function therefore I am not recognized")
def user_func4():
print("I am registered through an instance function therefore I am not recognized")
def user_func5():
print("I am registered through a static function therefore I am not recognized")
还有一个小测试:
if __name__ == "__main__":
a = ClassTest()
a.testFunc["user_func"] = user_func
a.testFunc["user_func"]()
a.testFunc["user_func2"] = eval("user_func2")
a.testFunc["user_func2"]()
ClassTest.testFunc["user_func"] = user_func
ClassTest.testFunc["user_func"]()
ClassTest.testFunc["user_func2"] = eval("user_func2")
ClassTest.testFunc["user_func2"]()
a.registerClassFunc("user_func5") # does not work on import
a.testFunc["user_func5"]()
ClassTest.registerClassFuncFromStatic("user_func3") # does not work on import
ClassTest.testFunc["user_func3"]()
ClassTest.registerClassFuncOnClass("user_func4") # does not work on import
ClassTest.testFunc["user_func4"]()
所有这些工作都提供了所有这些元素都在同一个文件中。一旦功能被分成两个文件和一个主文件:
from ClassTest import ClassTest
from UserFunctions import user_func,user_func2, user_func3, user_func4, user_func5
if __name__ == "__main__":
a = ClassTest()
a.testFunc["user_func"] = user_func
...
只有前两个保持工作(直接设置函数),其他的-使用一个函数做同样的事情-对所有的eval
调用给出一个NameError
。例如:NameError: name 'user_func5' is not defined
。你知道吗
使用这些方法与直接设置这些函数相比,在这里丢失作用域的逻辑是什么?我是否可以使用从其他包导入的方法使它工作,这样我就可以用方法而不是直接在类中放置任何函数?你知道吗
There's a live version of fix #1 from this answer online that you can try out for yourself
问题
你是对的,这不起作用的原因是由于范围问题。您可以通过仔细检查docs for ^{} 来了解发生了什么:
因此,我们可以合理地假设您遇到的问题是} 的支持:
globals
和locals
的内容,在ClassTest
的定义(可能是单独的模块)中,eval
被调用。由于调用eval
的上下文通常不是定义和/或导入user_func, user_func2....
的上下文,因此就eval
而言,这些函数是未定义的。这一思路得到了docs for ^{修复
对于如何修复此代码,您有几个不同的选项。所有这些都将涉及从调用的上下文传递
locals
,例如,ClassTest.registerClassFunc
到定义该方法的上下文。此外,您应该利用这个机会从代码中排除eval
的使用(它的使用被认为是不好的做法,它是massive security hole,yadda yadda yadda)。假定locals
是定义user_func
的作用域的dict,您可以始终执行以下操作:而不是:
固定#1
Link to live version of this fix
这将是最容易实现的修复,因为它只需要对
ClassTest
的方法的定义进行一些调整(并且不需要对任何方法签名进行更改)。它依赖于这样一个事实,即可以在函数中使用inspect
包来直接获取调用上下文的locals
:如果您使用上述给定的
ClassTest
定义,那么您编写的导入测试现在将按预期运行。你知道吗优点
完全提供了最初预期的功能。
不涉及对函数签名的更改。
缺点
调用
inspect.currentframe()
会导致性能下降,因此如果计划每秒调用ClassTest
的方法一百万次,则可能无法使用此修复程序。inspect.currentframe()
只保证在CPython上工作。Mileage may vary when running this code with other implementations of Python。固定#2
Fix#2与Fix#1基本相同,只是在这个版本中,您在调用点显式地将
locals
传递给ClassTest
的方法。例如,在这个fix下ClassTest.registerClassFunc
的定义是:你可以在代码中这样调用它:
优点
inspect.currentframe()
,因此可能比fix#1更具性能/可移植性。你知道吗缺点
您必须修改方法签名,因此还必须更改使用这些方法的任何现有代码。
从现在开始,您必须将
locals()
样板添加到每个ClassTest
方法的每次调用中。相关问题 更多 >
编程相关推荐