Python: ¿Cómo hago una subclase de una superclase?

86

En Python, ¿cómo se hace una subclase a partir de una superclase?

dave.j.lott
fuente
3
Tenga en cuenta que Python cambió la forma en que realiza las subclases, por lo que hay 2 formas de hacerlo y no se mezclan. Obtendrá un error si mezcla. Lea esta publicación para ver la diferencia: stackoverflow.com/questions/1713038/…
Mark Lakata

Respuestas:

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

O, mejor aún, el uso de la función incorporada de Python super()(consulte la documentación de Python 2 / Python 3 ) puede ser un método ligeramente mejor para llamar al padre para la inicialización:

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

O, exactamente lo mismo que antes, excepto que usa la forma de argumento cero de super(), que solo funciona dentro de una definición de clase:

class MySubClassBetter(MySuperClass):
    def __init__(self):
        super().__init__()
thompsongunner
fuente
6
OTOH, algunas personas advierten en contra super, especialmente para los nuevos programadores de Python (por ejemplo, Lutz). Yo lo evito.
Eric
6
La única razón para evitarlo superes si no comprende las diferencias entre cómo superfunciona en Python y cómo funciona super/ parenten otros lenguajes. Es cierto que esto no es obvio para las personas que provienen de otros idiomas, pero no concluiría que eso lo califica como algo para "advertir". Se hace el trabajo. Simplemente funciona de manera diferente. Simplemente lea sobre lo que realmente hace en Python antes de quejarse de obtener resultados que no esperaba.
TheAtomicOption
3
¿Cuál es la diferencia entre los dos?
Tiwtiw
65

Un pequeño ejemplo heroico:

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

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

La sección sobre herencia en la documentación de Python lo explica con más detalle

Bryan Oakley
fuente
5
Solo necesita definir ese __init__método si desea agregarle más código, de lo contrario, el método init original se usa de todos modos (aunque vale la pena mencionarlo y es un código perfectamente válido)
dbr
2
Creo que la pregunta fue lo suficientemente vaga como para asumir que podría haber más código agregado. Es mejor proporcionar demasiada información que insuficiente y terminar con otra pregunta cuando el OP lo implemente. :)
Matt Dewey
15
class Class1(object):
    pass

class Class2(Class1):
    pass

Class2 es una subclase de Class1

workmad3
fuente
Frio. Esto es lo que realmente estaba buscando, es decir, una subclase sin extensión / anulaciones para el super.
BuvinJ
9

En las respuestas anteriores, superse inicializa sin ningún argumento (palabra clave). Sin embargo, a menudo le gustaría hacer eso, así como transmitir algunos de sus propios argumentos "personalizados". Aquí hay un ejemplo 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 es una subclase de la listcual, cuando se inicializa, se ordena inmediatamente en la dirección especificada por el reverseargumento de la palabra clave, como lo ilustran las siguientes pruebas:

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

Gracias al paso de *argsa super, la lista se puede inicializar y completar con elementos en lugar de solo estar vacía. (Tenga en cuenta que reversees un argumento de solo palabras clave de acuerdo con PEP 3102 ).

Kurt Peek
fuente
4

Hay otra forma de crear subclases en python dinámicamente con una función type():

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

Por lo general, desea utilizar este método cuando trabaje con metaclases. Cuando desea hacer algunas automatizaciones de nivel inferior, eso altera la forma en que Python crea la clase. Lo más probable es que nunca necesite hacerlo de esta manera, pero cuando lo haga, ya sabrá lo que está haciendo.

Pol
fuente
3
class Subclass (SuperClass):
      # Subclass stuff here
Wernsey
fuente
2
class Mammal(object): 
#mammal stuff

class Dog(Mammal): 
#doggie stuff
Chris Ballance
fuente
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())
Antiomic
fuente
5
Esta respuesta sería más útil si incluyera una explicación de lo que hace
grooveplex
4
Aunque este código puede ayudar a resolver el problema, no explica por qué y / o cómo responde la pregunta. Proporcionar este contexto adicional mejoraría significativamente su valor educativo a largo plazo. Por favor, editar su respuesta para agregar explicación, incluyendo lo que se aplican limitaciones y supuestos.
Toby Speight
2
Si bien este fragmento de código puede resolver la pregunta, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo a la pregunta para los lectores en el futuro, y es posible que esas personas no conozcan los motivos de su sugerencia de código.
andreas
0

La subclasificación en Python se realiza de la siguiente manera:

class WindowElement:
    def print(self):
        pass

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

Aquí hay un tutorial sobre Python que también contiene clases y subclases.

dmeister
fuente