クラスFoo
をクラスBar
で展開したいのですが、通常の方法(class Foo(Bar)
)で展開できないという問題があります。クラスBar
は多少動的に生成されます。
私はこの小さな例を作って、私の望ましい結果を説明しました。
class Bar:
def super_cool_function():
print("Cool")
class Foo:
def __init__(self, another_class):
# I want to extend Foo by another_class
# Desired result
foobar = Foo(Bar)
foobar.super_cool_function()
もう一度これはnotです:
class Foo(Bar):
pass
foobar = Foo()
foobar.super_cool_function()
「クラスBar
は多少動的に生成されます」それは問題ありません...ブループリント(Foo
によって拡張されるクラスの)の青写真に従っている限り、pythonクロージャはこちら。内部でクラスを作成し、関数からそれを返すことにより、新しいクラスを動的に作成します。
def get_class(superclass):
class Foo(superclass):
def __init__(self, ...):
...
return Foo
DynamicFoo = get_class(Bar)
myobj = DynamicFoo()
これは、pythonでよく見られるパターンです。クロージャを利用して、コールバックとクラスを動的に作成します。
上記の答えは、Bar
が実際に定義されていない場合でも、正しく定義されていることを前提としています。 super_cool_function
にはセルフパラメータがありません。インスタンスメソッドは常に最初のパラメーター(インスタンス自体)が最初の属性として自動的に渡されて呼び出されます。
したがって、Bar
の正しい定義は次のようになります。
class Bar:
def super_cool_function(self):
print("Cool")
次に、内部クラスFoo
の最も単純な定義でget_class
を定義します。
def get_class(superclass):
class Foo(superclass):
pass
return Foo
DynamicFoo = get_class(Bar)
myobj = DynamicFoo()
myobj.super_cool_function()
# Cool
あなたの望ましい使い方は少し奇妙です:
foobar = Foo(Bar)
Foo
クラスオブジェクトを渡してBar
インスタンスを作成し、Bar
インスタンスのように動作するものを取得することを期待しています。通常、プロキシクラスは、引数なしでオブジェクトを構築するだけでなく、プロキシするオブジェクトを取得するか、どこかをルックアップするように設計されています。
しかし、それは__init__
オブジェクトを構築するメソッド。これは単なる標準のプロキシクラスです。そう:
class Foo:
def __init__(self, cls):
self._inst = cls()
def __getattr__(self, name):
return getattr(self._inst, name)
def __setattr__(self, name, value):
if name in {'_inst'}:
super().__setattr__(name, value)
else:
setattr(self._inst, name, value)
def __delattr__(self, name):
delattr(self._inst, name)
もちろん、それを呼び出すことはできませんsuper_cool_function
はfoobar
に対してBar
インスタンスよりも多く、メソッドとして定義されており、self
パラメータがないためです。ただし、Foo
インスタンスから取得したのと同じエラーがBar
インスタンスから取得されます。
>>> foobar.super_cool_function
<bound method Bar.super_cool_function of <__main__.Bar object at 0x129f95080>>
>>> foobar.super_cool_function()
TypeError: super_cool_function() takes 0 positional arguments but 1 was