ฉันจะเริ่มต้นคลาสพื้นฐาน (ขั้นสูง) ได้อย่างไร


126

ใน Python ให้พิจารณาว่าฉันมีรหัสต่อไปนี้:

>>> class SuperClass(object):
    def __init__(self, x):
        self.x = x

>>> class SubClass(SuperClass):
    def __init__(self, y):
        self.y = y
        # how do I initialize the SuperClass __init__ here?

ฉันจะเริ่มต้นSuperClass __init__ในคลาสย่อยได้อย่างไร ฉันกำลังทำตามบทช่วยสอน Python และไม่ครอบคลุมถึงเรื่องนั้น เมื่อฉันค้นหาใน Google ฉันพบว่ามีวิธีทำมากกว่าหนึ่งวิธี วิธีมาตรฐานในการจัดการสิ่งนี้คืออะไร?

คำตอบ:


147

Python (จนถึงเวอร์ชัน 3) รองรับคลาส "แบบเก่า" และสไตล์ใหม่ คลาสรูปแบบใหม่มาจากobjectและเป็นสิ่งที่คุณกำลังใช้และเรียกใช้คลาสพื้นฐานผ่านsuper()เช่น

class X(object):
  def __init__(self, x):
    pass

  def doit(self, bar):
    pass

class Y(X):
  def __init__(self):
    super(Y, self).__init__(123)

  def doit(self, foo):
    return super(Y, self).doit(foo)

เนื่องจาก python รู้เกี่ยวกับคลาสแบบเก่าและแบบใหม่มีหลายวิธีในการเรียกใช้เมธอดพื้นฐานซึ่งเป็นสาเหตุที่คุณพบหลายวิธีในการทำเช่นนั้น

เพื่อความสมบูรณ์คลาสแบบเก่าเรียกเมธอดพื้นฐานโดยใช้คลาสฐานอย่างชัดเจนเช่น

def doit(self, foo):
  return X.doit(self, foo)

แต่เนื่องจากคุณไม่ควรใช้แบบเก่าอีกต่อไปฉันจะไม่สนใจเรื่องนี้มากเกินไป

Python 3 รู้เกี่ยวกับคลาสรูปแบบใหม่เท่านั้น (ไม่ว่าคุณจะได้มาจากobjectหรือไม่ก็ตาม)


38

ทั้งสอง

SuperClass.__init__(self, x)

หรือ

super(SubClass,self).__init__( x )

จะใช้งานได้ (ฉันชอบอันที่ 2 มากกว่าเพราะมันเป็นไปตามหลักการ DRY มากกว่า)

ดูที่นี่: http://docs.python.org/reference/datamodel.html#basic-customization


8
ไม่ถูกต้อง. super ใช้งานได้กับคลาสสไตล์ใหม่เท่านั้นและเป็นวิธีเดียวที่เหมาะสมในการเรียกฐานเมื่อใช้คลาสรูปแบบใหม่ นอกจากนี้คุณยังต้องส่ง 'ตัวเอง' อย่างชัดเจนโดยใช้โครงสร้างแบบเก่า
Ivo van der Wijk

1
@Ivo - OP ให้คลาสสไตล์ใหม่ในตัวอย่างและมีประเด็นเพียงเล็กน้อยในการพูดถึงความแตกต่างระหว่างสไตล์ใหม่กับสไตล์เก่าเนื่องจากไม่มีใครควรใช้แบบเก่าอีกต่อไป การเชื่อมโยงผมให้ (เพื่อเอกสารหลาม) ชี้ให้เห็นว่ามีมากกว่าหนึ่งวิธีที่ "เหมาะสม" __init__ที่จะเรียกซุปเปอร์คลาส
adamk


21

ฉันจะเริ่มต้นคลาสพื้นฐาน (ขั้นสูง) ได้อย่างไร

class SuperClass(object):
    def __init__(self, x):
        self.x = x

class SubClass(SuperClass):
    def __init__(self, y):
        self.y = y

ใช้superวัตถุเพื่อให้แน่ใจว่าคุณได้รับวิธีการถัดไป (เป็นวิธีการที่ถูกผูกไว้) ในลำดับการแก้ปัญหาวิธีการ ใน Python 2 คุณต้องส่งชื่อคลาสและselfไปที่ super เพื่อค้นหา__init__วิธีการที่ถูกผูกไว้:

 class SubClass(SuperClass):
      def __init__(self, y):
          super(SubClass, self).__init__('x')
          self.y = y

ใน Python 3 มีเวทมนตร์เล็กน้อยที่ทำให้อาร์กิวเมนต์superไม่จำเป็น - และข้อดีอีกอย่างคือมันทำงานได้เร็วขึ้นเล็กน้อย:

 class SubClass(SuperClass):
      def __init__(self, y):
          super().__init__('x')
          self.y = y

การเข้ารหัสผู้ปกครองแบบฮาร์ดโค้ดด้านล่างนี้จะป้องกันไม่ให้คุณใช้การสืบทอดร่วมกัน:

 class SubClass(SuperClass):
      def __init__(self, y):
          SuperClass.__init__(self, 'x') # don't do this
          self.y = y

โปรดทราบว่า__init__อาจกลับมาเท่านั้นNone - มีวัตถุประสงค์เพื่อแก้ไขวัตถุในสถานที่

บางสิ่งบางอย่าง __new__

มีอีกวิธีหนึ่งในการเริ่มต้นอินสแตนซ์ - และเป็นวิธีเดียวสำหรับคลาสย่อยของประเภทที่ไม่เปลี่ยนรูปใน Python ดังนั้นจึงจำเป็นหากคุณต้องการคลาสย่อยstrหรือtupleหรือวัตถุอื่นที่ไม่เปลี่ยนรูป

คุณอาจคิดว่ามันเป็นวิธีการคลาสเพราะได้รับอาร์กิวเมนต์คลาสโดยปริยาย แต่จริงๆแล้วมันเป็นวิธีคงที่ ดังนั้นคุณต้องโทร__new__ด้วยclsอย่างชัดเจน

โดยปกติเราจะส่งคืนอินสแตนซ์จาก__new__ดังนั้นหากคุณเป็นเช่นนั้นคุณต้องเรียกฐานของคุณ__new__ผ่านด้วยsuperเช่นกันในคลาสพื้นฐานของคุณ ดังนั้นหากคุณใช้ทั้งสองวิธี:

class SuperClass(object):
    def __new__(cls, x):
        return super(SuperClass, cls).__new__(cls)
    def __init__(self, x):
        self.x = x

class SubClass(object):
    def __new__(cls, y):
        return super(SubClass, cls).__new__(cls)

    def __init__(self, y):
        self.y = y
        super(SubClass, self).__init__('x')

Python 3 หลีกเลี่ยงความแปลกเล็กน้อยของการโทรขั้นสูงที่เกิดจาก__new__การเป็นวิธีการคงที่ แต่คุณยังต้องส่งclsต่อไปยังวิธีที่ไม่ถูกผูกไว้__new__:

class SuperClass(object):
    def __new__(cls, x):
        return super().__new__(cls)
    def __init__(self, x):
        self.x = x

class SubClass(object):
    def __new__(cls, y):
        return super().__new__(cls)
    def __init__(self, y):
        self.y = y
        super().__init__('x')
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.