2012-06-15 12 views
19

Ok, więc mam ten kod:„classmethod” obiekt nie jest wymagalne

class SomeClass: 
    @classmethod 
    def func1(cls,arg1): 
     #---Do Something--- 
    @classmethod 
    def func2(cls,arg1): 
     #---Do Something--- 

    # A 'function map' that has function name as its keys and the above function 
    # objects as values 
    func_map={'func1':func1,'func2':func2} 

    @classmethod 
    def func3(cls,arg1): 
     # following is a dict(created by reading a config file) that 
     # contains func names as keys and boolean as values that tells 
     # the program whether or not to run that function 
     global funcList 
     for func in funcList: 
      if funcList[func]==True: 
       cls.func_map[func](arg1)  #TROUBLING PART!!! 

    if _name__='main' 
     SomeClass.func3('Argumentus-Primus') 

Kiedy uruchomić ten ciśgle błąd:

 
Exception TypeError: "'classmethod' object is not callable" 

jestem w stanie dowiedzieć się, co jest nie tak z to i będzie wdzięczny za twoją pomoc.

+0

Przepraszamy za niedokładne dodanie opisu błędu. Edytował odpowiedź (i to wszystko, co wiem o tym błędzie). A gdybym miał odpowiedź na pytanie, dlaczego miałbym zadać to pytanie? : S Rozejrzałem się za tym błędem i odkryłem, że ludzie otrzymywali te błędy, ponieważ nie używali poprawnie kodu, np. w wątku facet miał dostęp do elementu ze słownika takiego jak 'someDict (key)' i robił podobny błąd .. ale uważam, że dzwonię do funkcji (która powinna być wywołana, prawda?). Popraw mnie, jeśli się mylę. – user1126425

+0

Gdy pojawi się błąd, skopiuj wklej cały ślad stosu. Powie Ci przydatne rzeczy, na przykład, w której linii pojawia się błąd. –

+0

Lattye, 'Exception TypeError:" Obiekt 'classmethod' nie jest wywoływany "w 'pyadecg.__wrap_py_func 'ignored' to wszystko, co mogę zobaczyć w stosie stacków. Dzięki za pomoc – user1126425

Odpowiedz

12

Nie można tworzyć odwołania do classmethods aż klasa została zdefiniowana. Musisz przenieść go poza definicję klasy. Jednak używanie globalnej mapy funkcji do decydowania o tym, co jest uruchamiane, jest naprawdę niezręczne. Jeśli opisałeś, co próbujesz z tym zrobić, prawdopodobnie moglibyśmy zaproponować lepsze rozwiązanie.

class SomeClass(object): 
    @classmethod 
    def func1(cls, arg1): 
     print("Called func1({})".format(arg1)) 

    @classmethod 
    def func2(cls, arg1): 
     print("Call func2({})".format(arg1)) 

    @classmethod 
    def func3(cls, arg1): 
     for fnName,do in funcList.iteritems(): 
      if do: 
       try: 
        cls.func_map[fnName](arg1) 
       except KeyError: 
        print("Don't know function '{}'".format(fnName)) 

# can't create function map until class has been created 
SomeClass.func_map = { 
    'func1': SomeClass.func1, 
    'func2': SomeClass.func2 
} 

if __name__=='__main__': 
    funcList = {'func1':True, 'func2':False} 
    SomeClass.func3('Argumentus-Primus') 
+2

Dzięki za odpowiedź Hugh. 1. To bardzo mnie myli. Dlaczego pyton nie zatrzyma mnie w tym miejscu, kiedy ponownie je wymówię w dyktacie? Narzekałem tylko, gdy próbowałem to nazwać. 2. Ten globalny funcList został utworzony przez odczytanie pliku konfiguracyjnego (konfiguracja odczytu odbywa się w innym module), więc nie mogłem wymyślić innej metody ... 3. Próbuję uzyskać konfigurację wejściową plik od użytkownika, który powie programowi, jakie funkcje mają być uruchamiane, a jednocześnie chce zachować wyraźny rozdział między różnymi częściami kodu (aby ułatwić jego rozszerzenie). – user1126425

