少しpythonプログラムを
class a():
def _func(self):
return "asdf"
# Not sure what to resplace __init__ with so that a.func will return asdf
def __init__(self, *args, **kwargs):
setattr(self, 'func', classmethod(self._func))
if __== "__main__":
a.func
トレースバックエラーが表示されます
Traceback (most recent call last):
File "setattr_static.py", line 9, in <module>
a.func
AttributeError: class a has no attribute 'func'
私が理解しようとしているのは、オブジェクトをインスタンス化せずにクラスメソッドをクラスに動的に設定するにはどうすればよいですか?
この問題の答えは
class a():
pass
def func(cls, some_other_argument):
return some_other_argument
setattr(a, 'func', classmethod(func))
if __== "__main__":
print(a.func)
print(a.func("asdf"))
次の出力を返します
<bound method type.func of <class '__main__.a'>>
asdf
クラスオブジェクトへの単純な割り当てまたはクラスオブジェクトのsetattrによって、クラスにクラスメソッドを動的に追加できます。ここでは、混乱を減らすためにクラスが大文字で始まるというpython規則を使用しています。
# define a class object (your class may be more complicated than this...)
class A(object):
pass
# a class method takes the class object as its first variable
def func(cls):
print 'I am a class method'
# you can just add it to the class if you already know the name you want to use
A.func = classmethod(func)
# or you can auto-generate the name and set it this way
the_name = 'other_func'
setattr(A, the_name, classmethod(func))
ここにはいくつかの問題があります。
__init__
_は、インスタンスを作成するときにのみ実行されます。 obj = a()
。これは、_a.func
_を実行するときに、setattr()
呼び出しが発生しなかったことを意味します_func
_内で___init__
_を使用する代わりに、_self._func
_または_self.__class__._func
_を使用する必要があります。self
はa
のインスタンスになります。インスタンスに属性を設定すると、クラスではなくそのインスタンスでのみ使用可能になります。したがって、setattr(self, 'func', self._func)
を呼び出した後でも、_a.func
_はAttributeErrorを発生させますstaticmethod
を使用すると、何もしません。staticmethod
は結果の関数を返し、引数を変更しません。したがって、代わりにsetattr(self, 'func', staticmethod(self._func))
のようなものが必要になります(ただし、上記のコメントを考慮すると、これはまだ機能しません)質問は、実際に何をしようとしているのですか?インスタンスを初期化するときにクラスに属性を本当に追加したい場合は、次のようなことができます。
_class a():
def _func(self):
return "asdf"
def __init__(self, *args, **kwargs):
setattr(self.__class__, 'func', staticmethod(self._func))
if __== '__main__':
obj = a()
a.func
a.func()
_
ただし、これはまだ奇妙です。これで、_a.func
_にアクセスして問題なく呼び出すことができますが、_a.func
_のself
引数は常に、最後に作成されたa
のインスタンスになります。 _func()
のようなインスタンスメソッドをクラスの静的メソッドまたはクラスメソッドに変える正しい方法を実際に考えることはできません。
クラスに関数を動的に追加しようとしているので、おそらく次のようなものが実際にしようとしていることに近くなりますか?
_class a():
pass
def _func():
return "asdf"
a.func = staticmethod(_func) # or setattr(a, 'func', staticmethod(_func))
if __== '__main__':
a.func
a.func()
_
この方法でできます
class a():
def _func(self):
return "asdf"
setattr(a, 'func', staticmethod(a._func))
if __== "__main__":
a.func()
私は仕事をする意味のある方法を見つけました:
まず、このようなBaseClassを定義します。
_class MethodPatcher:
@classmethod
def patch(cls, target):
for k in cls.__dict__:
obj = getattr(cls, k)
if not k.startswith('_') and callable(obj):
setattr(target, k, obj)
_
これで元のクラスができました:
_class MyClass(object):
def a(self):
print('a')
_
次に、新しいPatcher
クラスに追加する新しいメソッドを定義します。
(この場合、メソッド名の先頭を__
_にしないでください)
_class MyPatcher(MethodPatcher):
def b(self):
print('b')
_
次に呼び出します:
_MyPatcher.patch(MyClass)
_
したがって、新しいメソッドb(self)
が元のMyClass
に追加されていることがわかります。
_obj = MyClass()
obj.a() # which prints an 'a'
obj.b() # which prints a 'b'
_
MethodPatcher
がデカールされている場合、2つのことを行う必要があります。
ChildClass
のModelPatcher
の子クラスを定義しますChildClass.patch(TargetClass)
を呼び出しますそのため、デコレーターを使用することで2番目のステップを簡略化できることがすぐにわかりました。
デコレータを定義します:
_def patch_methods(model_class):
def do_patch(cls):
cls.patch(model_class)
return do_patch
_
そして、次のように使用できます。
_@patch_methods(MyClass)
class MyClassPatcher(MethodPatcher):
def extra_method_a(self):
print('a', self)
@classmethod
def extra_class_method_b(cls):
print('c', cls)
# !!ATTENTION!! the effect on declaring staticmethod here may not work as expected:
# calling this method on an instance will take the self into the first argument.
# @staticmethod
# def extra_static_method_c():
# print('c')
_
したがって、MethodPatcher
と_patch_method
_の定義を単一のモジュールに入れることができます。
_# method_patcher.py
class MethodPatcher:
@classmethod
def patch(cls, target):
for k in cls.__dict__:
obj = getattr(cls, k)
if not k.startswith('_') and callable(obj):
setattr(target, k, obj)
def patch_methods(model_class):
def do_patch(cls):
cls.patch(model_class)
return do_patch
_
したがって、自由に使用できます。
_from method_patcher import ModelPatcher, patch_model
_
すぐに、MethodPatcher
クラスは必須ではなく、_@patch_method
_デコレーターが作業を行うことができるため、[〜#〜] finally [〜#〜]のみ_patch_method
_が必要です:
_def patch_methods(model_class):
def do_patch(cls):
for k in cls.__dict__:
obj = getattr(cls, k)
if not k.startswith('_') and callable(obj):
setattr(model_class, k, obj)
return do_patch
_
そして、使用法は次のようになります。
_@patch_methods(MyClass)
class MyClassPatcher:
def extra_method_a(self):
print('a', self)
@classmethod
def extra_class_method_b(cls):
print('c', cls)
# !!ATTENTION!! the effect on declaring staticmethod here may not work as expected:
# calling this method on an instance will take the self into the first argument.
# @staticmethod
# def extra_static_method_c():
# print('c')
_
setattr(self, 'func', staticmethod(self._func))
する必要があります
___init__
_を呼び出すには、クラスvariable=a()
を初期化する必要があります。静的クラスには初期化がありません
私はPython 2.7.5を使用していますが、上記のソリューションを動作させることができませんでした。
# define a class object (your class may be more complicated than this...)
class A(object):
pass
def func(self):
print 'I am class {}'.format(self.name)
A.func = func
# using classmethod() here failed with:
# AttributeError: type object '...' has no attribute 'name'