Lớp Python kế thừa đối tượng


1244

Có bất kỳ lý do cho một khai báo lớp để kế thừa từ object?

Tôi chỉ tìm thấy một số mã làm điều này và tôi không thể tìm thấy một lý do tốt tại sao.

class MyClass(object):
    # class code follows...

2
Điều này tạo ra một lớp phong cách mới .
SLaks

116
Câu trả lời cho câu hỏi này (trong khi đơn giản) là khá khó tìm. Googling những thứ như "lớp cơ sở đối tượng python" hoặc tương tự xuất hiện với các trang và trang hướng dẫn về lập trình hướng đối tượng. Nâng cao bởi vì đây là liên kết đầu tiên đưa tôi đến cụm từ tìm kiếm "đối tượng trăn kiểu cũ so với kiểu mới"
differlysuperiorman

Câu trả lời:


764

Có bất kỳ lý do cho một khai báo lớp để kế thừa từ object?

Trong Python 3, ngoài khả năng tương thích giữa Python 2 và 3, không có lý do . Trong Python 2, nhiều lý do .


Câu chuyện Python 2.x:

Trong Python 2.x (từ 2.2 trở đi) có hai kiểu lớp tùy thuộc vào sự hiện diện hay vắng mặt của objectlớp cơ sở:

  1. Các lớp phong cách "cổ điển" : họ không có objectlớp cơ sở:

    >>> class ClassicSpam:      # no base class
    ...     pass
    >>> ClassicSpam.__bases__
    ()
  2. Các lớp kiểu "mới" : chúng có, trực tiếp hoặc gián tiếp (ví dụ: kế thừa từ một kiểu dựng sẵn ), objectnhư một lớp cơ sở:

    >>> class NewSpam(object):           # directly inherit from object
    ...    pass
    >>> NewSpam.__bases__
    (<type 'object'>,)
    >>> class IntSpam(int):              # indirectly inherit from object...
    ...    pass
    >>> IntSpam.__bases__
    (<type 'int'>,) 
    >>> IntSpam.__bases__[0].__bases__   # ... because int inherits from object  
    (<type 'object'>,)

Không còn nghi ngờ gì nữa, khi viết một lớp học, bạn sẽ luôn muốn tham gia các lớp học theo phong cách mới. Các đặc quyền làm như vậy là rất nhiều, để liệt kê một số trong số họ:

  • Hỗ trợ cho người mô tả . Cụ thể, các cấu trúc sau được thực hiện với các mô tả:

    1. classmethod: Một phương thức nhận lớp dưới dạng một đối số ngầm thay vì thể hiện.
    2. staticmethod: Một phương thức không nhận được đối số ngầm selflà đối số đầu tiên.
    3. thuộc tính với property: Tạo các hàm để quản lý việc nhận, cài đặt và xóa thuộc tính.
    4. __slots__: Lưu các giả định bộ nhớ của một lớp và cũng dẫn đến truy cập thuộc tính nhanh hơn. Tất nhiên, nó không áp đặt các hạn chế .
  • Các __new__phương pháp tĩnh: cho phép bạn tùy chỉnh cách mới trường lớp được tạo ra.

  • Thứ tự phân giải phương thức (MRO) : theo thứ tự các lớp cơ sở của một lớp sẽ được tìm kiếm khi cố gắng giải quyết phương thức nào sẽ gọi.

  • Liên quan đến MRO, supercác cuộc gọi . Cũng thấy, super()coi là siêu.

Nếu bạn không thừa kế từ object, hãy quên những thứ này. Một mô tả đầy đủ hơn về các điểm đạn trước đó cùng với các đặc quyền khác của các lớp phong cách "mới" có thể được tìm thấy ở đây .

Một trong những nhược điểm của các lớp kiểu mới là bản thân lớp này đòi hỏi nhiều bộ nhớ hơn. Tuy nhiên, trừ khi bạn đang tạo ra nhiều đối tượng lớp, tôi nghi ngờ đây sẽ là một vấn đề và đó là một sự tiêu cực chìm trong một biển tích cực.


