#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