คลาส Python ทั้งหมดควรขยายออบเจ็กต์หรือไม่


129

ฉันพบว่าทั้งสองงานต่อไปนี้:

class Foo():
    def a(self):
        print "hello"

class Foo(object):
    def a(self):
        print "hello"

คลาส Python ทั้งหมดควรขยายออบเจ็กต์หรือไม่ มีปัญหาที่อาจเกิดขึ้นกับการไม่ขยายวัตถุหรือไม่?


2
มีความแตกต่างระหว่างclass Foo():และclass Foo:หรือไม่? ตามที่ฉันสังเกตทั้งสองทำงานใน Python 3
Wolf

คำถามนี้ตอบได้ดี: stackoverflow.com/questions/4015417/…
nngeek

คำตอบ:


117

ใน Python 2 การไม่สืบทอดจากobjectจะสร้างคลาสแบบเก่าซึ่งทำให้เกิดtypeผลลัพธ์ที่แตกต่างกัน:

>>> class Foo: pass
... 
>>> type(Foo())
<type 'instance'>

เมื่อเทียบกับ

>>> class Bar(object): pass
... 
>>> type(Bar())
<class '__main__.Bar'>

นอกจากนี้กฎสำหรับการสืบทอดหลายรายการยังแตกต่างกันในลักษณะที่ฉันจะไม่พยายามสรุปที่นี่ เอกสารที่ดีทั้งหมดที่ฉันเคยเห็นเกี่ยวกับ MI อธิบายถึงคลาสรูปแบบใหม่

ในที่สุดคลาสแบบเก่าก็หายไปใน Python 3 และการสืบทอดจากobjectกลายเป็นความหมายโดยปริยาย ดังนั้นจึงชอบคลาสสไตล์ใหม่ ๆ อยู่เสมอเว้นแต่คุณจะต้องการความเข้ากันได้กับซอฟต์แวร์รุ่นเก่า


68

ใน Python 3 คลาสจะขยายออกไปobjectโดยปริยายไม่ว่าคุณจะพูดเองหรือไม่ก็ตาม

ในหลาม 2 มีสไตล์เก่าและใหม่สไตล์ชั้นเรียน objectเพื่อส่งสัญญาณระดับเป็นแบบใหม่ที่คุณจะต้องสืบทอดอย่างชัดเจนจาก หากไม่เป็นเช่นนั้นจะใช้การใช้งานแบบเก่า

โดยทั่วไปคุณต้องการคลาสรูปแบบใหม่ สืบทอดobjectอย่างชัดเจน โปรดทราบว่าสิ่งนี้ใช้กับโค้ด Python 3 ที่มีจุดมุ่งหมายเพื่อให้เข้ากันได้กับ Python 2


ใช่ความแตกต่างFree Foo ชี้ว่าหายไปแล้ว BTW: วงเล็บว่างเป็นทางเลือกหรือไม่?
Wolf

4
มีโค้ด python 3 จำนวนมากที่ใช้ foo (object) :. นี่เป็นเพียงอนุสัญญางั้นหรือ?
RFV5s

2
@RFVenter อาจเป็นรหัสที่ควรจะทำงานภายใต้ทั้ง Python 2 และ 3 ซึ่งในกรณีนี้คุณต้องซับคลาสออบเจ็กต์อย่างชัดเจนเพื่อให้คลาสทำงานเหมือนกันใน Python 2 เป็นส่วนใหญ่
blubberdiblub

@blubberdiblub นั่นคือสิ่งที่ฉันสงสัย แต่โครงการของเราทำงานเฉพาะบน python 3.5 Virtualenv ฉันคิดว่าต้องคัดลอกโค้ดมาจากโครงการ python 2
RFV5s

@RFVenter ใช่นั่นอาจเป็นคำอธิบายอื่น และแน่นอนว่าถ้าเป็น Python 3.x ตอนนี้ก็สามารถกำจัดการอ้างอิงวัตถุได้
blubberdiblub

