[python] 중첩 클래스의 범위?

파이썬에서 중첩 된 클래스의 범위를 이해하려고합니다. 다음은 내 예제 코드입니다.

class OuterClass:
    outer_var = 1
    class InnerClass:
        inner_var = outer_var

클래스 생성이 완료되지 않고 오류가 발생합니다.

<type 'exceptions.NameError'>: name 'outer_var' is not defined

시도 inner_var = Outerclass.outer_var는 작동하지 않습니다. 나는 얻다:

<type 'exceptions.NameError'>: name 'OuterClass' is not defined

나는 정적에 액세스하려고 outer_var에서을 InnerClass.

이를 수행하는 방법이 있습니까?



답변

class Outer(object):
    outer_var = 1

    class Inner(object):
        @property
        def inner_var(self):
            return Outer.outer_var

이것은 유사한 것들이 다른 언어에서 작동하는 것과 완전히 같지 않으며,에 대한 액세스 범위를 지정하는 대신 전역 조회를 사용합니다 outer_var. (이름 Outer이 바인딩 된 개체를 변경하면 이 코드는 다음에 실행될 때 해당 개체를 사용합니다.)

대신 모든 Inner객체가 Outer왜냐하면 outer_var실제로 인스턴스 속성 이기 때문에에 대한 참조를 갖기 를 원하는 경우 :

class Outer(object):
    def __init__(self):
        self.outer_var = 1

    def get_inner(self):
        return self.Inner(self)
        # "self.Inner" is because Inner is a class attribute of this class
        # "Outer.Inner" would also work, or move Inner to global scope
        # and then just use "Inner"

    class Inner(object):
        def __init__(self, outer):
            self.outer = outer

        @property
        def inner_var(self):
            return self.outer.outer_var

중첩 클래스는 Python에서 다소 드물며 클래스 간의 특별한 관계를 자동으로 암시하지 않습니다. 중첩하지 않는 것이 좋습니다. ( 원하는 경우 클래스 속성을 Outer로 설정할 수 있습니다 Inner.)


답변

나는 당신이 간단히 할 수 있다고 생각합니다.

class OuterClass:
    outer_var = 1

    class InnerClass:
        pass
    InnerClass.inner_var = outer_var

발생한 문제는 다음과 같습니다.

블록은 단위로 실행되는 Python 프로그램 텍스트의 일부입니다. 다음은 블록입니다 : 모듈, 함수 본문 및 클래스 정의.
(…)
범위는 블록 내에서 이름의 가시성을 정의합니다.
(…)
클래스 블록에 정의 된 이름의 범위는 클래스 블록으로 제한됩니다. 메소드의 코드 블록으로 확장되지 않습니다. 여기에는 함수 범위를 사용하여 구현되기 때문에 생성기 표현식이 포함됩니다. 이것은 다음이 실패 함을 의미합니다.

   class A:

       a = 42

       b = list(a + i for i in range(10))

http://docs.python.org/reference/executionmodel.html#naming-and-binding

위의 의미 :
함수 본문은 코드 블록이고 메서드는 함수입니다. 그러면 클래스 정의에있는 함수 본문에서 정의 된 이름이 함수 본문으로 확장되지 않습니다.

귀하의 경우에 이것을 의역 :
클래스 정의는 코드 블록이며 외부 클래스 정의에 존재하는 내부 클래스 정의에서 정의 된 이름은 내부 클래스 정의로 확장되지 않습니다.


답변

중첩 클래스를 사용하지 않는 것이 더 나을 수 있습니다. 중첩해야하는 경우 다음을 시도하십시오.

x = 1
class OuterClass:
    outer_var = x
    class InnerClass:
        inner_var = x

또는 중첩하기 전에 두 클래스를 모두 선언하십시오.

class OuterClass:
    outer_var = 1

class InnerClass:
    inner_var = OuterClass.outer_var

OuterClass.InnerClass = InnerClass

(그 후에 del InnerClass필요한 경우 할 수 있습니다 .)


답변

가장 쉬운 솔루션 :

class OuterClass:
    outer_var = 1
    class InnerClass:
        def __init__(self):
            self.inner_var = OuterClass.outer_var

명시 적이어야하지만 많은 노력이 필요하지 않습니다.


답변

파이썬에서 변경 가능한 객체는 참조로 전달되므로 외부 클래스의 참조를 내부 클래스에 전달할 수 있습니다.

class OuterClass:
    def __init__(self):
        self.outer_var = 1
        self.inner_class = OuterClass.InnerClass(self)
        print('Inner variable in OuterClass = %d' % self.inner_class.inner_var)

    class InnerClass:
        def __init__(self, outer_class):
            self.outer_class = outer_class
            self.inner_var = 2
            print('Outer variable in InnerClass = %d' % self.outer_class.outer_var)


답변

모든 설명은 Python 문서 The Python Tutorial 에서 찾을 수 있습니다.

첫 번째 오류 <type 'exceptions.NameError'>: name 'outer_var' is not defined. 설명은 다음과 같습니다.

메서드 내에서 데이터 속성 (또는 다른 메서드!)을 참조하는 약어는 없습니다. 이것이 실제로 메서드의 가독성을 증가 시킨다는 것을 발견했습니다. 메서드를 살펴볼 때 지역 변수와 인스턴스 변수를 혼동 할 가능성이 없습니다.

The Python Tutorial 9.4 에서 인용

두 번째 오류 <type 'exceptions.NameError'>: name 'OuterClass' is not defined

클래스 정의가 정상적으로 종료되면 (끝까지) 클래스 객체가 생성됩니다.

Python Tutorial 9.3.1 에서 인용

그래서 당신이 시도했을 때 inner_var = Outerclass.outer_var, Quterclass아직 생성되지 않은 것입니다.name 'OuterClass' is not defined

첫 번째 오류에 대한 더 자세하지만 지루한 설명 :

비록 클래스가 둘러싸는 함수의 범위에 접근 할 수 있지만, 그것들은 클래스 내에 중첩 된 코드에 대한 둘러싸는 범위의 역할을하지 않습니다. 파이썬은 참조 된 이름에 대해 둘러싸는 함수를 검색하지만 둘러싸는 클래스는 검색하지 않습니다. 즉, 클래스는 로컬 범위이고 둘러싸는 로컬 범위에 액세스 할 수 있지만 추가 중첩 코드에 대한 둘러싸는 로컬 범위 역할을하지 않습니다.

Learning.Python (5th) .Mark.Lutz 에서 인용


답변