0

Dodaj self jako argument dla każdej metody w klasie.

także

if _name__='main' 
    SomeClass.func3('Argumentus-Primus') 

powinna wyglądać następująco:

if __name__=='__main__': 
    SomeClass.func3('Argumentus-Primus') 

i nie powinno być w ciele klasy.

+0

to wszystkie metody klasowe, a nie metody instancji. – user1126425

+0

Rozumiem. Dlaczego po prostu nie użyjesz instrukcji switch zamiast mapy? Lub możesz użyć getattr, aby wywołać metodę. To znaczy, jeśli stworzyłeś metodę instancji. – ulu5

+0

Starałem się być elegancki w moim kodzie ... i napisać go tak, aby można go było łatwo rozbudować :) Nie chcę używać go jako metody instancji ... ponieważ powoduje to zmiany niektórych zasobów, które są używane przez inne moduły, które muszą je wyświetlać w spójny sposób. – user1126425

2

Metodę klasową otacza daną funkcję magicznym obiektem, który nie jest rzeczywiście możliwy do wywołania. Można go wywołać tylko przy użyciu składni ClassName.method(args).

nie polecam, aby zrobić to w ten sposób, należy rozważyć robi coś takiego zamiast:

func_list = { 
    'func1': True, 
    'func2': False 
} 

class SomeClass(object): 
    def do_func1(self, arg1): 
     print("func1", arg1) 

    def do_func2(self, arg1): 
     print("func2", arg1) 

    def run(self, arg1): 
     for name, enabled in func_list.items(): 
      if enabled: 
       the_method = getattr(self, 'do_' + name) 
       the_method(arg1) 


if __name__ == '__main__': 
    sc = SomeClass() 
    sc.run('Argumentus-Primus') 
+0

Dzięki za odpowiedź Antti. Czy mówisz, że metoda klasy nie jest opcją? W moim przypadku mógłbym wywołać func3 po prostu używając SomeClass.func3 (arg1), ale problem zdawał się wywoływać z innymi funkcjami. Potrzebowałem również metod klasycznych, aby móc to zrobić bez tworzenia instancji tej klasy w innych modułach (co jest pewnego rodzaju ograniczeniem mojego kodu). – user1126425

+0

A dlaczego nie tworzyć instancji? Jeśli nigdy nie stworzysz klasy, nie potrzebujesz lekcji. Nawet metody klasowe ... –

+0

Hmm .. Myślę, że masz rację. Postępowałem zgodnie z konwencjami Java. W każdym razie przedstawił mi ten problem i chcę się dowiedzieć, dlaczego nie mogę tego zrobić w ten sposób? – user1126425

0

Być może trzeba będzie wypróbować metodę statyczną.

@staticmethod 
def function():... 

Metody statyczne nie przekazują klasy jako domyślnego pierwszego argumentu.

+1

Interesujące, ale po prostu prowadzi do "TypeError:" staticmethod " obiekt nie jest dostępny do wywołania. – starfry

9

odkryłem coś dzisiaj, że będą pomocne tutaj: Możemy rozpakować magiczne staticmethod i classmethod obiektów poprzez: getattr(func, '__func__')

Jak znajdę te informacje? Korzystając z PyCharm JetBrains (nie wiem o innych IDE Pythona), obejrzałem kod źródłowy dla @staticmethod i @classmethod. Obie klasy definiują atrybut __func__.

"Resztę pozostawia się jako ćwiczenie dla czytelnika."

+2

To są tylko stuby stworzone dla pycharm, dzięki czemu kodowanie i introspekcja działają. W rzeczywistości te dekoratory są wbudowane, które są napisane w C –

Powiązane problemy