17

ใน python 3 คุณสามารถสร้างคลาสได้สามวิธีและภายในจะเท่ากันทั้งหมด (ดูตัวอย่าง) มันไม่สำคัญว่าคุณจะสร้างชั้นเรียนทั้งหมดในหลาม 3 สืบทอดจากชั้นเรียนพิเศษที่เรียกว่า วัตถุ คลาสอ็อบเจ็กต์ เป็นคลาสพื้นฐานใน python และมีฟังก์ชันการทำงานมากมายเช่น double-underscore method, descriptors, super () method, property () method เป็นต้น

ตัวอย่าง 1.

class MyClass:
 pass

ตัวอย่าง 2.

class MyClass():
 pass

ตัวอย่างที่ 3.

class MyClass(object):
  pass

1
สิ่งนี้ไม่เป็นความจริงอย่างเคร่งครัด ... stackoverflow.com/questions/1238606/…
Philip Adler

ฉันไม่แน่ใจว่าฉันติดตามคุณ และใช่อาจไม่เกี่ยวข้องกับคนส่วนใหญ่จนกว่าจะมีความเกี่ยวข้อง
Philip Adler

@PhilipAdler มันสันนิษฐานทั่วไปว่าทำให้การอ้างอิงถึงในตัวobject objectหากเราต้องพิจารณาว่าตัวระบุในตัวของ CPython สามารถแทนที่ได้เราแทบจะไม่สามารถยืนยันเกี่ยวกับโมเดลข้อมูลได้ สามารถโต้แย้งอย่างจริงจังstrได้หรือไม่ที่ไม่ยอมรับสตริงเป็นอาร์กิวเมนต์เนื่องจากสามารถกำหนดได้builtins.str = None?
Nuno André

ฉันมักจะเห็นคำกล่าวอ้างนี้ว่า "สันนิษฐานอย่างกว้างขวาง" และฉันยอมรับว่ามันเป็นข้อสันนิษฐานที่ทุกการใช้งานในปัจจุบันทำ (ไม่ใช่ข้อกำหนดของภาษา) ฉันไม่เคยได้รับประสบการณ์ของโปรแกรมเมอร์ python ส่วนใหญ่ ได้พบสมมติสิ่งนี้รู้เกี่ยวกับมันหรือได้พิจารณามัน ไม่ว่าจะด้วยวิธีใดการยืนยันว่าโดยทั่วไปจะถือว่าแม้ว่าจะเป็นจริง แต่ก็ไม่ได้ทำให้การยืนยันของฉันเป็นโมฆะว่าความเท่าเทียมนั้นไม่เป็นความจริงอย่างเคร่งครัด
Philip Adler

1

ใช่คลาส Python ทั้งหมดควรขยาย (หรือมากกว่าคลาสย่อยนี่คือ Python ที่นี่) แม้ว่าโดยปกติจะไม่มีปัญหาร้ายแรงเกิดขึ้น แต่ในบางกรณี (เช่นเดียวกับการสืบทอดต้นไม้หลายต้น) สิ่งนี้จะมีความสำคัญ นอกจากนี้ยังช่วยให้สามารถใช้งานร่วมกับ Python 3 ได้ดีขึ้น


1
ในทางเทคนิคถ้าคุณไม่มีคุณจะได้คลาสคลาสสิก แต่ไม่มีข้อดีที่แท้จริงสำหรับสิ่งนี้และ python 3 ไม่รองรับ
max k

ฉันสงสัยว่าทำไมมันถึงปรับปรุงความเข้ากันได้กับ python3 ตามความเข้าใจของฉัน python3 จะทำให้มันขยายวัตถุโดยอัตโนมัติแม้ว่าคุณจะไม่ได้ระบุใช่ไหม
Paul Lo