Câu chuyện Python 3.x:

Trong Python 3, mọi thứ được đơn giản hóa. Chỉ có các lớp kiểu mới tồn tại (được gọi đơn giản là các lớp), do đó, sự khác biệt duy nhất trong việc thêm objectlà yêu cầu bạn nhập thêm 8 ký tự. Điều này:

class ClassicSpam:
    pass

là hoàn toàn tương đương (ngoài tên của họ :-) với điều này:

class NewSpam(object):
     pass

và về điều này:

class Spam():
    pass

Tất cả đều có objecttrong họ __bases__.

>>> [object in cls.__bases__ for cls in {Spam, NewSpam, ClassicSpam}]
[True, True, True]

Vậy bạn nên làm gì?

Trong Python 2: luôn kế thừa từ objectrõ ràng . Nhận các đặc quyền.

Trong Python 3: kế thừa từ objectnếu bạn đang viết mã cố gắng là bất khả tri của Python, nghĩa là, nó cần phải hoạt động cả trong Python 2 và Python 3. Nếu không, nó thực sự không có gì khác biệt vì Python chèn nó cho bạn đằng sau hậu trường.


"tùy thuộc vào sự hiện diện hay vắng mặt của loại tích hợp dưới dạng lớp cơ sở" => thực ra không phải là "sự vắng mặt hay hiện diện của loại dựng sẵn như một lớp cơ sở" mà là từ đó lớp kế thừa - trực tiếp hoặc gián tiếp - từ object. IIRC đã có một thời điểm mà không phải tất cả các kiểu dựng sẵn được chuyển sang các lớp kiểu mới.
bruno Desthuilliers 19/03/18

@brunodesthuilliers Ấn tượng của tôi là tất cả các loại tích hợp đều được thừa hưởng từ object. Tôi có một Python 2.2.3 xung quanh và sau khi kiểm tra nhanh tôi không thể tìm thấy một kẻ phạm tội nhưng, tôi sẽ điều chỉnh lại câu trả lời sau để làm cho nó rõ ràng hơn. Sẽ được quan tâm nếu bạn có thể tìm thấy một ví dụ mặc dù, sự tò mò của tôi được khơi gợi.
Dimitris Fasarakis Hilliard

Thành thật mà nói (cf "IIRC" trong bình luận trước của tôi) Tôi không chắc chắn 101% về điểm này (tất cả các loại dựng sẵn đã được chuyển đổi sang các lớp kiểu mới khi các lớp kiểu mới được giới thiệu) - Tôi có thể chỉ đơn giản sai, hoặc điều này chỉ có thể liên quan đến một số loại lib (nhưng không được xây dựng) tiêu chuẩn. Nhưng tôi nghĩ tốt hơn là nên làm rõ rằng những gì tạo nên một lớp phong cách mới đang có objecttrong các cơ sở của nó.
bruno Desthuilliers 20/03/18

7
quá tệ stackoverflow chỉ làm upvote = upvote + 1 cho những câu trả lời loại này, ước gì tôi có thể làm upvote + = N
PirateApp

1
staticmethodclassmethodlàm việc tốt ngay cả trên các lớp học kiểu cũ. propertysorta hoạt động để đọc trên các lớp kiểu cũ, nó chỉ không thể ghi được ghi (vì vậy nếu bạn gán cho tên, thì thể hiện sẽ có được một thuộc tính của tên đã cho làm mờ thuộc tính). Cũng lưu ý rằng __slots__sự cải thiện về tốc độ truy cập thuộc tính chủ yếu là về việc làm mất đi sự mất mát mà quyền truy cập thuộc tính lớp kiểu mới phải gánh chịu, vì vậy nó không thực sự là một điểm bán của các lớp kiểu mới (mặc dù tiết kiệm bộ nhớ là một điểm bán hàng).
ShadowRanger

540

Con trăn 3

  • class MyClass(object): = Lớp học kiểu mới
  • class MyClass:= Lớp kiểu mới (hoàn toàn kế thừa từ object)

