Python: ฉันจะสร้างคลาสย่อยจากซูเปอร์คลาสได้อย่างไร


86

ใน Python คุณสร้างคลาสย่อยจากซูเปอร์คลาสได้อย่างไร?


3
โปรดทราบว่า Python เปลี่ยนวิธีการทำคลาสย่อยดังนั้นจึงมี 2 วิธีในการทำและไม่ผสมกัน คุณจะได้รับข้อผิดพลาดหากคุณผสม อ่านโพสต์นี้เพื่อดูความแตกต่าง: stackoverflow.com/questions/1713038/…
Mark Lakata

คำตอบ:


90
# Initialize using Parent
#
class MySubClass(MySuperClass):
    def __init__(self):
        MySuperClass.__init__(self)

หรือที่ดีกว่านั้นคือการใช้ฟังก์ชันในตัวของ Python super()(ดูเอกสารประกอบPython 2 / Python 3 ) อาจเป็นวิธีที่ดีกว่าเล็กน้อยในการเรียกพาเรนต์สำหรับการเริ่มต้น:

# Better initialize using Parent (less redundant).
#
class MySubClassBetter(MySuperClass):
    def __init__(self):
        super(MySubClassBetter, self).__init__()

หรือสิ่งที่แน่นอนเช่นเดียวกับด้านบนยกเว้นการใช้รูปแบบอาร์กิวเมนต์เป็นศูนย์super()ซึ่งใช้ได้เฉพาะในนิยามคลาส

class MySubClassBetter(MySuperClass):
    def __init__(self):
        super().__init__()

6
OTOH บางคนเตือนsuperโดยเฉพาะอย่างยิ่งสำหรับโปรแกรมเมอร์ Python ใหม่ (เช่น Lutz) ฉันหลีกเลี่ยงมัน
eric

7
เหตุผลเดียวที่ควรหลีกเลี่ยงsuperคือหากคุณไม่เข้าใจความแตกต่างระหว่างวิธีการsuperทำงานใน Python และวิธีการsuper/ parentทำงานในภาษาอื่น เป็นที่ยอมรับว่าสิ่งนี้ไม่ชัดเจนสำหรับผู้ที่มาจากภาษาอื่น แต่ฉันจะไม่สรุปว่าสิ่งนี้ถือว่าเป็นสิ่งที่ "ควรระวัง" มันไม่ทำงาน มันทำงานแตกต่างกัน เพียงอ่านเกี่ยวกับสิ่งที่มันทำใน Python ก่อนที่คุณจะบ่นเกี่ยวกับผลลัพธ์ที่คุณไม่คาดคิด
TheAtomicOption


65

ตัวอย่างเล็ก ๆ น้อย ๆ ที่กล้าหาญ:

class SuperHero(object): #superclass, inherits from default object
    def getName(self):
        raise NotImplementedError #you want to override this on the child classes

class SuperMan(SuperHero): #subclass, inherits from SuperHero
    def getName(self):
        return "Clark Kent"

class SuperManII(SuperHero): #another subclass
    def getName(self):
       return "Clark Kent, Jr."

if __name__ == "__main__":
    sm = SuperMan()
    print sm.getName()
    sm2 = SuperManII()
    print sm2.getName()

37
class MySubClass(MySuperClass):
    def __init__(self):
        MySuperClass.__init__(self)

        # <the rest of your custom initialization code goes here>

ส่วนที่เกี่ยวกับการรับมรดกในเอกสารหลามอธิบายในรายละเอียดมากขึ้น


5
คุณจะต้องกำหนด__init__วิธีการนั้นหากต้องการเพิ่มรหัสเพิ่มเติมมิฉะนั้นจะใช้วิธีการเริ่มต้นเดิมต่อไป (แม้ว่าจะคุ้มค่าที่จะกล่าวถึงและเป็นรหัสที่ถูกต้องอย่างสมบูรณ์)
dbr

2
ฉันคิดว่าคำถามนั้นคลุมเครือพอที่จะสันนิษฐานได้ว่าอาจมีการเพิ่มรหัสเพิ่มเติม ดีกว่าที่จะให้ข้อมูลมากเกินไปไม่เพียงพอและจบลงด้วยคำถามอื่นเมื่อ OP ดำเนินการ :)
Matt Dewey

15
class Class1(object):
    pass

class Class2(Class1):
    pass

Class2 เป็นคลาสย่อยของ Class1


เย็น. นี่คือสิ่งที่ฉันกำลังมองหาอยู่นั่นคือคลาสย่อยที่ไม่มีส่วนขยาย / แทนที่ไปยังซุปเปอร์
BuvinJ

