Advanced Classes
Advanced Class Topics¶
- Python’s Class Development Toolkit | YouTube.com Raymond Hettinger
Super Function¶
The super function is required when more than one class in a hierarchy has an __init__()
method. Below Wizard
inherits from Player
and they both have an __init__()
method. To make this work we need to call super().__init__()
in the child class’s __init__()
, and we should usually do that first. The super call will have the same signature as the __init__()
of the parent class. See below.
- Super Considered Super! | YouTube.com Raymond Hettinger
class Player:
def __init__(self, name, level):
self.Name = name
self.Class = "Villager"
self.Level = min(max(1, level), 20) # Min: 1, Max: 20
self.Health = self.Level * 8
def __str__(self):
_fields = (f"{k}: {v}" for k, v in self.__dict__.items())
return '\n '.join(_fields) + '\n'
class Wizard(Player):
def __init__(self, name, level, school):
super().__init__(name, level)
self.Class = f"Wizard of {school}"
self.Mana = self.Level * 10
print(Player("George", 1))
print(Wizard("Jim Darkmagic", level=10, school="Illusion"))
Meta Classes¶
- Meta Programming | YouTube.com David Beazley
If a class is an object factory, then a meta class is a class factory. Meta Classes are often considered black magic, please use them with caution. Meta classes should never be your first impulse as a solution to solve any given puzzle. Often a simple decorator will be faster, easier and less surprising.
Custom meta classes typically inherit from type
and redefine the __new__()
method. A meta class is like a class decorator in capability but the meta class allows modifications to take place before the instances are created. Decorators do their magic strictly after the fact. While a decorator can affects any decorated class individually, a meta class at the top level will affect an entire class hierarchy.
class Foo(type):
def __new__(cls, name, bases, clsdict):
print(f"A New {cls.__qualname__} named {name}!")
return super().__new__(cls, name, bases, clsdict)
class Bar(metaclass=Foo):
""" If Foo must be declared as a metaclass `metaclass=Foo`.
This will not work the same if we just inherit from Foo. """
pass
class Baz(Bar):
""" Now we can inherit from Bar and get the same behavior. """
pass
b = Bar()
z = Baz()
Structure Example¶
from inspect import Parameter, Signature
class StructMeta(type):
def __new__(cls, clsname, bases, clsdict):
clsobj = super().__new__(cls, clsname, bases, clsdict)
sig = cls.make_signature(clsobj._fields)
setattr(clsobj, '__signature__', sig)
return clsobj
@staticmethod
def make_signature(names):
return Signature(
Parameter(name, Parameter.POSITIONAL_OR_KEYWORD)
for name in names)
class Structure(metaclass=StructMeta):
_fields = []
def __init__(self, *args, **kwargs):
bound = self.__signature__.bind(*args, **kwargs)
for name, val in bound.arguments.items():
setattr(self, name, val)
def __str__(self):
out = (f"{name}: {val}" for name, val in self.__dict__.items())
return '\n'.join(out)
class Struct(Structure):
_fields = ['name']
s = Struct("Baz")
print(s)
Dataclasses¶
The dataclass is a class decorator for quickly defining a common type of class without all the boilerplate.
- Dataclasses | YouTube.com Raymond Hettinger
from dataclasses import dataclass
@dataclass
class Color:
hue: int
saturation: float
lightness: float = 0.5
blue = Color(hue=240, saturation=0.75, lightness=0.75)
print(blue)
print(blue.hue)
print(blue.saturation)
print(blue.lightness)
light_blue = Color(hue=240, saturation=0.75, lightness=0.25)
print(light_blue == blue)
blue2 = Color(hue=240, saturation=0.75, lightness=0.75)
print(blue == blue2)