2014-10-08 5 views
0

Я довольно новичок в OOP и Python. Почти все, что я знаю, является самоучкой, поэтому я был бы признателен, если бы вы могли предоставить только ссылки для меня, чтобы читать, так как я не знаю точной терминологии, которую я должен искать, чтобы прояснить мои сомнения.Классы, скрытые атрибуты и наследование

Это мой код до сих пор:

class Point(object): 
    x = 2 
    y = 3 

    def __init__(self, x, y): 
     self.x_a = x 
     self.y_b = y 

class RectPoint(Point): 

    def __init__(self, x, y): 
     self.x_1 = x 
     self.y_1 = y 
     self.dist = (x*x + y*y)**0.5 


class CircPoint(Point): 
    pass 

a = Point(3,4) 
b = CircPoint(3,4) 
c = RectPoint(3,4) 

print a.x  # 2 
print a.y  # 3 
print a.x_a # 3 
print a.y_b # 4 
print b.x  # 2 
print b.y  # 3 
print b.x_a # 3 
print b.y_b # 4 
print c.x  # 2 
print c.y  # 3 
print c.x_1 # 3 
print c.y_1 # 4 
print c.dist # 5.0 
print c.x_a # AttributeError 
print c.y_b # AttributeError 

Почему атрибуты self.x_a и self.y_b не доступны для класса RectPoint но доступны для CircPoint? Как я могу сделать их доступными?

Кроме того, почему self.x и self.y доступны для двух классов RectPoint и CircPoint?

Ссылка для дальнейшего чтения также будет оценена (вместо объяснения)

+1

Я дам более опытным пользователям объяснить тщательно; но в нескольких словах: «a» имеет все, что должно быть, очевидно; 'b' - это« CircPoint », который наследует все от« Point »и ничего не добавляет, поэтому он имеет все, что имеет« Point ». С другой стороны, 'c' является' RectPoint', классом, который наследует 'x' и' y' от 'Point', но где вы определяете другой метод' __init__', поэтому это переопределяет метод исходного класса. – Roberto

ответ

4

Ваш RectPoint.__init__маскиPoint.__init__ метод. Поскольку Point.__init__ не выполняется для RectPoint экземпляров, атрибуты self.x_a и self.y_b никогда не устанавливаются. Это потому, что Python сначала ищет экземпляр, затем класс, а затем базовые классы для атрибутов. Здесь методы - это специальные атрибуты. При создании экземпляра класса Python ищет метод __init__ в классе, а затем в базовых классах.

CircPoint не реализует свои собственные __init__ так Point.__init__ найден и используется, и self.x_a и self.y_bявляются множество.

Вы конкретно укажите класс атрибуты для x и y; Python находит их с одинаковым порядком поиска; они не заданы в экземпляре и в конечном итоге затем находятся в базовом классе Point; либо потому, что у вас есть экземпляр Point или подкласс Point, и были обысканы базовые классы этого подкласса.

Вы можете явно вызов переопределенном __init__ метода из RectPoint.__init__:

class RectPoint(Point): 
    def __init__(self, x, y): 
     super(RectPoint, self).__init__(x, y) 
     self.x_1 = x 
     self.y_1 = y 
     self.dist = (x*x + y*y)**0.5 

super() function дает вам доступ к исходной Point.__init__ методы здесь, называя его первым. Затем этот метод устанавливает атрибуты self.x_a и self.y_b, после чего он будет возвращен, а метод RectPoint.__init__ установит больше атрибутов.

Class chapter of the Python tutorial охватывает все это в деталях.

+0

+1 Я бы просто добавил (что я сделал в своем собственном - заброшенном ответе), что, хотя на некоторых языках «RectPoint» неявно называет конструктор «Point», но Python не является одним из этих языков. – chepner

+0

Большое спасибо. У меня есть еще один вопрос, не уверен, что я должен подключить его сюда или сделать его отдельным. Существует ли какое-либо практическое применение для переменных, которые не инициализируются в методе '__init__'? то есть из моего кода атрибуты 'x' и' y'? –

+0

@ M.Klugerford: да, вы можете использовать их как значения по умолчанию или обмениваться информацией между всеми экземплярами. Сравните это с бумагой архитектуры; вы можете сложить базовые классы, класс и экземпляр друг над другом и увидеть данные через слои, но * установка * атрибут в экземпляре скроет атрибут (маску) в классе. Но вы всегда можете установить атрибут * непосредственно * в классе с помощью класса ClassObject.attribute_name = new_value'. –

1

RectPoint экземпляры не имеют x_a и y_b атрибутов, потому что ваш метод RectPoint.__init__ никогда не определяет их, и никогда не называет Point.__init__, который будет.

x и y являются атрибутами класса и доступны для класса, на котором они определены, любых подклассов и экземпляров этих классов (если не переопределены путем установки атрибута в подклассе или экземпляре). self.x ищет x сначала в экземпляре, а затем, если он не найден там, в классе и его родительских классах.

1

При переопределении инициализации в классе Python вам все еще нужно вызвать инициализации метод класса, который вы унаследовали от или эти атрибуты не будут доступны для вашего класса ребенка. Вы делаете это с помощью супер-метода. В RectPoint, чан ваш INIT метод следующим образом:

def __init__(self, *args, **kwargs): 
    self.x_1 = x 
    self.y_1 = y 
    self.dist = (x*x + y*y)**0.5 
    super(RectPoint,self).__init__(*args,**kwargs) 
Смежные вопросы