web-dev-qa-db-ja.com

classmethodsを呼び出そうとするコードのさまざまなエラー

私はこのコードを持っています:

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

これを実行すると、エラーが発生し続けます。

例外TypeError: "'classmethod'オブジェクトを呼び出せません" 

私はこれの何が悪いのか理解することができません、そしてあなたの助けをいただければ幸いです。

21
user1126425

クラスが定義されるまで、classmethodsへの参照を作成することはできません。クラス定義から移動する必要があります。ただし、グローバル関数マップを使用して何を実行するかを決定するのは非常に厄介です。これで何をしようとしているのかを説明していただければ、おそらくより良い解決策を提案できます。

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')
16
Hugh Bothwell

今夜、ここで役立つ何かを発見しました。getattr(func, '__func__')を介して魔法のstaticmethodオブジェクトとclassmethodオブジェクトをアンラップできます。

この情報をどのように見つけましたか? JetBrainsのPyCharm(他のPython IDE)についてはわかりません)を使用して、_@staticmethod_と_@classmethod_のソースコードを表示しました。どちらのクラスも属性___func___。

"残りは読者の練習問題として残されています。"

10
kevinarpe

Classmethodは、実際には呼び出せない魔法のオブジェクトで特定の関数をラップします。 ClassName.method(args)構文を使用してのみ呼び出すことができます。

この方法で行うことはお勧めしません。代わりに次のようなことを検討してください。

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 __== '__main__':
    sc = SomeClass()
    sc.run('Argumentus-Primus')
2
Antti Haapala

他のすべての回答は、class SomeClass定義の外にコードを追加することを提案しています。場合によっては大丈夫かもしれませんが、私の場合は非常に不便でした。 func_mapをクラス内に保持したかったのです。

次のアプローチをお勧めします。クラス変数ではなく、もう1つのclassmethodを使用します。

class SomeClass:
    # ...

    @classmethod
    def get_func_map(cls):
        return {'func1': cls.func1, 'func2': cls.func2}

    @classmethod
    def func3(cls, arg1):
        # .....
        cls.get_func_map()[func_name](arg1)

もちろん、get_func_mapメソッドを呼び出すたびに新しい辞書が作成されないように、このコードを変更する必要があります。簡単です。例を小さく明確にするために自分でやったわけではありません。

python 3.6でテスト済み

1
lesnik

クラス内の各メソッドの引数としてselfを追加します。

また

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

次のようになります。

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

クラスの本体内にあるべきではありません。

0
ulu5

これを行うには悪い方法があります:

def func3(cls,arg1):
    global funcList
    for func in funcList:
        if funcList[func]==True:
            eval(f'SomeClass.{func}')(arg1)

Funcが関数の名前である場合にのみ機能します。そうは言っても、しないでくださいユーザー入力を取得しているため、このメソッドを使用してください。呼び出しに厄介なコードを挿入するのは非常に簡単です。そうは言っても、これは機能します。

0
Rob Rose

静的メソッドを試す必要があるかもしれません。

@staticmethod
def function():...

静的メソッドは、暗黙の最初の引数としてクラスを渡しません。

0
John