2
@PaulLo Right แต่ถ้าคุณสืบทอดจากวัตถุอย่างชัดเจนคุณจะได้รับพฤติกรรม (รูปแบบใหม่) เหมือนกันทั้งใน Python 2 และ Python 3 ไม่ใช่เรื่องของการเปลี่ยนแปลงวิธีการทำงานของ Python 3 แต่เป็นเรื่องของการใช้ไปข้างหน้า - ความเข้ากันได้บน Python 2
pydsigner

คำแนะนำนี้ดูไม่ค่อยสวยงามนัก แต่ในกรณีที่คุณพูดถึง Python2 และ Python3 ดูเหมือนว่าจะได้ผล แต่มีความเกี่ยวข้องอย่างไรในทางปฏิบัติ?
Wolf

@ หมาป่ามันขึ้นอยู่กับว่าคุณกำลังทำอะไรอยู่ หากคุณมีโครงสร้างการสืบทอดที่ซับซ้อนมันมีความสำคัญมากทีเดียว หากคุณต้องการให้ชั้นเรียนของคุณเป็นตัวบอกคุณต้องใช้รูปแบบใหม่ ติดตามลิงค์ได้จากstackoverflow.com/questions/54867/…หากต้องการข้อมูลเชิงลึกเพิ่มเติม
pydsigner

1

ตามคำตอบอื่น ๆ การสืบทอด Python 3 จากวัตถุนั้นเป็นนัย แต่พวกเขาไม่ได้ระบุว่าคุณควรทำอะไรและอะไรคือแบบแผน

ตัวอย่างเอกสาร Python 3 ทั้งหมดใช้สไตล์ต่อไปนี้ซึ่งเป็นแบบแผนดังนั้นฉันขอแนะนำให้คุณทำตามนี้สำหรับโค้ดในอนาคตใน Python 3

class Foo:
    pass

ที่มา: https://docs.python.org/3/tutorial/classes.html#class-objects

ตัวอย่างคำพูด:

คลาสอ็อบเจ็กต์สนับสนุนการดำเนินการสองประเภท: การอ้างอิงแอตทริบิวต์และการสร้างอินสแตนซ์

การอ้างอิงแอตทริบิวต์ใช้ไวยากรณ์มาตรฐานที่ใช้สำหรับการอ้างอิงแอตทริบิวต์ทั้งหมดใน Python: obj.name ชื่อแอ็ตทริบิวต์ที่ถูกต้องคือชื่อทั้งหมดที่อยู่ในเนมสเปซของคลาสเมื่อสร้างคลาสอ็อบเจ็กต์ ดังนั้นหากคำจำกัดความของคลาสมีลักษณะดังนี้:

class MyClass:
    """A simple example class"""
    i = 12345

    def f(self):
        return 'hello world'

คำพูดอื่น:

โดยทั่วไปตัวแปรอินสแตนซ์มีไว้สำหรับข้อมูลที่ไม่ซ้ำกันของแต่ละอินสแตนซ์และตัวแปรคลาสใช้สำหรับแอตทริบิวต์และวิธีการที่ใช้ร่วมกันโดยอินสแตนซ์ทั้งหมดของคลาส:

class Dog:

    kind = 'canine'         # class variable shared by all instances

    def __init__(self, name):
        self.name = name    # instance variable unique to each instance

0

ใน python3 ไม่มีความแตกต่าง แต่ใน python2 การไม่ขยายobjectจะให้คลาสแบบเก่าแก่คุณ คุณต้องการใช้คลาสสไตล์ใหม่กับคลาสแบบเก่า


2
คำตอบนี้สมเหตุสมผล แต่ผู้ตอบคนอื่นไปถึงที่นั่นเร็วกว่าและ / หรือมีรายละเอียดที่ดีกว่า คำตอบนี้ไม่ได้เพิ่มมูลค่าใด ๆ ให้กับเพจดังที่กล่าวมา
Mark Amery
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.