Python:如何从超类创建子类?

96

在 Python 中,如何从一个超类创建一个子类?


4
请注意,Python已更改了子类化的方式,因此有两种方法可以实现,它们不能混合使用。如果混用会出错。阅读此文章以了解区别:https://dev59.com/EXI-5IYBdhLWcg3wta7w - Mark Lakata
13个回答

102
# 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
另一方面,一些人警告称对于新的Python程序员(例如Lutz),应避免使用“super”。我也避免使用它。 - eric
9
避免使用super的唯一原因是如果您不了解在Python中super的工作方式与其他语言中super/parent的工作方式之间的区别。必须承认,对于来自其他语言的人来说,这并不明显,但我不会认为这就足以提醒他们"小心使用"。它确实能够使用,只是有所不同。在抱怨得到意料之外的结果之前,请先阅读一下它在Python中实际做了什么。 - TheAtomicOption
6
这是调用父类函数的两种方法之间的区别。一种是使用"super",另一种是直接调用父类。 - Tiwtiw
这里有一个与__init__参数相同的示例。 - spatialaustin

78

一个英勇的小例子:

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())
    

3
是的...答案是13年前的,呵呵。无论如何,现在已更新 ;) - ewall

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

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

Python文档中关于继承的部分有更详细的解释。


5
如果您想添加其他代码,那么您只需要定义__init__方法,否则将继续使用原始的init方法(尽管值得一提,这是完全有效的代码)。 - dbr
2
我认为这个问题的描述不够明确,可能还需要添加更多的代码。提供过多的信息总比信息不足并在 OP 实现时产生另一个问题要好。 :) - Matt Dewey

16
class Class1(object):
    pass

class Class2(Class1):
    pass

Class2是Class1的子类。


很好。这正是我实际上正在寻找的,即一个没有扩展/覆盖超类的子类。 - BuvinJ

11
在上面的答案中,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创建类的方式时,你会用到它。大多数情况下,你永远不需要以这种方式做,但当你需要时,你已经知道你在做什么。


3
class Subclass (SuperClass):
      # Subclass stuff here

3

您使用的是:

class DerivedClassName(BaseClassName):

具体细节,请参见Python文档第9.5节


2
class Mammal(object): 
#mammal stuff

class Dog(Mammal): 
#doggie stuff

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接