programing

내부 클래스에서 외부 클래스에 액세스하는 방법은 무엇입니까?

magicmemo 2023. 6. 30. 22:16
반응형

내부 클래스에서 외부 클래스에 액세스하는 방법은 무엇입니까?

저도 그런 상황이...

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의 클래스 인스턴스에 액세스하려고 합니다.따라서 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 mess_around(self):

    outer_class_self = self

    class Mooble():
        def do_sthg_different(self):
            ...
            outer_class_self.do_sthg()

게다가... "self"는 관습에 의해서만 사용되기 때문에, 당신은 다음과 같이 할 수 있습니다.

def do_sthg(self):
    ...

def mess_around(outer_class_self):

    class Mooble():
        def do_sthg_different(self):
            ...
            outer_class_self.do_sthg()

그러면 외부 클래스 외부에서 이 내부 클래스를 만들 수 없다는 것이 반대가 될 수 있습니다.하지만 이것은 사실이 아닙니다.

class Bumblebee():

    def do_sthg(self):
        print "sthg"
    
    def give_me_an_inner_class(outer_class_self):

        class Mooble():
            def do_sthg_different(self):
                print "something diff\n"
                outer_class_self.do_sthg()
        return Mooble
    

그리고, 마일 떨어진 곳에.

blob = Bumblebee().give_me_an_inner_class()()
blob.do_sthg_different()    

심지어 보트를 조금 밖으로 밀어내고 이 내부 클래스를 확장합니다(NB는 얻을 수 있습니다).super()을 하기 는 일려면클서변합경니다야의 .Moobleclass Mooble(object)).

class InnerBumblebeeWithAddedBounce(Bumblebee().give_me_an_inner_class()):
    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 give_me_an_inner_fatty_class(self):
        class ExtendedInnerFatty(Fatty.InnerFatty):
            pass
        return ExtendedInnerFatty
                
fatty1 = Fatty()
fatty2 = Fatty()

innerFattyClass1 = fatty1.give_me_an_inner_fatty_class()
innerFattyClass2 = fatty2.give_me_an_inner_fatty_class()

print (issubclass(innerFattyClass1, Fatty.InnerFatty))
print (issubclass(innerFattyClass2, Fatty.InnerFatty))

파티에 늦게... 하지만 더 확장하기 위해.@mike rodent멋진 답변입니다. 아래에 그의 솔루션이 얼마나 유연한지, 그리고 왜 그것이 받아들여져야 하는지(또는 받아들여져야 했는지)를 보여주는 제 자신의 예를 제시했습니다.

파이썬 3.7

class Parent():

    def __init__(self, name):
        self.name = name
        self.children = []

    class Inner(object):
        pass

    def Child(self, name):
        parent = self
        class Child(Parent.Inner):
            def __init__(self, name):
                self.name = name
                self.parent = parent
                parent.children.append(self)
        return Child(name)



parent = Parent('Bar')

child1 = parent.Child('Foo')
child2 = parent.Child('World')

print(
    # Getting its first childs name
    child1.name, # From itself
    parent.children[0].name, # From its parent
    # Also works with the second child
    child2.name,
    parent.children[1].name,
    # Go nuts if you want
    child2.parent.children[0].name,
    child1.parent.children[1].name
)

print(
    # Getting the parents name
    parent.name, # From itself
    child1.parent.name, # From its children
    child2.parent.name,
    # Go nuts again if you want
    parent.children[0].parent.name,
    parent.children[1].parent.name,
    # Or insane
    child2.parent.children[0].parent.children[1].parent.name,
    child1.parent.children[1].parent.children[0].parent.name
)


# Second parent? No problem
parent2 = Parent('John')
child3 = parent2.Child('Doe')
child4 = parent2.Child('Appleseed')

print(
    child3.name, parent2.children[0].name,
    child4.name, parent2.children[1].name,
    parent2.name # ....
)

출력:

Foo Foo World World Foo World
Bar Bar Bar Bar Bar Bar Bar
Doe Doe Appleseed Appleseed John

