Klassen/Instanzen

# definiert die Fahrzeug-Klasse
class Fahrzeug:
    name = ""
    art = "Auto"
    farbe = ""
    wert = 100.00

    def beschreibung(self):
        desc_str = f"""'{self.name}' ist ein {self.art}
        hat die Farbe {self.farbe} und hat einen Wert von: {self.wert} €."""
        return desc_str

class BMW(Fahrzeug):
    """Erbt alle Eigenschaften der Klasse Fahrzeug"""
    pass

# die Anwendung...
auto1 = Fahrzeug()
auto1.name = "Rudi"
auto1.farbe ="rot"

print(auto1.beschreibung())
auto2 = BMW()
auto2.name = "Rudi-Ratlos"
auto2.farbe ="blau"
print(auto2.beschreibung())
'Rudi' ist ein Auto
        hat die Farbe rot und hat einen Wert von: 100.0 €.
'Rudi-Ratlos' ist ein Auto
        hat die Farbe blau und hat einen Wert von: 100.0 €.
for var in dir(auto1):
    print(var)
__class__
__delattr__
__dict__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__gt__
__hash__
__init__
__init_subclass__
__le__
__lt__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
art
beschreibung
farbe
name
wert
# nochmal alle Variablen und Methoden ohne die internen Methoden
[var for var in dir(auto2) if not var.startswith('__')]
['art', 'beschreibung', 'farbe', 'name', 'wert']
#auto1.hasattr('wert')
id(auto1)
4563164352
type(auto1)
__main__.Fahrzeug
repr(auto1)
'<__main__.Fahrzeug object at 0x10ffc5cc0>'
print(issubclass(BMW, Fahrzeug))
True
help(auto2)
Help on BMW in module __main__ object:

class BMW(Fahrzeug)
 |  Erbt alle Eigenschaften der Klasse Fahrzeug
 |
 |  Method resolution order:
 |      BMW
 |      Fahrzeug
 |      builtins.object
 |
 |  Methods inherited from Fahrzeug:
 |
 |  beschreibung(self)
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Fahrzeug:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes inherited from Fahrzeug:
 |
 |  art = 'Auto'
 |
 |  farbe = ''
 |
 |  name = ''
 |
 |  wert = 100.0

Ducktyping

Duck-Typing ist ein Konzept der objektorientierten Programmierung, bei dem der Typ eines Objektes nicht durch seine Klasse beschrieben wird, sondern durch das Vorhandensein bestimmter Methoden oder Attribute.

Quelle: Wikipedia

en: “When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.”

de: „Wenn ich einen Vogel sehe, der wie eine Ente läuft, wie eine Ente schwimmt und wie eine Ente schnattert, dann nenne ich diesen Vogel eine Ente.“

class Person:
    def hilfe(self):
        print("Hilfe!")

class Ente:
    def hilfe(self):
        print("Quaaaaaack!")

class Quitscheente:
    def hilfe(self):
        print("Miiip, miip")

class SomethingElse:
    pass

def ImWald(x):
    x.hilfe()

schnatterienchen = Ente()
schneider = Person()
was = SomethingElse()
ding = Quitscheente()
katze = None
alien = "unbekanntes Wesen"

for ding in [schnatterienchen, schneider, was, ding, alien]:
    try:
        ImWald(ding)
    except AttributeError:
        print('Kein Hilferuf?')
Quaaaaaack!
Hilfe!
Kein Hilferuf?
Miiip, miip
Kein Hilferuf?
hasattr(schneider, 'hilfe')
True

Tiefe Einsichten

https://hynek.me/articles/hashes-and-equality/

  • Hashes und Identity

Dies gilt es zu beachten, wenn das Standardverhalten von Klassen neu definiert wird!

class C:
    def __init__(self, x):
        self.x = x
    def __repr__(self):
        return f"C({self.x})"
    def __hash__(self):
        return hash(self.x)
    def __eq__(self, other):
        return (
            self.__class__ == other.__class__ and
            self.x == other.x
        )
d = dict()
s = set()
c = C(1)
d[c] = 42
s.add(c)
print(d, s)
print(c in s and c in d)  # c is in both!
c.x = 2
print(c in s or c in d)   # c is in neither!?
{C(1): 42} {C(1)}
True
False