IT TIP

Python에서 개인 및 보호 메서드 상속

itqueen 2020. 12. 15. 20:37
반응형

Python에서 개인 및 보호 메서드 상속


파이썬에는 '실제'개인 / 보호 방법이 없습니다. 이 접근 방식은 아무것도 숨기는 것이 아닙니다. 저는 파이썬이 무엇을하는지 이해하고 싶습니다.

class Parent(object):
    def _protected(self):
        pass

    def __private(self):
        pass

class Child(Parent):
    def foo(self):
        self._protected()   # This works

    def bar(self):
        self.__private()    # This doesn't work, I get a AttributeError:
                            # 'Child' object has no attribute '_Child__private'

그렇다면이 동작은 '보호 된'메서드는 상속되지만 '개인'은 전혀 상속되지 않음을 의미합니까?
아니면 내가 놓친 것이 있습니까?


Python에는 개인 정보 보호 모델이 없으며 C ++, C # 또는 Java와 같은 액세스 수정자가 없습니다. 진정한 '보호'또는 '개인'속성은 없습니다.

선도적 인 이중 밑줄없이 후행를 두 번 밑줄 이름은 엉망이 상속 할 때 충돌로부터 보호 할 수 있습니다. 서브 클래스는 자체 __private()메서드를 정의 할 수 있으며 부모 클래스의 동일한 이름을 방해하지 않습니다. 이러한 이름은 클래스 개인 으로 간주됩니다 . 클래스 외부에서도 여전히 액세스 할 수 있지만 실수로 충돌 할 가능성은 훨씬 적습니다.

맹 글링은 이러한 이름 앞에 추가 밑줄과 클래스 이름을 추가하여 (이름이 사용되는 방식이나 존재 여부에 관계없이) 효과적으로 네임 스페이스를 제공하여 수행 됩니다. 에서 Parent클래스, 어떤 __private식별자 이름 (컴파일시) 치환 _Parent__private년 동안, Child클래스 식별자에 의해 대체된다 _Child__private클래스 정의 사방.

다음이 작동합니다.

class Child(Parent):
    def foo(self):
        self._protected()

    def bar(self):
        self._Parent__private()

어휘 분석 문서에서 예약 된 식별자 클래스를 참조하십시오 .

__*
클래스 개인 이름. 이 범주의 이름은 클래스 정의 컨텍스트 내에서 사용될 때 기본 클래스와 파생 클래스의 "개인"특성 간의 이름 충돌을 방지하기 위해 잘린 형식을 사용하도록 다시 작성됩니다.

이름에 대한 참조 문서 :

Private name mangling : 클래스 정의에서 텍스트로 발생하는 식별자가 두 개 이상의 밑줄 문자로 시작하고 두 개 이상의 밑줄로 끝나지 않는 경우 해당 클래스의 개인 이름으로 간주됩니다. 개인 이름은 코드가 생성되기 전에 더 긴 형식으로 변환됩니다. 변환은 이름 앞에 선행 밑줄이 제거되고 단일 밑줄이 삽입 된 클래스 이름을 삽입합니다. 예를 들어, __spamHam이라는 클래스에서 발생 하는 식별자 _Ham__spam. 이 변환은 식별자가 사용되는 구문 컨텍스트와 독립적입니다.

클래스 를 하위 클래스로 지정하려는 개발자에게 특정 이름을 사용할 수 없거나 클래스를 손상시킬 위험이 있음 특별히 알리지 않으려면 클래스 전용 이름을 사용하지 마십시오 . 게시 된 프레임 워크 및 라이브러리 외에는이 기능이 거의 사용되지 않습니다.

PEP 8 파이썬 스타일 가이드는 개인 이름 맹 글링에 대한 대답이있다 :

클래스가 하위 클래스로 지정되고 하위 클래스에서 사용하지 않으려는 속성이있는 경우 이중 선행 밑줄과 후행 밑줄없이 이름을 지정하는 것이 좋습니다. 이것은 파이썬의 이름 변경 알고리즘을 호출하는데, 여기서 클래스의 이름이 속성 이름으로 변경됩니다. 이렇게하면 하위 클래스에 이름이 같은 속성이 실수로 포함 된 경우 속성 이름 충돌을 방지 할 수 있습니다.

참고 1 : 단순 클래스 이름 만 엉킨 이름에 사용되므로 하위 클래스가 동일한 클래스 이름과 속성 이름을 모두 선택하면 이름 충돌이 발생할 수 있습니다.

참고 2 : 이름 맹 글링은 디버깅 및 __getattr__()덜 편리함 과 같은 특정 용도를 만들 수 있습니다 . 그러나 이름 맹 글링 알고리즘은 잘 문서화되어 있으며 수동으로 수행하기 쉽습니다.

참고 3 : 모든 사람이 이름 변경을 좋아하는 것은 아닙니다. 우발적 인 이름 충돌을 피해야하는 필요성과 고급 발신자가 사용할 가능성의 균형을 맞추십시오.


double __속성이 변경되어에서 _ClassName__method_name암시하는 의미 론적 프라이버시보다 더 비공개 적으로 _method_name만듭니다.

You can technically still get at it if you'd really like to, but presumably no one is going to do that, so for maintenance of code abstraction reasons, the method might as well be private at that point.

class Parent(object):
    def _protected(self):
        pass

    def __private(self):
        print("Is it really private?")

class Child(Parent):
    def foo(self):
        self._protected()

    def bar(self):
        self.__private()

c = Child()
c._Parent__private()

This has the additional upside (or some would say primary upside) of allowing a method to not collide with child class method names.


Also PEP8 says

Use one leading underscore only for non-public methods and instance variables.

To avoid name clashes with subclasses, use two leading underscores to invoke Python's name mangling rules.

Python mangles these names with the class name: if class Foo has an attribute named __a, it cannot be accessed by Foo.__a. (An insistent user could still gain access by calling Foo._Foo__a.) Generally, double leading underscores should be used only to avoid name conflicts with attributes in classes designed to be subclassed.

You should stay away from _such_methods too, by convention. I mean you should treat them as private


By declaring your data member private :

__private()

you simply can't access it from outside the class

Python supports a technique called name mangling.

This feature turns class member prefixed with two underscores into:

_className.memberName

if you want to access it from Child() you can use: self._Parent__private()


Although this is an old question, I encountered it and found a nice workaround.

In the case you name mangled on the parent class because you wanted to mimic a protected function, but still wanted to access the function in an easy manner on the child class.

parent_class_private_func_list = [func for func in dir(Child) if func.startswith ('_Parent__')]

for parent_private_func in parent_class_private_func_list:
        setattr(self, parent_private_func.replace("_Parent__", "_Child"), getattr(self, parent_private_func))        

The idea is manually replacing the parents function name into one fitting to the current namespace. After adding this in the init function of the child class, you can call the function in an easy manner.

self.__private()

AFAIK, in the second case Python perform "name mangling", so the name of the __private method of the parent class is really:

_Parent__private

And you cannot use it in child in this form neither

ReferenceURL : https://stackoverflow.com/questions/20261517/inheritance-of-private-and-protected-methods-in-python

반응형