私はそのような状況にあります...
class Outer(object):
def some_method(self):
# do something
class Inner(object):
def __init__(self):
self.Outer.some_method() # <-- this is the line in question
Outer
クラスからInner
クラスのメソッドにアクセスするにはどうすればよいですか?
編集-回答いただきありがとうございます。これを実装するためにどのように設計したかを再評価し、より堅牢な方法を考え出す必要があると結論しています。
ネストされたクラスのメソッドは、外部クラスのインスタンス属性に直接アクセスできません。
内部クラスのインスタンスを作成した場合でも、必ずしも外部クラスのインスタンスが存在するわけではないことに注意してください。
実際、ネストされたクラスは内部クラスと外部クラスの間の特定の関係を意味しないため、ネストされたクラスの使用は推奨されません。
内部クラスインスタンスから外部クラスインスタンスにアクセスしようとしています。そのため、factory-methodを使用して、Innerインスタンスを構築し、Outerインスタンスをそれに渡します。
class Outer(object):
def createInner(self):
return Outer.Inner(self)
class Inner(object):
def __init__(self, outer_instance):
self.outer_instance = outer_instance
self.outer_instance.somemethod()
def inner_method(self):
self.outer_instance.anothermethod()
多分私は怒っていますが、これは確かに非常に簡単に思えます-事は外側のクラスのメソッド内にあなたの内側のクラスを作ることです...
def do_sthg( self ):
...
def messAround( self ):
outerClassSelf = self
class mooble():
def do_sthg_different( self ):
...
outerClassSelf.do_sthg()
さらに...「自己」は慣例でのみ使用されるため、これを行うことができます。
def do_sthg( self ):
...
def messAround( outerClassSelf ):
class mooble():
def do_sthg_different( self ):
...
outerClassSelf.do_sthg()
外部クラスの外側からこの内部クラスを作成できないことに反対するかもしれません...しかし、これは真実ではありません:
class Bumblebee():
def do_sthg( self ):
print "sthg"
def giveMeAnInnerClass( outerClassSelf ):
class mooble():
def do_sthg_different( self ):
print "something diff\n"
outerClassSelf.do_sthg()
return mooble
それから、どこか数マイル離れたところ:
blob = Bumblebee().giveMeAnInnerClass()()
blob.do_sthg_different()
ボートを少し押し出し、この内部クラスを拡張して(super()が機能するようにするには、moobleのクラスシグネチャを「class mooble(object)」に変更する必要があります)
class InnerBumblebeeWithAddedBounce( Bumblebee().giveMeAnInnerClass() ):
def bounce( self ):
print "bounce"
def do_sthg_different( self ):
super( InnerBumblebeeWithAddedBounce, self ).do_sthg_different()
print "and more different"
ibwab = InnerBumblebeeWithAddedBounce()
ibwab.bounce()
ibwab.do_sthg_different()
later
mrh1997は、この手法を使用して配信される内部クラスの非一般的な継承について興味深い点を提起しました。しかし、解決策は非常に簡単なようです:
class Fatty():
def do_sthg( self ):
pass
class InnerFatty( object ):
pass
def giveMeAnInnerFattyClass(self):
class ExtendedInnerFatty( Fatty.InnerFatty ):
pass
return ExtendedInnerFatty
fatty1 = Fatty()
fatty2 = Fatty()
innerFattyClass1 = fatty1.giveMeAnInnerFattyClass()
innerFattyClass2 = fatty2.giveMeAnInnerFattyClass()
print ( issubclass( innerFattyClass1, Fatty.InnerFatty ))
print ( issubclass( innerFattyClass2, Fatty.InnerFatty ))
このようなクラスをネストするのではなく、継承を使用するつもりですか?あなたがしていることは、Pythonでは意味がありません。
内部クラスのメソッド内でOuter.some_method
を参照するだけでOuter
のsome_methodにアクセスできますが、期待どおりに機能しません。たとえば、これを試してみると:
class Outer(object):
def some_method(self):
# do something
class Inner(object):
def __init__(self):
Outer.some_method()
... Outer.some_method
はInner
インスタンスを最初の引数として受け取ることを想定しているため、Outer
オブジェクトを初期化するとTypeErrorが発生します。 (上記の例では、基本的にsome_method
をOuter
のクラスメソッドとして呼び出そうとしています。)
私はいくつかのPythonコードを作成しましたouterクラス)をそのinnerクラスから、この質問に対する別の answer からの良いアイデアに基づいています。
_class higher_level__unknown_irrelevant_name__class:
def __init__(self, ...args...):
...other code...
# Important lines to access sub-classes.
subclasses = self._subclass_container()
self.some_subclass = subclasses["some_subclass"]
del subclasses # Free up variable for other use.
def sub_function(self, ...args...):
...other code...
def _subclass_container(self):
_parent_class = self # Create access to parent class.
class some_subclass:
def __init__(self):
self._parent_class = _parent_class # Easy access from self.
# Optional line, clears variable space, but SHOULD NOT BE USED
# IF THERE ARE MULTIPLE SUBCLASSES as would stop their parent access.
# del _parent_class
class subclass_2:
def __init__(self):
self._parent_class = _parent_class
# Return reference(s) to the subclass(es).
return {"some_subclass": some_subclass, "subclass_2": subclass_2}
_
メインコード、「プロダクション対応」(コメントなしなど)。山かっこ内の各値(たとえば_<x>
_)をすべて目的の値に置き換えてください。
_class <higher_level_class>:
def __init__(self):
subclasses = self._subclass_container()
self.<sub_class> = subclasses[<sub_class, type string>]
del subclasses
def _subclass_container(self):
_parent_class = self
class <sub_class>:
def __init__(self):
self._parent_class = _parent_class
return {<sub_class, type string>: <sub_class>}
_
__subclass_container
_という名前の関数を作成して、(関数内で実行されているコードからの)上位クラスへの参照である変数self
にアクセスするラッパーとして機能します。
__parent_class
_のサブクラスがアクセスできるこの関数の変数self
への参照である__subclass_container
_という名前の変数を作成します(他のself
変数との名前の競合を回避します)サブクラスで)。
__subclass_container
_関数を呼び出すコードが内部のサブクラスにアクセスできるように、サブクラス/サブクラスを辞書/リストとして返します。
上位クラス(または必要な場所)内の___init__
_関数で、関数__subclass_container
_から返されたサブクラスを変数subclasses
に受け取ります。
subclasses
変数に格納されているサブクラスを、より高いレベルのクラスの属性に割り当てます。
サブクラスをより高いレベルのクラスに割り当てるコードをコピーしやすくし、___init__
_関数が変更されました:
メインコードの行12の前に挿入します。
_ def _subclass_init(self):
_
次に、この関数に(メインコードの)行5〜6を挿入し、行4〜7を次のコードに置き換えます。
_ self._subclass_init(self)
_
サブクラスの数が多い/不明な場合に、より高いレベルのクラスにサブクラスを割り当てることができるようにします。
6行目を次のコードに置き換えます。
_ for subclass_name in list(subclasses.keys()):
setattr(self, subclass_name, subclasses[subclass_name])
_
"a"(_class a:
_)という名前のクラスが作成されます。それにアクセスする必要があるサブクラス(親)があります。 1つのサブクラスは「x1」と呼ばれます。このサブクラスでは、コードa.run_func()
が実行されます。
次に、「b」という名前の別のクラスが作成され、クラス「a」(class b(a):
)からderivedが作成されます。その後、いくつかのコードがb.x1()
を実行します(派生サブクラスであるbのサブ関数「x1」を呼び出します)。この関数はa.run_func()
を実行し、クラス "a"の関数 "run_func"を呼び出します。not親の関数 "run_func"クラス「a」で定義された関数は、その親であるクラス「a」の関数を参照するように設定されているためです。
これは問題を引き起こします(たとえば、関数_a.run_func
_が削除された場合)、クラス_a.x1
_のコードを書き換えない唯一の解決策は、サブクラス_x1
_をすべての更新コードで再定義することですクラス「a」から派生したクラスは明らかに難しく、それだけの価値はありません。
別の可能性:
class _Outer (object):
# Define your static methods here, e.g.
@staticmethod
def subclassRef ():
return Outer
class Outer (_Outer):
class Inner (object):
def outer (self):
return _Outer
def doSomething (self):
outer = self.outer ()
# Call your static mehthods.
cls = outer.subclassRef ()
return cls ()
メタクラスを使用して外部クラスに簡単にアクセスできます:外部クラスの作成後、クラスの属性辞書をチェックし(または必要なロジックを適用します-私の例は簡単な例です)、対応する値を設定します:
import six
import inspect
# helper method from `peewee` project to add metaclass
_METACLASS_ = '_metaclass_helper_'
def with_metaclass(meta, base=object):
return meta(_METACLASS_, (base,), {})
class OuterMeta(type):
def __new__(mcs, name, parents, dct):
cls = super(OuterMeta, mcs).__new__(mcs, name, parents, dct)
for klass in dct.values():
if inspect.isclass(klass):
print("Setting outer of '%s' to '%s'" % (klass, cls))
klass.outer = cls
return cls
# @six.add_metaclass(OuterMeta) -- this is alternative to `with_metaclass`
class Outer(with_metaclass(OuterMeta)):
def foo(self):
return "I'm outer class!"
class Inner(object):
outer = None # <-- by default it's None
def bar(self):
return "I'm inner class"
print(Outer.Inner.outer)
>>> <class '__main__.Outer'>
assert isinstance(Outer.Inner.outer(), Outer)
print(Outer().foo())
>>> I'm outer class!
print(Outer.Inner.outer().foo())
>>> I'm outer class!
print(Outer.Inner().outer().foo())
>>> I'm outer class!
print(Outer.Inner().bar())
>>> I'm inner class!
このアプローチを使用すると、相互に2つのクラスを簡単にバインドおよび参照できます。
@tsnorriの説得力のある考え方を拡張し、外側のメソッドは 静的メソッド である可能性があること
class Outer(object):
@staticmethod
def some_static_method(self):
# do something
class Inner(object):
def __init__(self):
self.some_static_method() # <-- this will work later
Inner.some_static_method = some_static_method
これで、問題の行は実際に呼び出されるまでに機能するはずです。
上記のコードの最後の行は、Innerクラスに、Outer静的メソッドのクローンである静的メソッドを提供します。
これは、2つのPython機能、 関数はオブジェクト 、および スコープはテキスト という機能を利用しています。
通常、ローカルスコープは(テキストの)現在の関数のローカル名を参照します。
...または現在のclass私たちの場合。したがって、Outerクラスの定義に対して「ローカル」オブジェクト(Inner
およびsome_static_method
)は、その定義内で直接参照できます。