Con trăn 2

  • class MyClass(object): = Lớp học kiểu mới
  • class MyClass:= LỚP PHONG CÁCH

Giải thích :

Khi định nghĩa các lớp cơ sở trong Python 3.x, bạn được phép bỏ objectđịnh nghĩa. Tuy nhiên, điều này có thể mở ra cơ hội cho một vấn đề nghiêm trọng khó theo dõi

Python đã giới thiệu các lớp kiểu mới trở lại trong Python 2.2 và bây giờ các lớp kiểu cũ thực sự khá cũ. Thảo luận về các lớp kiểu cũ được chôn trong các tài liệu 2.x và không tồn tại trong các tài liệu 3.x.

Vấn đề là, cú pháp cho các lớp học kiểu cũ bằng Python 2.x cũng giống như cú pháp thay thế cho các lớp học kiểu mới bằng Python 3.x . Python 2.x vẫn được sử dụng rất rộng rãi (ví dụ GAE, Web2Py) và bất kỳ mã nào (hoặc bộ mã hóa) vô tình đưa các định nghĩa lớp kiểu 3.x vào mã 2.x sẽ kết thúc với một số đối tượng cơ sở lỗi thời nghiêm trọng. Và bởi vì các lớp kiểu cũ không có trên radar của bất kỳ ai, nên có khả năng họ sẽ không biết thứ gì đánh trúng họ.

Vì vậy, chỉ cần đánh vần nó trên con đường dài và tiết kiệm cho một số nhà phát triển 2.x những giọt nước mắt.


13
"Khi xác định các lớp cơ sở trong Python 3.x, bạn được phép bỏ đối tượng khỏi định nghĩa. Tuy nhiên, điều này có thể mở ra một vấn đề nghiêm trọng để theo dõi vấn đề" Bạn đang đề cập đến vấn đề gì?
Aidis

6
@Aidis: Tôi nghĩ rằng họ có nghĩa là mã chạy trên cả Py2 và Py3 sẽ ổn trên Py3, nhưng bị phá vỡ trên Py2 nếu nó phụ thuộc vào các tính năng của lớp kiểu mới. Cá nhân, nếu tôi viết mã như vậy, tôi bỏ qua phần thừa kế rõ ràng và chỉ đặt __metaclass__ = typeở đầu mô-đun (sau from __future__ import absolute_import, division, print_functiondòng :-)); Đây là một hack tương thích trong Py2, làm cho tất cả các lớp được xác định sau đó trong mô-đun theo kiểu mới theo mặc định và trong Py3, nó hoàn toàn bị bỏ qua (chỉ là một biến toàn cục ngẫu nhiên ngồi xung quanh), vì vậy nó vô hại.
ShadowRanger

400

Vâng, đây là một đối tượng 'phong cách mới'. Đó là một tính năng được giới thiệu trong python2.2.

Đối tượng phong cách mới có một mô hình đối tượng khác nhau để đối tượng cổ điển, và một số điều sẽ không hoạt động đúng với các đối tượng theo phong cách cũ, ví dụ, super(), @propertyvà mô tả. Xem bài viết này để có một mô tả tốt về một lớp phong cách mới là gì.

Liên kết SO cho một mô tả về sự khác biệt: Sự khác biệt giữa các kiểu kiểu cũ và các lớp kiểu mới trong Python là gì?


110
+1 này. Lưu ý rằng các lớp kiểu cũ đã biến mất trong Python 3, vì vậy bạn chỉ cần kế thừa từ objectPython 2.

9
Đây không phải là một câu trả lời thực sự. Tôi chỉ đưa ra tài liệu tham khảo cho các bài viết khác. Tôi nghĩ câu trả lời của Yarin nên được chấp nhận là câu trả lời cho câu hỏi này.
alwbtc

2
@alwbtc: Câu trả lời này cũng có cái gì đó mới. Ví dụ, đề cập đến "super ()" đã đưa tôi đến một cái quan trọng khác [ở đây] ( stackoverflow.com/questions/576169/ chất ).
ViFI

