Python函数指针在同一个Class中

时间:2013-12-04 17:25:48

标签: python function class function-pointers

我在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个解决方案可以解决这个问题:

  1. 在类构造函数(__init__()),
  2. 中定义操作字典
  3. 将可调用函数移动到另一个类(在我的例子中,该类位于不同的模块中,我没有尝试使用同一模块中的类),
  4. 在同一个类中定义@staticmethod
  5. 的功能

    但是,我仍然不知道为什么最初的方法似乎不正确。因此,如何在实例化之前引用同一个类中的函数?

4 个答案:

答案 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中的其他所有类一样,类定义是可执行代码,并且在执行定义之前,类名称不会分配给命名空间。