다시 한 번, 멋진 대답, 마이크에 대한 소품!

이거 찾았어요.

질문에 맞게 수정:

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)

저는 당신이 어떻게든 이것이나 다른 것들을 위한 장식가를 쓸 수 있다고 확신합니다.

관련:파이썬의 내부 수업의 목적은 무엇입니까?

메타 클래스를 사용하여 외부 클래스에 쉽게 액세스할 수 있습니다. 외부 클래스를 만든 후 모든 클래스에 대해 속성 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}

메인 코드인 "생산 준비 완료"(댓글 등 없음). 각 괄 안 모 값 예 교 야 해 체 합 니 다 을 든 의 호 예 니 : 합 ▁remember 다 :<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>}

이 방법의 작동 방식에 대한 설명(기본 단계):

  1. 는 이름의 ._subclass_container변수에 접근하기 위한 포장지 역할을 하다self(함수 내부에서 실행 중인 코드에서) 상위 레벨 클래스에 대한 참조.

    1. 는 이름의 ._parent_class 변에대참니다입조에 입니다.self 하함수의 _subclass_container액세스할 수 . (이 다른 합니다.)self변수(하위 클래스의 경우).

    2. 클래스를 사전가 " " " " "/" " " " " "/" " " " " 를 호출합니다._subclass_container함수는 내부의 하위 항목에 액세스할 수 있습니다.

  2. __init__ 클래스 필요한 이라면 어디든)에서합니다._subclass_container 수에변에 .subclasses.

  3. 에 된 하위 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])

이 솔루션이 유용한 위치와 상위 레벨의 클래스 이름을 얻을 수 없는 위치에 대한 예제 시나리오:

이 "입니다.class a:이됩니다.이 생성됩니다.액세스해야 하는 하위 클래스(상위 클래스)가 있습니다.하나의 하위 클래스를 "x1"이라고 합니다.클래스에서는 이하클에서코드는스래위▁the입니다.a.run_func()실행됩니다.

그런 다음 클래스 "a"에서 파생된 "b"라는 이름의 다른 클래스가 생성됩니다.class b(a):그는 그후일코실행니다됩드가부▁runs다▁).▁code니를 실행합니다.b.x1()(파생 하위 클래스인 b의 하위 함수 "x1"을 계산).은 이함는실다니됩행수▁this▁function▁runs 실행합니다.a.run_func()클래스 "a"에 정의된 함수가 클래스 "a"의 함수를 참조하도록 설정되어 있기 때문에 클래스 "a"의 함수 "run_func"를 호출하지 않고 클래스 "b"의 함수를 호출합니다.

이로 인해 문제가 발생할 수 있습니다(예: 기능하는 경우).a.run_func삭제됨) 및 클래스에서 코드를 다시 쓰지 않는 유일한 솔루션a.x1하위 클래스를 재정의하는 것입니다.x1클래스 "a"에서 파생된 모든 클래스에 대한 업데이트된 코드로, 분명 어렵고 가치가 없을 것입니다.

이렇게 클래스를 중첩하는 것이 아니라 상속을 사용하려는 것입니까?파이썬에서는 당신이 하는 일이 말이 되지 않습니다.

당신은 할 수 있습니다.OuterOuter.some_method내부 계층의 방식 내에서, 하지만 당신이 기대하는 것처럼 작동하지 않을 것입니다.예를 들어, 다음과 같이 시도합니다.

class Outer(object):

    def some_method(self):
        # do something

    class Inner(object):
        def __init__(self):
            Outer.some_method()

시 됩니다.파일을 초기화할 때 유형 오류가 표시됩니다.Inner 객체, 왜면하.Outer.some_method는 를받것예니다됩상로으을▁an다▁to▁receive니예▁expects됩을 받을 것으로 예상합니다.Outer인스턴스를 첫 번째 인수로 지정합니다. (위의 예에서, 당신은 기본적으로 호출하려고 합니다.some_method의 수업 으로서.Outer.)

또 다른 가능성:

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

