Primero ejecuté el siguiente código, que salió muy bien:
class Monster: def __init__(self): self._can_do = [] print("created a monster") super().__init__() class Race(Monster): """ all races must derive from this """ def __init__(self): super().__init__() print("created a race x") class Human(Race): def __init__(self): super().__init__() self._can_do.append("Do nothing special !") print("created a human") class Elf(Race): def __init__(self): super().__init__() self._can_do.append("Avoid sleep") print("created an elf") class Class: """ all classes must derive from this """ def __init__(self): super().__init__() print("created a class x") class Fighter(Class): def __init__(self): super().__init__() self._can_do.append("Hit hard") print("created a fighter") class Wizard(Class): def __init__(self): super().__init__() self._can_do.append("Cast spells") print("created a wizard") class Hero(Human, Fighter): def __init__(self): x = super() print(f"super = {x}") super().__init__() def speak(self): for action in self._can_do: print(f"I can {action} !") print("creating hero 1 :") hero1 = Hero() print("hero 1 human fighter says :") hero1.speak()
El resultado fue:
creating hero 1 : created a monster created a class x created a fighter created a race x created a human hero 1 human fighter says : I can Hit hard ! I can Do nothing special ! !
Luego tuve otra oportunidad, cambiando ligeramente el código, como se muestra a continuación, porque es donde quiero ir:
(hizo la clase de héroe heredando dinámicamente en lugar de estáticamente)
import typing class Monster: def __init__(self): self._can_do = [] print("created a monster") super().__init__() class Race(Monster): """ all races must derive from this """ def __init__(self): super().__init__() print("created a race x") class Human(Race): def __init__(self): super().__init__() self._can_do.append("Do nothing special !") print("created a human") class Elf(Race): def __init__(self): super().__init__() self._can_do.append("Avoid sleep") print("created an elf") class Class: """ all classes must derive from this """ def __init__(self): super().__init__() print("created a class x") class Fighter(Class): def __init__(self): super().__init__() self._can_do.append("Hit hard") print("created a fighter") class Wizard(Class): def __init__(self): super().__init__() self._can_do.append("Cast spells") print("created a wizard") RaceT = typing.TypeVar('RaceT', bound=Race) ClassT = typing.TypeVar('ClassT', bound=Class) class Hero(typing.Generic[RaceT, ClassT]): def __init__(self): super().__init__() def speak(self): for action in self._can_do: print(f"I can {action} !") print("creating hero 1 :") hero1 = Hero[Human,Fighter]() print("hero 1 human fighter says :") hero1.speak()
Esta vez, todo salió mal:
creating hero 1 : hero 1 human fighter says : Traceback (most recent call last): File "./test2.py", line 61, in hero1.speak() File "./test2.py", line 54, in speak for action in self._can_do: AttributeError: 'Hero' object has no attribute '_can_do'
Parece que la creación de una clase genérica hace que el super no pueda encontrar el inicializador de la clase padre, ¿no?
Me he perdido algo ?
Eso no es lo que significa la tipificación genérica. Cuando usted declara
class Hero(typing.Generic[RaceT, ClassT]): ...
entonces eso significa que Hero
toma dos parámetros de tipo. No significa que Hero[Human, Fighter]
sea una subclase de Human
o Fighter
, más que List[int]
es una subclase de int
. La escritura genérica no es una manera de ajustar dinámicamente las superclases de una clase.
Aquí hay una solución de metaclase que le permite generar dinámicamente clases a partir de una Race, Class
par de Race, Class
class Hero(type): instances = {} # All Elf Wizards should have the same class, for example @classmethod def class_factory(metacls, race, class_): if not (issubclass(race, Race) and issubclass(class_, Class)): raise ValueError("Needs race and class, got {} and {}".format(race, class_)) name = "{0.__name__}{1.__name__}".format(race, class_) if name in metacls.instances: return metacls.instances[name] cls = metacls(name, (race, class_), {}) metacls.instances[name] = cls return cls ElfWizard = Hero.class_factory(Elf, Wizard) assert ElfWizard is Hero.class_factory(Elf, Wizard) tim = ElfWizard()
huellas dactilares
created a monster created a class x created a wizard created a race x created an elf