2013-09-27 315 views
8

Tôi có mã sau đây.Tại sao lớp con không kế thừa phương thức từ lớp cha trong python trong ví dụ này?

class Foo(object): 
    def __init__(self): 
     self.__baz = 40 
    def foo(self): 
     print self.__baz 

class Bar(Foo): 
    def __init__(self): 
     #super(Bar, self).__init__() 
     self.__baz = 21 
    def bar(self): 
     print self.__baz 

x = Bar() 
x.foo() 
x.bar() 

tôi nhận được lỗi này:

Traceback (most recent call last): 
    File "classes.py", line 15, in <module> 
    x.foo() 
    File "classes.py", line 5, in foo 
    print self.__baz 
AttributeError: 'Bar' object has no attribute '_Foo__baz' 

tại sao là foo phương pháp không được thừa kế trong Bar.

EDIT: Nó hoạt động tốt, nếu bạn gọi siêu được nhận xét.

+3

Không chắc chắn, nhưng không phải vì __variablename là một biến đặc biệt? http://stackoverflow.com/a/1301369/2537322 – meyer9

+0

Rất tò mò, tại sao nó * làm việc * nếu bạn gọi 'super()'? –

+0

Không phải là câu trả lời, nhưng thêm chi tiết hơn - nếu bạn thay đổi từ '__baz' thành' baz' cả hai cuộc gọi in 21. Nếu bạn gọi 'super()' và để nguyên là '__baz', chúng in' 40' và '21' tương ứng. –

Trả lời

7

Thuộc tính gạch dưới đôi có tên bị cắt xén dựa trên không gian tên hiện tại/chứa. Trong hàm foo, không gian tên hiện tại là Foo vì vậy khi python tra cứu self.__baz, nó thực sự sẽ tìm kiếm do lược đồ mangling tên. Vì không có nơi nào trong Foo bạn thực sự đã đặt thuộc tính __baz, lớp không có thuộc tính _Foo__baz (thuộc tính _Bar__baz vì bạn đặt self.__baz theo phương thức trong phạm vi Bar).

Tất nhiên, như bạn đã có thể nhận thấy, nếu bạn gọi Foo.__init__(self) trong Baz.__init__ (trực tiếp hoặc qua super), bạn sẽ thấy vấn đề đi xa vì Foo.__init__ bộ __baz (ví dụ: _Foo__baz).

+0

để phương pháp foo không được kế thừa chính xác? Tôi hơi bối rối về những gì đang xảy ra ở đây ... –

+0

@ user1988876 - phương thức 'foo' * được * kế thừa. Nhưng khi bạn gọi nó, thuộc tính mà nó đang cố gắng truy cập là * mất tích *. Khi python thấy 'self .__ baz' bên trong định nghĩa của lớp' Bar', nó thay đổi nó thành 'self._Bar__baz'. Khi nó thấy 'self .__ baz' bên trong định nghĩa của lớp' Foo', nó thay đổi nó thành 'self._Foo__baz'. Toàn bộ ý tưởng ở đây là để 'self .__ baz' bên trong' Foo' có thể khác biệt với 'self .__ baz' bên trong' Bar'. – mgilson

+0

Vì vậy, thực sự khi anh ta gọi 'siêu (Bar, tự).__init __() 'lớp con của đối tượng Bar có ** hai ** thuộc tính một là' _Bar__baz' (vì anh ta 'tự .__ baz = 21' trong phương thức init lớp con) và khác là' _Foo__baz' từ lớp cha **? * * Trong trường hợp lỗi (nếu anh ta không gọi 'super (Bar, self) .__ init __()') Đối tượng của Bar chỉ có một thuộc tính là '_Bar__baz' **? ** –

3

Khi bạn đặt tên biến với dấu gạch dưới kép như vậy trong python tên thành viên sẽ bị làm mờ. Khai báo __baz cung cấp cho bạn thành viên _Bar__baz.

class Bar(Foo): 
def __init__(self): 
    #super(Bar, self).__init__() 
    self.__baz = 21 
def bar(self): 
    print self._Bar__baz 

x = Bar() 
x.bar() 
>>> 21 
+0

bạn đã thay đổi định nghĩa của hàm 'bar'. Tôi muốn biết lý do tại sao nó hoạt động khi cuộc gọi siêu được thực hiện, như tôi đã thực hiện trong chỉnh sửa –

+0

+ khi bạn thêm một mẹo hữu ích cho tôi, nhưng việc sử dụng '_Bar__baz' một cách rõ ràng là không tệ? * * –