34

Lịch sử từ Tìm hiểu Python theo cách khó :

Biểu hiện ban đầu của Python về một lớp học đã bị phá vỡ theo nhiều cách nghiêm trọng. Vào thời điểm lỗi này được nhận ra thì đã quá muộn và họ phải hỗ trợ. Để khắc phục sự cố, họ cần một số kiểu "lớp mới" để "lớp cũ" tiếp tục hoạt động nhưng bạn có thể sử dụng phiên bản mới chính xác hơn.

Họ quyết định rằng họ sẽ sử dụng một từ "đối tượng", hạ cấp, để trở thành "lớp" mà bạn kế thừa để tạo ra một lớp. Thật khó hiểu, nhưng một lớp kế thừa từ lớp có tên là "đối tượng" để tạo ra một lớp nhưng nó không phải là một đối tượng thực sự là một lớp, nhưng đừng quên kế thừa từ đối tượng.

Ngoài ra, chỉ để cho bạn biết sự khác biệt giữa các lớp kiểu mới và các lớp kiểu cũ là gì, đó là các lớp kiểu mới luôn kế thừa từ objectlớp hoặc từ một lớp khác được thừa hưởng từ object:

class NewStyle(object):
    pass

Một ví dụ khác là:

class AnotherExampleOfNewStyle(NewStyle):
    pass

Trong khi một lớp cơ sở kiểu cũ trông như thế này:

class OldStyle():
    pass

Và một lớp trẻ kiểu cũ trông như thế này:

class OldStyleSubclass(OldStyle):
    pass

Bạn có thể thấy rằng một lớp cơ sở Kiểu cũ không kế thừa từ bất kỳ lớp nào khác, tuy nhiên, các lớp Kiểu cũ dĩ nhiên có thể kế thừa từ nhau. Kế thừa từ đối tượng đảm bảo rằng chức năng nhất định có sẵn trong mỗi lớp Python. Các lớp kiểu mới đã được giới thiệu trong Python 2.2


8
Gọi lớp gốc objectkhông phải là điều khó hiểu, và trên thực tế, nó khá chuẩn. Smalltalk có một lớp gốc được đặt tên Objectvà một siêu dữ liệu gốc có tên Class. Tại sao? Bởi vì, cũng giống như Dogmột lớp học cho chó, Objectlà một lớp học cho các đối tượng và Classlà một lớp học cho các lớp học. Java, C #, ObjC, Ruby và hầu hết các ngôn ngữ OO dựa trên lớp khác mà mọi người sử dụng ngày nay có lớp gốc sử dụng một số biến thể Objectnhư tên, không chỉ Python.
abarnert

30

Vâng, đó là lịch sử . Không có nó, nó tạo ra một lớp kiểu cũ.

Nếu bạn sử dụng type()trên một đối tượng kiểu cũ, bạn chỉ cần lấy "thể hiện". Trên một đối tượng kiểu mới, bạn có được lớp của nó.


Ngoài ra, nếu bạn sử dụng type()trên một lớp kiểu cũ, bạn sẽ nhận được "classobj" thay vì "type".
Joel Sjögren

7

Cú pháp của câu lệnh tạo lớp:

class <ClassName>(superclass):
    #code follows

Trong trường hợp không có bất kỳ siêu lớp nào khác mà bạn đặc biệt muốn kế thừa từ đó, superclassthì luôn luôn phải objectlà gốc của tất cả các lớp trong Python.

objectvề mặt kỹ thuật là gốc của các lớp "kiểu mới" trong Python. Nhưng các lớp học theo phong cách mới ngày nay cũng tốt như là phong cách duy nhất của các lớp học.

Nhưng, nếu bạn không sử dụng rõ ràng từ này objectkhi tạo các lớp, thì như những người khác đã đề cập, Python 3.x hoàn toàn kế thừa từ objectsiêu lớp. Nhưng tôi đoán rõ ràng luôn luôn tốt hơn ngầm (địa ngục)

Tài liệu tham khảo

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.