우리가 할 수 있는 것은 내부 클래스 내부의 외부 클래스의 자체 변수를 클래스 인수로 전달하고 내부 클래스를 내부 클래스로 전달하는 것입니다.

class Outer:
    def __init__(self):
        self.somevalue=91
        self.Inner=self.Inner(self)
    def SomeMethod(self):
        print('This is Something from Outer Class')

    class Inner:
        def __init__(self,Outer)
            self.SomeMethod=Outer.SomeMethod
            self.somevalue=Outer.somevalue
    
        def SomeAnotherMethod(self):
            print(self.somevalue)
            self.SomeMethod()        

>>>f=Outer()
>>>f.Inner.SomeAnotherMethod() 
91
This is Something from Outer Class

이제 이 기능을 실행한 후 작동합니다.

외부 방법이 정적 방법일 수 있다는 @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 static 메서드의 복제본인 static 메서드를 제공합니다.


이는 함수객체이고 범위가 텍스트라는 두 가지 Python 기능을 활용합니다.

일반적으로 로컬 스코프는 (텍스트적으로) 현재 함수의 로컬 이름을 참조합니다.

...또는 우리의 경우에는 현재 클래스.따라서 객체는 외부 클래스의 정의에 "국소적"입니다.Inner그리고.some_static_method을 해당 할 수 는 해당 정의 내에서 직접 참조할 수 있습니다.

@mike-rodent의 멋진 답변에 감사드리며, @tre-x에 감사드립니다.

접근 방식에 따라 3단계 클래스 중첩 정의 및 상호 호출의 예는 다음과 같습니다.

# [0 - CLASSDEBUG_TEST, 1 - ONELINEND_SYSEXIT]
_DF = (True, True)

class rootcls_stackoverflow_q2024566_a60908562(object):
    # https://stackoverflow.com/a/60908562

    def __init__(self):
        pass
    
    class innercls(object):        
        pass

    def print_hi(self):
        print(f"hi rootcls")
    
    def call_innercls_function(self):
        parent = self.innercls_parent("Barbar")
        parent.print_hi()
        child = parent.innercls_child("Foofoo")
        child.print_hi()

        util = self.innercls_util()
        util.get_current_format_time()
        util.get_python_interpreter_path()
    
    def innercls_util(self):
        rootcls = self
        class innercls_util(rootcls.innercls):
            def get_current_format_time(self):
                import time
                time_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                print(time_str)
                return time_str

            def get_python_interpreter_path(self):
                import sys
                pypath_interpreter = sys.executable
                print(pypath_interpreter)
                return pypath_interpreter
            
        return innercls_util()    # Be sure to include parentheses

    def innercls_parent(self, name):
        rootcls = self
        class innercls_parent(rootcls.innercls):
            def __init__(self, name):
                self.name = name
                self.children = []
            
            def print_hi(self):
                print(f"hi {self.name} of innercls_parent")
            
            def call_rootcls_function(self):
                print(f"call root class function:", end = " ")
                rootcls.print_hi()
            
            def innercls_child(self, name, rootcls=rootcls):
                rootcls = rootcls
                parentcls = self
                class innercls_child(rootcls.innercls):
                    def __init__(self, name):
                        self.name = name
                        self.parent = parentcls
                        parentcls.children.append(self)
                    
                    def print_hi(self):
                        print(f"hi {self.name} of innercls_child")
                    
                    def call_parentcls_function(self):
                        parentcls.print_hi()

                    def call_rootcls_function(self):
                        print(f"call root class function:", end = " ")
                        rootcls.print_hi()
                return innercls_child(name)
        return innercls_parent(name)
    
    def innercls_test(self):
        rootcls = self
        class innercls_test(rootcls.innercls):
            def __init__(self):
                pass

            def test_doit(self):
                parent = rootcls.innercls_parent("Bar")
                child1 = parent.innercls_child("Foo")
                child2 = parent.innercls_child("World")

                print(
                    child1.name,
                    parent.children[0].name,

                    child2.name,
                    parent.children[1].name,

                    child2.parent.children[0].parent.children[1].parent.name,
                    child1.parent.children[1].parent.children[0].parent.name
                )

                rootcls.print_hi()
                rootcls.call_innercls_function()

                parent.print_hi()
                parent.call_rootcls_function()

                child1.print_hi()
                child2.print_hi()
        return innercls_test()