10

ในคำตอบข้างต้นคำตอบsuperจะเริ่มต้นโดยไม่มีอาร์กิวเมนต์ (คีย์เวิร์ด) อย่างไรก็ตามบ่อยครั้งที่คุณต้องการทำเช่นนั้นรวมทั้งส่งต่อข้อโต้แย้งที่ "กำหนดเอง" ของคุณเอง นี่คือตัวอย่างที่แสดงกรณีการใช้งานนี้:

class SortedList(list):
    def __init__(self, *args, reverse=False, **kwargs):
        super().__init__(*args, **kwargs)       # Initialize the super class
        self.reverse = reverse
        self.sort(reverse=self.reverse)         # Do additional things with the custom keyword arguments

นี่คือคลาสย่อยlistที่เมื่อเริ่มต้นจะเรียงลำดับตัวเองทันทีตามทิศทางที่ระบุโดยreverseอาร์กิวเมนต์คำสำคัญดังที่แสดงการทดสอบต่อไปนี้:

import pytest

def test_1():
    assert SortedList([5, 2, 3]) == [2, 3, 5]

def test_2():
    SortedList([5, 2, 3], reverse=True) == [5, 3, 2]

def test_3():
    with pytest.raises(TypeError):
        sorted_list = SortedList([5, 2, 3], True)   # This doesn't work because 'reverse' must be passed as a keyword argument

if __name__ == "__main__":
    pytest.main([__file__])

ด้วยการส่งต่อ*argsไปsuperยังรายการสามารถเริ่มต้นและเติมข้อมูลด้วยรายการแทนที่จะว่างเปล่า (โปรดทราบว่าreverseเป็นอาร์กิวเมนต์คำหลักเท่านั้นตามPEP 3102 )


4

มีอีกวิธีหนึ่งในการสร้างคลาสย่อยใน python แบบไดนามิกด้วยฟังก์ชันtype():

SubClass = type('SubClass', (BaseClass,), {'set_x': set_x})  # Methods can be set, including __init__()

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





1
class BankAccount:

  def __init__(self, balance=0):
    self.balance = int(balance)

  def checkBalance(self): ## Checking opening balance....
    return self.balance

  def deposit(self, deposit_amount=1000): ## takes in cash deposit amount and updates the balance accordingly.
    self.deposit_amount = deposit_amount
    self.balance += deposit_amount
    return self.balance

  def withdraw(self, withdraw_amount=500): ## takes in cash withdrawal amount and updates the balance accordingly
    if self.balance < withdraw_amount: ## if amount is greater than balance return `"invalid transaction"`
        return 'invalid transaction'
    else:
      self.balance -= withdraw_amount
      return self.balance


class MinimumBalanceAccount(BankAccount): #subclass MinimumBalanceAccount of the BankAccount class

    def __init__(self,balance=0, minimum_balance=500):
        BankAccount.__init__(self, balance=0)
        self.minimum_balance = minimum_balance
        self.balance = balance - minimum_balance
        #print "Subclass MinimumBalanceAccount of the BankAccount class created!"

    def MinimumBalance(self):
        return self.minimum_balance

c = BankAccount()
print(c.deposit(50))
print(c.withdraw(10))

b = MinimumBalanceAccount(100, 50)
print(b.deposit(50))
print(b.withdraw(10))
print(b.MinimumBalance())

5
คำตอบนี้จะมีประโยชน์มากขึ้นหากคุณรวมคำอธิบายว่ามันทำอะไร
grooveplex

4
แม้ว่ารหัสนี้อาจช่วยในการแก้ปัญหาก็ไม่ได้อธิบายว่าทำไมและ / หรือวิธีการที่มันสามารถตอบคำถามได้ การให้บริบทเพิ่มเติมนี้จะช่วยเพิ่มคุณค่าทางการศึกษาในระยะยาวได้อย่างมีนัยสำคัญ โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายรวมถึงข้อ จำกัด และสมมติฐานที่ใช้
Toby Speight

2
แม้ว่าข้อมูลโค้ดนี้จะช่วยแก้ปัญหาได้ แต่การมีคำอธิบายจะช่วยปรับปรุงคุณภาพของโพสต์ของคุณได้มาก โปรดจำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและบุคคลเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำโค้ดของคุณ
andreas

0

Subclassing ใน Python ทำได้ดังนี้:

class WindowElement:
    def print(self):
        pass

class Button(WindowElement):
    def print(self):
        pass

นี่คือบทช่วยสอนเกี่ยวกับ Python ที่มีคลาสและคลาสย่อยด้วย

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