2016-10-21 86 views
0

我需要一個級路由器(由於缺乏一個更好的詞)。路由器需要實例化一個類&根據傳遞給它的變量調用該類實例的一個函數。如何調用類函數從變量

如何正確定義類的功能?

如何正確調用類的功能?

示例代碼:

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) 
+0

如果我還不知道該課程,我該如何正確定義該方法?那麼我將如何正確使用變量&而不是方法名稱來調用該對象? – Emily

+0

如果直接調用「路由」方法,那麼使用類的意義何在?一個普通的函數也可以工作。 –

+0

主要原因是因爲路由器的實例將在線程上運行。將有數百個線程。每個線程都需要一個獨特的路由器實例,他們需要同時工作。我不確定如何在不使用課程的情況下做到這一點? – Emily

回答

2

我需要一個級路由器(由於缺乏一個更好的詞)。

您確定您需要一個嗎?

路由器需要實例化一個類&調用類的實例

當它屬於一類或實例的函數,函數通常命名爲「方法」。不是很重要,但它使事情更清晰。此外,根據定義,「實例」顯然總是一個類的實例;)

如何正確定義類函數? 如何正確調用類函數?

請問路由器真的必須是類嗎?但無論如何...

這裏有幾個不同的問題(當然,我假設你需要的東西,這就夠了通用)。

第一個是你的類(將由「路由器」被實例化的一個)構造函數可能需要一些ARGS - 位置或命名或兩者兼而有之。如果路由器負責實現類的實例化(但是它應該是?),則必須將這些參數(位置和名稱)傳遞給路由器。由於你的路由器必須是通用的(否則它是無用的),你不能在你的路由器的構造函數中明確地命名這些參數。

希望,Python有一個方法調用函數時,在調用時分別使用***運營商來說,「解壓」的元組(對於位置參數)和類型的字典(命名參數),即:

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

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

這讓您將參數傳遞給函數在一個通用的方法。

所以,如果你希望你的路由器負責instanciating「目標」類的,你必須支持這一點:

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 - 因爲你需要有Worker類,它是構造器的參數來實現路由器的實例化,你可以自己實例化Worker並將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 /如果工人的實例非常昂貴,而且您甚至不確定是否真的需要它,在這種情況下,您希望等到路由器的「主」方法被稱爲instanciate工人。

第二個問題是「我如何得到工作人員的方法名稱」。 Lukas已經回答了這個問題:你使用getattr(obj, attrname)

第三個問題是「如果我的工作者方法需要參數,我該如何傳遞它們」。這與工人的構造函數參數是一樣的問題,所以解決方案顯然是相同的。根據具體的使用情況,你必須在實例化路由器或調用它的「主要」方法時傳遞這些參數。

WRT /這個「主」的方法,請記住,您可以通過實現__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() 

請注意,儘管我保留了您的「路由器」術語,但我上面介紹的大部分都是已知的模式。您可能想要搜索「代理」,「代理方法」和(對於最後一個例子)「部分評估」。

+0

如果你正在穿線路由器,你還會使用一個函數嗎? – Emily

+0

路由器構造函數也將添加到傳遞給該實例的變量。在實例化之前,路由器也會做一個「設置」和後續的「清理」工作。我可以想象這可以用函數和裝飾器完成?但是上課似乎是最好的解決方案。考慮到這一點,你還會使用一個函數嗎? – Emily

+0

@當然沒有,當然我會使用一個類 - 即使只是爲了可讀性。還有/你的第一個問題:如果你是Python的新手(這可能是你的問題),你可能想在使用線程之前考慮三次 - 在大多數情況下,他們不會在python中購買太多(搜索「全局解釋器鎖定」),所以你可能會更好地使用子進程。這裏又取決於你沒有提供的背景,但我認爲這很有用。 –

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