如何从变量调用类函数

时间:2016-10-21 10:56:45

标签: python python-3.x

我需要一个类路由器(缺少一个更好的词)。路由器需要实例化一个类&根据传递给它的变量调用该类实例的函数。

如何正确定义类函数?

如何正确调用类函数?

示例代码:

class ClassWorker1:

    def function_1(self):
        print('1a')

    def function_2(self):
        print('2a')

    def function_3(self):
        print('3a')


class ClassWorker2:

    def function_1(self):
        print('1b')

    def function_2(self):
        print('2b')

    def function_3(self):
        print('3b')


class ClassRouter(object):
    def __init__(self, class_name, class_function):
        self.class_instance = class_name()
        self.class_function = class_function
        self.main()

    def main(self):
         # how should I call the class function here?
         self.class_instance.class_function()
         return


a = 1
b = 1


if a == 1:
    class_name = ClassWorker1
else:
    class_name = ClassWorker1

if b == 1:
    # Strings won't work as class function definition
    # I won't know the class at this point.  I will only know
    # the shared function name at this point.
    # how could this class function be defined directly?
    class_function = 'function_1'

elif b == 2:
    class_function = 'function_2'

else:
    class_function = 'function_3'


ClassRouter(class_name, class_function)

3 个答案:

答案 0 :(得分:2)

  

我需要一个类路由器(缺少一个更好的词)。

您确定需要吗?

  

路由器需要实例化一个类&调用该类实例的函数

当它属于类或实例时,函数通常被命名为“方法”。不是很重要,但它让事情变得更加清晰。此外,根据定义,“实例”显然总是一个类的实例;)

  

如何正确定义类功能?   如何正确调用类函数?

路由器真的是否必须是一个类?但无论如何......

这里有几个不同的问题(我当然假设你需要一些足够通用的东西)。

第一个是你的类(将由“路由器”实例化的那个)构造函数可能需要一些args - position或named或两者。如果路由器有责任实现类(但它应该是什么?),你必须将这些args(位置和命名)传递给路由器。而且由于你的路由器必须是通用的(否则它没用),你不能在路由器的构造函数中明确地命名这些args。

希望Python有一种方法可以在调用函数时“解包”元组(用于位置args)和dicts(用于命名args),在调用时分别使用***运算符,即:

def somefunc(arg1, arg2, arg3="foo", arg4=None):
    print arg1, arg2, arg3, arg4

args = ("one", "two", "three")
kwargs = {"arg4": "four"}
somefunc(*args, **kwargs)

这允许您以通用方式将参数传递给函数。

因此,如果您希望路由器负责实现“目标”类的实施,您必须支持这一点:

class Router(object):
    def __init__(self, cls, clsargs=None, clskwargs=None):
        if clsargs is None:
            clsargs = ()
        if clskwargs is None:
            clskwargs = {}
        self._obj = cls(*clsargs, **clskwargs)


class Worker(object):
    def __init__(self, name):
        self.name = name
            print self.name


r = Router(Worker, clsargs=("foo",))
# or
r = Router(Worker, clskwargs={"name":"foo"})

现在请注意,此时你真的没有获得任何东西(除了更多的代码)让路由器实现了工作者 - 因为你需要拥有Worker类和它的构造函数的args来实现路由器,你可以好吧,只需自己实现工作者并将Worker实例传递给路由器:

由于你必须引用传递给路由器的类(否则你无法传递它),你也可以

class Router(object):
    def __init__(self, obj):
        self._obj = obj

class Worker(object):
    def __init__(self, name):
        self.name = name
            print self.name

r = Router(Worker("foo"))
# or 
r = Router(Worker(name="foo"))

让路由器实现工作人员是有意义的情况是:

1 /如果工程师的构造函数参数在路由器实例化时不知道并且稍后要传递(这需要一个不同的路由器方法来传递这些参数)

2 /如果工人的实例非常昂贵而你甚至不确定你真的需要它,在这种情况下你要等到路由器的“主”方法被调用来实现工人。

第二个问题是“我如何按名称获得工人的方法”。 Lukas已经回答了这个问题:你使用getattr(obj, attrname)

第三个问题是“如果我的工人方法需要参数,我该如何传递它们”。这与worker的构造函数参数的问题相同,因此解决方案显然是相同的。根据具体的使用情况,你必须在实例化路由器或调用它的“主”方法时传递这些args。

wrt / this“main”方法,请记住,您可以通过实现__call__方法来定义自己的可调用类型,即

class NotAFunc(object):
    def __init__(self, wot):
        self.wot = wot

    def __call__(self, count):
        print self.wot * count


notafunc = NotAFunc("wot ? ")
notafunc(42)

因此将它用作路由器的“主要”方法

是有意义的

现在你真的需要一个路由器吗? Python函数本身就是对象(因此函数可以接受函数和/或返回函数),而且充当闭包(闭包是“捕获”已定义的环境的一部分的函数):

def route(instance, methodname, methargs=None, methkwargs=None):
    method = getattr(instance, methodname)
    if methargs is None:
        methargs = ()
    if methkwargs is None:
        methkwargs = {}
    def func():
        return method(*methargs, **methkwargs)
    return func

class Worker(object):
    def __init__(self, name):
        self.name = name

    def work(self, count):
        return [self.name for i in range(count)]


r = route(Worker("foo"), "work", (42,))
print r()

请注意,虽然我保留了您的“路由器”术语,但我上面描述的大部分内容都是已知的模式。您可能想要搜索“代理”,“代理方法”和(最后一个例子)“部分评估”。

答案 1 :(得分:1)

您正在寻找动态属性查找。

class C:
    def c1(self, x):
        return 2*x

instance = C()
method_name = 'c1'

method = getattr(instance, method_name)
print(method(1))  # call method and print result

答案 2 :(得分:0)

您需要覆盖(new-style!)类的__new__方法。

class ClassRouter(object):
    def __new__(self, class_name, *args):
        if arg=="Class1":
            new_instance = ClassWorker1(*args)
            new_instance.method()
            return new_instance
        elif arg=="Class2":
            return ClassWorker2(*args)