มีเหตุผลใดสำหรับการประกาศคลาสเพื่อสืบทอดจากobject
?
ฉันเพิ่งพบรหัสบางอย่างที่ทำสิ่งนี้และฉันไม่สามารถหาเหตุผลที่ดีได้
class MyClass(object):
# class code follows...
มีเหตุผลใดสำหรับการประกาศคลาสเพื่อสืบทอดจากobject
?
ฉันเพิ่งพบรหัสบางอย่างที่ทำสิ่งนี้และฉันไม่สามารถหาเหตุผลที่ดีได้
class MyClass(object):
# class code follows...
คำตอบ:
มีเหตุผลใดสำหรับการประกาศคลาสเพื่อสืบทอดจาก
object
?
ในหลาม 3 นอกเหนือจากการทำงานร่วมกันระหว่างงูหลาม 2 และ 3 ไม่มีเหตุผล ในหลาม 2 ด้วยเหตุผลหลายประการ
ใน Python 2.x (จาก 2.2 เป็นต้นไป) มีสองรูปแบบของคลาสขึ้นอยู่กับว่ามีหรือไม่มีobject
คลาสฐาน:
คลาสสไตล์ "คลาสสิค" : ไม่มีobject
คลาสพื้นฐาน:
>>> class ClassicSpam: # no base class
... pass
>>> ClassicSpam.__bases__
()
คลาสสไตล์ "ใหม่" : มีทั้งทางตรงหรือทางอ้อม (เช่นสืบทอดจากประเภทบิวด์อิน ) object
เป็นคลาสพื้นฐาน:
>>> 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'>,)
โดยไม่ต้องสงสัยเมื่อเขียนชั้นเรียนคุณจะเสมอต้องการที่จะไปสำหรับการเรียนแบบใหม่ ประโยชน์ของการทำเช่นนั้นมีมากมายให้ทำรายการบางส่วน
สนับสนุน descriptorsการสนับสนุนสำหรับการอธิบายโดยเฉพาะโครงสร้างต่อไปนี้จะเกิดขึ้นกับ descriptors:
classmethod
: เมธอดที่รับคลาสเป็นอาร์กิวเมนต์โดยนัยแทนอินสแตนซ์staticmethod
: วิธีที่ไม่ได้รับอาร์กิวเมนต์โดยนัย self
เป็นอาร์กิวเมนต์แรกproperty
: สร้างฟังก์ชั่นสำหรับจัดการการรับการตั้งค่าและการลบแอททริบิว__slots__
: บันทึกการใช้หน่วยความจำของคลาสและยังส่งผลให้เข้าถึงแอตทริบิวต์ได้เร็วขึ้น แน่นอนมันไม่กำหนดข้อ จำกัด__new__
วิธีสถิต: ช่วยให้คุณสามารถกำหนดวิธีการใหม่อินสแตนซ์ชั้นที่ถูกสร้างขึ้น
ลำดับการแก้ไขเมธอด (MRO) : ในลำดับใดคลาสฐานของคลาสจะถูกค้นหาเมื่อพยายามแก้ไขวิธีการโทร
ที่เกี่ยวข้องกับการซ่อมบำรุง, การโทรsuper
ยังเห็นsuper()
ว่าถือว่าสุดยอด
หากคุณไม่ได้รับมรดกobject
ให้ลืมสิ่งเหล่านี้ คำอธิบายที่ละเอียดมากขึ้นของสัญลักษณ์แสดงหัวข้อย่อยก่อนหน้าพร้อมกับ perks อื่น ๆ ของการเรียนสไตล์ "ใหม่" สามารถพบได้ที่นี่
ข้อเสียอย่างหนึ่งของคลาสสไตล์ใหม่คือคลาสนั้นต้องการหน่วยความจำมากกว่า แม้ว่าคุณจะสร้างวัตถุคลาสมาก แต่ฉันสงสัยว่ามันจะเป็นปัญหาและมันก็เป็นลบในเชิงบวกในทะเลบวก
ใน Python 3 สิ่งต่างๆจะง่ายขึ้น มีคลาสสไตล์ใหม่เท่านั้น (เรียกอย่างชัดเจนว่าคลาส) ดังนั้นความแตกต่างเพียงอย่างเดียวในการเพิ่มobject
คือต้องการให้คุณพิมพ์อักขระอีก 8 ตัว นี้:
class ClassicSpam:
pass
เทียบเท่าโดยสิ้นเชิง (นอกเหนือจากชื่อ :-) ถึงสิ่งนี้:
class NewSpam(object):
pass
และสิ่งนี้:
class Spam():
pass
ทั้งหมดมีอยู่ในพวกเขาobject
__bases__
>>> [object in cls.__bases__ for cls in {Spam, NewSpam, ClassicSpam}]
[True, True, True]
ใน Python 2: สืบทอดจากเสมอobject
อย่างชัดเจนอย่างชัดเจนรับสิทธิพิเศษ
ใน Python 3:สืบทอดมาจากobject
ถ้าคุณกำลังเขียนโค้ดที่พยายามจะเป็น Python ผู้ไม่เชื่อเรื่องพระเจ้านั่นคือมันต้องทำงานทั้งใน Python 2 และ Python 3 ไม่เช่นนั้นมันจะไม่สร้างความแตกต่างเลยเพราะ Python แทรกมันไว้ให้คุณ เบื้องหลัง.
object
จาก IIRC มีช่วงเวลาที่ยังไม่มีตัวบิวท์อินทั้งหมดที่ย้ายไปยังคลาสสไตล์ใหม่
object
ความประทับใจของฉันคือการที่ทุกคนในตัวชนิดไม่รับมรดกจาก ฉันมี Python 2.2.3 รอบตัวและหลังจากการตรวจสอบอย่างรวดเร็วฉันไม่พบผู้กระทำความผิด แต่ฉันจะป้อนคำตอบในภายหลังเพื่อให้ชัดเจนยิ่งขึ้น จะสนใจถ้าคุณสามารถหาตัวอย่างแม้ว่าความอยากรู้ของฉันป่องๆ
object
อยู่ในฐานของมัน
staticmethod
และclassmethod
ทำงานได้ดีแม้ในชั้นเรียนแบบเก่า property
sorta ใช้สำหรับการอ่านในคลาสแบบเก่ามันไม่สามารถดักการเขียนได้ (ดังนั้นหากคุณกำหนดให้กับชื่ออินสแตนซ์จะได้รับแอตทริบิวต์ของชื่อที่กำหนดซึ่งทำให้คุณสมบัติเป็นเงา) โปรดทราบว่า__slots__
การปรับปรุงความเร็วในการเข้าถึงแอตทริบิวต์นั้นส่วนใหญ่เกี่ยวกับการยกเลิกการสูญเสียที่เกิดขึ้นกับการเข้าถึงแอตทริบิวต์ของคลาสสไตล์ใหม่ดังนั้นจึงไม่ใช่จุดขายของคลาสสไตล์ใหม่ (ประหยัดหน่วยความจำเป็นจุดขาย)
Python 3
class MyClass(object):
= คลาสสไตล์ใหม่class MyClass:
= คลาสสไตล์ใหม่ (สืบทอดโดยปริยายobject
)Python 2
class MyClass(object):
= คลาสสไตล์ใหม่class MyClass:
= คลาสเก่าคำอธิบาย :
เมื่อกำหนดคลาสพื้นฐานใน Python 3.x คุณได้รับอนุญาตให้ดรอปobject
จากนิยาม อย่างไรก็ตามนี่สามารถเปิดประตูให้กับปัญหาที่ติดตามยาก ...
Python แนะนำคลาสแบบใหม่ใน Python 2.2 และตอนนี้คลาสแบบเก่านั้นค่อนข้างเก่า การอภิปรายของชั้นเรียนแบบเก่าจะถูกฝังไว้ในเอกสาร 2.xและไม่มีอยู่ในเอกสาร 3.x
ปัญหาคือไวยากรณ์สำหรับการเรียนแบบเก่าในหลาม 2.x เป็นเช่นเดียวกับรูปแบบทางเลือกสำหรับการเรียนแบบใหม่ในหลาม 3.x Python 2.x ยังคงใช้กันอย่างแพร่หลายมาก (เช่น GAE, Web2Py) และโค้ดใด ๆ (หรือ coder) นำคำจำกัดความสไตล์คลาส 3.x ไปสู่โค้ด 2.x โดยไม่ได้ตั้งใจจะจบลงด้วยวัตถุฐานที่ล้าสมัยอย่างจริงจัง และเนื่องจากชั้นเรียนแบบเก่าไม่ได้อยู่ในเรดาห์ของใครเลยพวกเขาจึงไม่รู้ว่าสิ่งใดกระทบ
ดังนั้นลองสะกดมันให้ไกลและช่วยนักพัฒนา 2.x ให้น้ำตา
__metaclass__ = type
ที่ด้านบนของโมดูล (หลังจากfrom __future__ import absolute_import, division, print_function
บรรทัด :-)); มันเป็นแฮ็คที่ใช้งานร่วมกันได้ใน Py2 ซึ่งจะทำให้คลาสที่กำหนดในภายหลังทั้งหมดในโมดูลรูปแบบใหม่โดยค่าเริ่มต้นและใน Py3 จะถูกละเว้นโดยสิ้นเชิง
ใช่นี่เป็นวัตถุ 'รูปแบบใหม่' มันเป็นคุณสมบัติที่แนะนำใน python2.2
วัตถุรูปแบบใหม่ที่มีรูปแบบที่แตกต่างกันของวัตถุวัตถุคลาสสิกและบางสิ่งบางอย่างจะไม่ทำงานอย่างถูกต้องกับวัตถุแบบเก่าเช่นsuper()
, @property
และอธิบาย ดูบทความนี้สำหรับคำอธิบายที่ดีเกี่ยวกับสไตล์คลาสใหม่
ลิงก์สำหรับคำอธิบายของความแตกต่าง SO: ความแตกต่างระหว่างสไตล์เก่ากับคลาสสไตล์ใหม่ใน Python คืออะไร
object
ใน Python 2 เท่านั้น
ประวัติความเป็นมาจากLearn Python the Hard Way :
การตีความดั้งเดิมของ Python ของชั้นเรียนถูกทำลายในรูปแบบที่ร้ายแรงหลายประการ เมื่อถึงเวลาที่ความผิดนี้ได้รับการยอมรับว่ามันสายเกินไปแล้วและพวกเขาต้องสนับสนุนมัน เพื่อแก้ไขปัญหาพวกเขาต้องการสไตล์ "คลาสใหม่" เพื่อให้ "คลาสเก่า" ทำงานต่อไป แต่คุณสามารถใช้เวอร์ชันที่ถูกต้องมากขึ้น
พวกเขาตัดสินใจว่าพวกเขาจะใช้คำว่า "วัตถุ" ลดระดับให้เป็น "คลาส" ที่คุณสืบทอดมาจากการสร้างชั้นเรียน มันเป็นความสับสน แต่คลาสที่สืบทอดมาจากคลาสที่ชื่อว่า "object" เพื่อสร้างคลาส แต่มันไม่ใช่วัตถุจริงๆเป็นคลาส แต่ไม่ลืมที่จะสืบทอดจาก object
นอกจากนี้เพื่อแจ้งให้คุณทราบว่าความแตกต่างระหว่างคลาสสไตล์ใหม่กับคลาสเก่าคือคลาสสไตล์ใหม่นั้นมักสืบทอดจาก object
คลาสหรือคลาสอื่นที่สืบทอดมาจากobject
:
class NewStyle(object):
pass
ตัวอย่างอื่นคือ:
class AnotherExampleOfNewStyle(NewStyle):
pass
ในขณะที่คลาสพื้นฐานแบบเก่ามีลักษณะดังนี้:
class OldStyle():
pass
และคลาสเด็กแบบเก่าจะมีลักษณะดังนี้:
class OldStyleSubclass(OldStyle):
pass
คุณจะเห็นได้ว่าคลาสพื้นฐานของ Old Style นั้นไม่ได้สืบทอดจากคลาสอื่น ๆ อย่างไรก็ตามคลาสของ Old Style นั้นสามารถสืบทอดจากคลาสอื่นได้ การรับค่าจากวัตถุรับประกันได้ว่าการใช้งานบางอย่างนั้นมีให้ใน Python ทุกคลาส มีการนำสไตล์คลาสใหม่มาใช้ใน Python 2.2
object
นั้นไม่ใช่เรื่องที่น่าสับสน แต่ที่จริงแล้วมันเป็นมาตรฐานที่ค่อนข้างดี Smalltalk มีชื่อคลาสรูObject
ทและมีชื่อเมตาคลาสรูClass
ต ทำไม? เพราะเช่นเดียวDog
กับชั้นเรียนสำหรับสุนัขObject
เป็นชั้นเรียนสำหรับวัตถุและClass
เป็นชั้นเรียนสำหรับชั้นเรียน Java, C #, ObjC, Ruby และภาษา OO ตามคลาสอื่น ๆ ส่วนใหญ่ที่ผู้คนใช้ในปัจจุบันที่มีคลาสรูทใช้รูปแบบของObject
ชื่อไม่ใช่แค่ Python
ใช่มันเป็นประวัติศาสตร์ ก็ไม่มีมันจะสร้างชั้นเรียนแบบเก่า
หากคุณใช้type()
กับวัตถุแบบเก่าคุณจะได้รับ "อินสแตนซ์" บนออบเจ็กต์สไตล์ใหม่คุณจะได้คลาส
type()
กับคลาสแบบเก่าคุณจะได้รับ "classobj" แทนที่จะเป็น "type"
ไวยากรณ์ของคำสั่งการสร้างชั้นเรียน:
class <ClassName>(superclass):
#code follows
ในกรณีที่ไม่มีซูเปอร์คลาสอื่น ๆ ที่คุณต้องการสืบทอดโดยเฉพาะsuperclass
ควรเป็นobject
ซึ่งเป็นรากของคลาสทั้งหมดใน Python
object
ในทางเทคนิคแล้วรูทของคลาส "สไตล์ใหม่" ใน Python แต่วันนี้การเรียนสไตล์ใหม่นั้นดีพอ ๆ กับการเป็นสไตล์การเรียนเท่านั้น
แต่ถ้าคุณไม่ได้ใช้คำอย่างชัดเจนobject
เมื่อสร้างคลาสดังนั้นอย่างที่คนอื่น ๆ พูดถึง Python 3.x ได้รับสืบทอดมาจากobject
ซูเปอร์คลาสโดยปริยาย แต่ฉันคิดว่าชัดเจนดีกว่า implicit (นรก) เสมอ