이런 상황이 …
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
해야합니까?
답변
중첩 클래스의 메서드는 외부 클래스의 인스턴스 속성에 직접 액세스 할 수 없습니다.
내부 클래스의 인스턴스를 만든 경우에도 외부 클래스의 인스턴스가 반드시 존재하는 것은 아닙니다.
실제로 중첩이 내부 클래스와 외부 클래스 간의 특정 관계를 의미하지 않기 때문에 중첩 클래스를 사용하지 않는 것이 좋습니다.
답변
내부 클래스 인스턴스에서 Outer의 클래스 인스턴스에 액세스하려고합니다. 따라서 팩토리 메서드를 사용하여 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()
게다가 … “self”는 관례에 의해서만 사용되므로 다음과 같이 할 수 있습니다.
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()
보트를 약간 밀어 내고이 내부 클래스를 확장 (NB가 작동하도록하려면 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()
나중
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 ))
답변
이와 같은 중첩 클래스 대신 상속을 사용한다는 의미입니까? 당신이하는 일은 파이썬에서 의미가 없습니다.
내부 클래스의 메서드 내에서 Outer
참조하여의 some_method에 액세스 할 수 Outer.some_method
있지만 예상대로 작동하지 않습니다. 예를 들어 다음을 시도하면 :
class Outer(object):
def some_method(self):
# do something
class Inner(object):
def __init__(self):
Outer.some_method()
… Inner
객체를 초기화 할 때 TypeError가 발생 합니다 . 첫 번째 인수로 인스턴스 Outer.some_method
를받을 것으로 예상하기 때문 Outer
입니다. (위의 예에서는 기본적 some_method
으로의 클래스 메서드 로 호출하려고합니다 Outer
.)
답변
메타 클래스를 사용하여 외부 클래스에 쉽게 액세스 할 수 있습니다. 외부 클래스를 만든 후 모든 클래스에 대한 속성 dict를 확인하고 (또는 필요한 모든 로직을 적용합니다.
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!
이 방법을 사용하면 서로간에 두 클래스를 쉽게 바인딩하고 참조 할 수 있습니다.
답변
나는 사용하는 일부 파이썬 코드를 생성 한 외부 클래스를 자사에서 내부 클래스 서로 좋은 아이디어를 기반으로, 답변 이 질문에 대한. 짧고 간단하며 이해하기 쉽다고 생각합니다.
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:
) 라는 클래스 가 생성됩니다. 액세스해야하는 하위 클래스 (부모)가 있습니다. 하나의 서브 클래스는 “x1″이라고합니다. 이 서브 클래스에서 코드 a.run_func()
가 실행됩니다.
그런 다음 “a”( ) 클래스 에서 파생 된 “b”라는 다른 클래스가 생성 class b(a):
됩니다. 그 후 일부 코드가 실행됩니다 b.x1()
(파생 된 하위 클래스 인 b의 하위 함수 “x1″호출). 이 함수는 “a”클래스에 정의 된 함수가 참조하도록 설정되어 있으므로 부모 “b”의 “run_func”함수가 아니라a.run_func()
“a”클래스의 “run_func”함수를 호출하여 실행됩니다 . 클래스 “a”의 기능에 대한 것입니다.
이로 인해 문제가 발생할 수 있으며 (예 : 함수 a.run_func
가 삭제 된 경우) 클래스에서 코드를 다시 작성하지 않는 유일한 해결책 은 클래스 “a”에서 파생 된 모든 클래스에 대해 업데이트 된 코드로 a.x1
하위 클래스를 재정의 x1
하는 것입니다. 이는 분명히 어렵고 가치가 없습니다. 그것.
답변
내가 발견 이 .
질문에 맞게 조정했습니다.
class Outer(object):
def some_method(self):
# do something
class _Inner(object):
def __init__(self, outer):
outer.some_method()
def Inner(self):
return _Inner(self)
나는 당신이 어떻게 든 이것 또는 무언가에 대한 데코레이터를 작성할 수 있다고 확신합니다