if ('_DF' in locals() or '_DF' in globals()) and _DF[0]: 
    instance_rootcls = rootcls_stackoverflow_q2024566_a60908562()
    instance_innercls_test = instance_rootcls.innercls_test()
    instance_innercls_test.test_doit()
if ('_DF' in locals() or '_DF' in globals()) and _DF[1]:
    import sys; print(); sys.exit(0)

클래스를 만들어 내부 클래스를 장식할 수 있습니다.이 경우 @inner.

이 사람이 장식가이기 때문에외부.A = 내부(외부). 코드가 를 요구하면 일단 당신의 코드가 Outer를 요구하면.될 것입니다 A 것다실입니될행.inner.__get__메서드. 새 특성 집합이 있는 원래 클래스(A)를 반환합니다(A.owner = Outer).

클래스 A의 클래스 메소드, 이 경우def add(cls, y=3) 속성 " 속성을사수있다니습할용새▁new"를 사용할 수 .ownerreturn cls.owner.x + y + 1.

setattr(owner, name, self.inner) 이유는 설명자가 없기 때문입니다.owner.name => Outer.A => A더 이상 클래스 내부의 인스턴스가 아닙니다.

이게 도움이 되길 바랍니다.

    class inner:
    
        def __init__(self, inner):
            self.inner = inner
    
        def __get__(self, instance, owner):
            print('__get__ method executed, only once... ')
            name = self.inner.__name__
            setattr(self.inner, 'owner', owner) 
            setattr(owner, name, self.inner) # breaks descriptor
            return self.inner #returns Inner
    
    class Outer:
        x = 1
    
        @inner
        class A:
    
            @classmethod
            def add(cls, y=3):
                return cls.owner.x + y + 1
    
    print(Outer.A.add(0)) # First time executes inner.__get__ method
    print(Outer.A.add(0)) # Second time not necessary.

    >> __get__ method executed, only once... 
    >> 2
    >> 2

외부 클래스 개체를 내부 클래스로 구문 분석하여 수행할 수 있습니다.

class Outer():

    def __init__(self,userinput):
        self.userinput = userinput
    
    
    def outer_function(self):
        self.a = self.userinput + 2


    class Inner():

        def inner_function(self):
            self.b = self.a + 10

이것을 정의한 후, 그것은 기능을 실행해야 합니다.

m = Outer(3)
m.outer_function()
print (m.a)
#this will output 5

이제 그것은 외부 클래스의 변수를 가지고 있습니다.그런 다음, 내부 클래스 기능을 실행해야 합니다.

m.Inner.inner_function(m)

외부 클래스의 객체 m은 내부 클래스의 함수(괄호 안)로 구문 분석됩니다. 이제 내부 클래스 함수는 외부 클래스에서 self.a에 액세스합니다.

print (m.b)
#this will output 15
class Outer():
    class Inner():
        def __init__(self, o):
            self._outer=o
        def demo(self):
            print("I am the inner class and I call the outer class now")
            self._outer.whoami()

    def __init__(self):
        self._inner=Outer.Inner(self)

    def whoami(self):
        print("I am the outer class")

    def demo(self):
        self._inner.demo()

myOuter=Outer()
myOuter.demo()

너무 간단합니다.

입력:

class A:
    def __init__(self):
        pass

    def func1(self):
        print('class A func1')

    class B:
        def __init__(self):
            a1 = A()
            a1.func1()

        def func1(self):
            print('class B func1')

b = A.B()
b.func1()

산출량

클래스 A func1

클래스 B func1

언급URL : https://stackoverflow.com/questions/2024566/how-to-access-outer-class-from-an-inner-class

반응형