Python: Como faço uma subclasse de uma superclasse?

86

Em Python, como você faz uma subclasse de uma superclasse?

dave.j.lott
fonte
3
Observe que o Python mudou a maneira como você faz subclasses, portanto, existem 2 maneiras de fazer isso, e elas não se misturam. Você obterá um erro se misturar. Leia esta postagem para ver a diferença: stackoverflow.com/questions/1713038/…
Mark Lakata

Respostas:

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

Ou, melhor ainda, o uso da função integrada do Python super()(consulte a documentação do Python 2 / Python 3 para isso) pode ser um método um pouco melhor de chamar o pai para inicialização:

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

Ou exatamente a mesma coisa acima, exceto usando a forma de argumento zero de super(), que só funciona dentro de uma definição de classe:

class MySubClassBetter(MySuperClass):
    def __init__(self):
        super().__init__()
thompsongunner
fonte
6
OTOH, algumas pessoas alertam contra super, especialmente para novos programadores Python (por exemplo, Lutz). Eu evito isso.
Eric
6
A única razão para evitar superé se você não entende as diferenças entre como superfunciona em Python e como super/ parentfunciona em outras linguagens. Reconheço que isso não é óbvio para pessoas que vêm de outras línguas, mas eu não concluiria que isso o qualifique como algo a "prevenir". Ele faz o trabalho. Simplesmente funciona de forma diferente. Apenas leia sobre o que ele realmente faz em Python antes de reclamar sobre a obtenção de resultados inesperados.
TheAtomicOption de
3
Qual é a diferença entre os dois?
Tiwtiw
65

Um pequeno exemplo heróico:

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()
ewall
fonte
37
class MySubClass(MySuperClass):
    def __init__(self):
        MySuperClass.__init__(self)

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

A seção sobre herança na documentação do python explica em mais detalhes

Bryan Oakley
fonte
5
Você só precisa definir esse __init__método se quiser adicionar mais código a ele, caso contrário, o método init original será usado de qualquer maneira (embora valha a pena mencionar, e é um código perfeitamente válido)
dbr
2
Acho que a pergunta foi vaga o suficiente para assumir que pode haver mais código adicionado. Melhor fornecer muitas informações do que não o suficiente e acabar com outra pergunta quando o OP implementa. :)
Matt Dewey,
15
class Class1(object):
    pass

class Class2(Class1):
    pass

Class2 é uma subclasse de Class1

workmad3
fonte
Legal. Isso é o que eu estava procurando, ou seja, uma subclasse sem extensão / substitui o super.
BuvinJ
9

Nas respostas acima, o superé inicializado sem nenhum argumento (palavra-chave). Freqüentemente, entretanto, você gostaria de fazer isso, bem como transmitir alguns argumentos 'personalizados' de sua preferência. Aqui está um exemplo que ilustra este caso de uso:

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

Esta é uma subclasse da listqual, quando inicializada, imediatamente se classifica na direção especificada pelo reverseargumento de palavra - chave, como os seguintes testes ilustram:

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__])

Graças à transmissão de *argspara super, a lista pode ser inicializada e preenchida com itens em vez de ficar apenas vazia. (Observe que reverseé um argumento apenas de palavra-chave de acordo com PEP 3102 ).

Kurt Peek
fonte
4

Há outra maneira de criar subclasses em python dinamicamente com uma função type():

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

Você geralmente deseja usar este método ao trabalhar com metaclasses. Quando você deseja fazer algumas automações de nível inferior, isso altera a maneira como o python cria classes. Provavelmente, você nunca precisará fazer dessa maneira, mas quando o fizer, já saberá o que está fazendo.

Pol
fonte
3
class Subclass (SuperClass):
      # Subclass stuff here
Wernsey
fonte
3

Você usa:

class DerivedClassName(BaseClassName):

Para obter detalhes, consulte a documentação do Python, seção 9.5 .

Reed Copsey
fonte
2
class Mammal(object): 
#mammal stuff

class Dog(Mammal): 
#doggie stuff
Chris Ballance
fonte
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())
Antiômica
fonte
5
Esta resposta seria mais útil se você incluísse uma explicação do que ele faz
grooveplex
4
Embora este código possa ajudar a resolver o problema, ele não explica por que e / ou como responde à pergunta. Fornecer esse contexto adicional melhoraria significativamente seu valor educacional a longo prazo. Por favor edite sua resposta para adicionar explicação, incluindo o que limitações e premissas se aplicam.
Toby Speight de
2
Embora este snippet de código possa resolver a questão, incluir uma explicação realmente ajuda a melhorar a qualidade de sua postagem. Lembre-se de que você responderá à pergunta para leitores no futuro, e essas pessoas podem não saber os motivos de sua sugestão de código.
andreas de
0

A criação de subclasses em Python é feita da seguinte maneira:

class WindowElement:
    def print(self):
        pass

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

Aqui está um tutorial sobre Python que também contém classes e subclasses.

dmeister
fonte