我在Python中有以下类,我试图通过一个包含可用函数指针的字典调用一组自己的方法:
class Test():
functions = {
'operation_a' : Test.function_a;
'operation_b' : Test.function_b;
}
def run_operations(operation, *args, **kwargs):
try:
functions[str(operation)](self, args, kwargs)
except KeyError:
// some log ...
def function_a(self, *args, **kwargs):
print A
def function_b(self, *args, **kwargs):
print B
第一种方法似乎不正确,因为Python解释器找不到类'Test'(NameError:'Test'未定义)。我找不到方法(导入包,包和模块,from package.module import *
......等等)因此,我有3个解决方案可以解决这个问题:
__init__()
),但是,我仍然不知道为什么最初的方法似乎不正确。因此,如何在实例化之前引用同一个类中的函数?
答案 0 :(得分:8)
在类语句的主体结束之前,类对象不存在。但是在 def语句的主体后面的命名空间中可以使用这些函数。所以你想要的是:
class Test(object):
def run_operations(self, operation, *args, **kwargs):
try:
function = self.functions[operation]
except KeyError:
# some log ...
else:
function(self, args, kwargs)
def function_a(self, *args, **kwargs):
print "A"
def function_b(self, *args, **kwargs):
print "B"
functions = {
'operation_a' : function_a,
'operation_b' : function_b,
}
编辑:正如提到的那样,你也可以使用getattr
和当前的实例和方法名来获取方法,但这意味着所有方法都成为潜在的'操作',这是既不明确又有潜在的安全问题。仍然使用getattr明确“选择”合法操作的一种方法是只在相关函数中添加一个标记,即:
def operation(func):
func.is_operation = True
return func
class Test(object):
def run_operations(self, operation, *args, **kwargs):
method = getattr(self, operation, None)
if method is None:
# raise or log or whatever
elif not method.is_operation:
# raise or log or whatever
else:
method(*args, **kwargs)
@operation
def operation_a(self, *args, **kwargs):
print "A"
@operation
def operation_b(self, *args, **kwargs):
print "B"
def not_an_operation(self):
print "not me"
另一个解决方案是使用内部类作为操作的命名空间,即:
class Test(object):
def run_operations(self, operation, *args, **kwargs):
method = getattr(self.operations, operation, None)
if method is None:
# raise or log or whatever
else:
method(self, *args, **kwargs)
class operations(object):
@classmethod
def operation_a(cls, instance, *args, **kwargs):
print "A"
@classmethod
def operation_b(cls, instance, *args, **kwargs):
print "B"
还有其他可能的解决方案。哪一个是“最好的”取决于您的需求,但除非您构建一个框架,否则基于dict的框架尽可能简单,可读和有效。
答案 1 :(得分:3)
class Test():
def run_operations(operation, *args, **kwargs):
try:
functions[str(operation)](self, args, kwargs)
except KeyError:
// some log ...
def function_a(self, *args, **kwargs):
print A
def function_b(self, *args, **kwargs):
print B
functions = {
'operation_a' : function_a, #now you can reference it since it exists
'operation_b' : function_b, #you do not prefix it with class name
}
答案 2 :(得分:2)
你真的需要一个字吗?
getattr(Test(), 'function_a')
<bound method Test.function_a of <__main__.Test object at 0x019011B0>>
所有实例方法:
>>> import inspect
>>> dict(filter(lambda x: inspect.ismethod(x[1]), inspect.getmembers(Test())))
{'run_operations': <bound method Test.run_operations of <__main__.Test object at 0x01901D70>>, 'function_b': <bound method Test.
function_b of <__main__.Test object at 0x01901D70>>, 'function_a': <bound method Test.function_a of <__main__.Test object at 0x0
1901D70>>}
答案 3 :(得分:0)
你根本做不到,因为这个类还没有定义。与Python中的其他所有类一样,类定义是可执行代码,并且在执行定义之前,类名称不会分配给命名空间。