Python function pointers within the same Class

二次信任 提交于 2019-12-06 13:15:12

The class object doesn't exist before the end of the class statement's body. But the functions are available in the namespace after the def statement's body. So what you want is:

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,
        }

edit: As alko mentionned, you could also use getattr with the current instance and method name to get the method, but it means all methods become potential 'operations', which is both unexplicit and a potential security issue. One way to still use getattr with explicit "selection" of the legit operations is to just add a marker to the relevant functions, ie:

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"

Yet another solution is to use an inner class as namespace for the operations, ie:

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"

There are still other possible solutions. Which one is "best" depends on your needs, but unless you're building a framework the dict-based one is as simple, readable and effective as possible.

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
    }

Do you really need a dict?

getattr(Test(), 'function_a')
<bound method Test.function_a of <__main__.Test object at 0x019011B0>>

all instance methods:

>>> 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>>}   

You simply can't, because the class is not defined yet. Class definitions, like everything else in Python, are executable code, and the class name is not assigned to the namespace until the definition is executed.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!