Доступ к частным атрибутам в унаследованном классе в python

#python #oop #inheritance

Вопрос:

У меня есть класс a , определенный следующим образом:

 class a:
    def __init__(self, w, x, y, z):
        self.w = w
        self.x = x
        self.y = y
        self.__z = z
 

У меня также есть другой класс b , который наследует a , определенный следующим образом:

 class b(a):
    def __init__(self, w, x, y, z, t):
        super().__init__(w, x, y, z)
        self.__t = t
 

Теперь , если бы у меня был доступ w, x, y изнутри b , я мог бы просто сделать:

 self.w
self.x
self.y
 

Но я не могу этого сделать self.z или self.__z получить доступ z . Поэтому мой вопрос в том, как вы можете получить доступ к более простым значениям, таким как z внутри класса b

(Я знаю, что в python на самом деле нет частных переменных, и я мог self._a__z b бы получить доступ из класса z , но я ищу методы, которые позволили бы мне просто сделать что-то вроде self.z доступа изнутри z b )

Комментарии:

1. Весь смысл в том, чтобы сделать это частным, состоит в том, чтобы сделать это трудным. _a__z это единственный способ сделать это.

2. Весь смысл использования имени с двойным подчеркиванием-manglinbg заключается в предотвращении коллизий имен в подклассах. Если вы хотите просто использовать self.z , то не используйте искажение имени с двойным подчеркиванием. Вы пытаетесь получить свой торт и съесть его тоже.

3. 1. Если z он предназначен для доступа, b то он не должен быть закрытым, как предположил @juanpa.arrivillaga. 2. Если z предполагается, что он частично доступен (например, только для чтения) b , вы можете использовать getter s и/или setter s, как и в других языках ООП.

Ответ №1:

Существует множество способов решить проблему, изменив API класса a , чтобы предоставить его __z атрибут более удобным для наследования способом. Например, вы могли бы сделать фактическое искаженное имя атрибута детализацией реализации и сделать общедоступный API property :

 class a:
    def __init__(self, w, x, y, z):
        self.w = w
        self.x = x
        self.y = y
        self.__z = z

    @property
    def z(self):
        return self.__z

    @z.setter
    def z(self, value):
        self.__z = value
 

Но если вы не проводите какую-либо проверку или изменение значения где-то в коде свойства, вам , вероятно, следует просто избавиться от двойного подчеркивания и разрешить дочернему классу доступ self.z , как он может w , x и y . Самое простое решение-заменить self.__z = z на self.z = z . Вы всегда можете изменить его позже, чтобы использовать property , если обнаружите, что вам действительно нужна проверка или что-то в этом роде.

Если вы просто хотите намекнуть, что z это не является частью более широкого общедоступного API, а только для подклассов и другого кода, который знает об интимных деталях a дизайна, рассмотрите возможность использования одного подчеркивания: self._z = z . Это не имеет особых эффектов в интерпретаторе, но подчеркивание служит своего рода документацией, которая _z является внутренним атрибутом, и вы должны возиться с ней, только если знаете, что делаете.

Ответ №2:

Вы могли бы сделать что-то подобное, если хотите сохранить свой код в чистоте:

 class a:
    def __init__(self, w, x, y, z):
        self.w = w
        self.x = x
        self.y = y
        self.__z = z

    def get_field(self):
        return self.__z
class b(a):
    def __init__(self, w, x, y, z, t):
        super().__init__(w, x, y, z)
        self.__t = t

    def ChildMethodWhichUsingParentField(self):
        return self.get_field()


c = b(1,2,3,4,5)
print(c.ChildMethodWhichUsingParentField())
 

Выход

 4
 

Аналогично, вы можете использовать сеттер для изменения его значения:

 class a:
    def __init__(self, w, x, y, z):
        self.w = w
        self.x = x
        self.y = y
        self.__z = z

    def get_field(self):
        return self.__z
    def set_field(self,z):
        self.__z = z

class b(a):
    def __init__(self, w, x, y, z, t):
        super().__init__(w, x, y, z)
        self.__t = t

    def ChildMethodWhichUsingParentField(self):
        return self.get_field()
    def ChildMethodWhichSettingParentField(self,z):
        self.set_field(z)



c = b(1,2,3,4,5)
print(c.ChildMethodWhichUsingParentField())
c.ChildMethodWhichSettingParentField(10)
print(c.ChildMethodWhichUsingParentField())
 

Выход

 4
10