Daten und Verhalten zusammen
Bisher konnte eine Position ein Tupel oder ein Dictionary sein, mit getrennten Funktionen darauf. Eine Klasse bündelt die Daten und die zugehörigen Funktionen zu einem neuen Typ. class Position: definiert den Bauplan; ihr Aufruf, Position("AAPL", 100, 180.0), erzeugt aus diesem Plan ein Objekt (auch Instanz genannt). Jedes Objekt hält seine eigenen Daten, und die in der Klasse definierten Funktionen, Methoden genannt, arbeiten auf diesem Objekt.
class Position:
def __init__(self, symbol, quantity=0):
self.symbol = symbol # attributes belong to this object
self.quantity = quantity
def describe(self):
return f"{self.quantity} x {self.symbol}"
apple = Position("AAPL", 100)
tesla = Position("TSLA")
print(apple.describe()) # 100 x AAPL
print(tesla.describe()) # 0 x TSLA
print(apple.quantity, tesla.quantity) # 100 0__init__ und self
__init__ ist der Konstruktor: Python führt ihn beim Erzeugen eines Objekts automatisch aus, und er speichert die Startwerte. Jede Methode erhält das Objekt selbst als ersten Parameter, üblicherweise self genannt; Sie übergeben ihn nicht, Python tut es (apple.describe() ruft Position.describe(apple) auf). Alles, was mit self.name = wert gespeichert wird, ist ein Attribut dieses Objekts und bleibt zwischen Methodenaufrufen erhalten. __init__ richtet alles ein und gibt nichts zurück.
class Account:
def __init__(self, cash):
self.cash = cash
def deposit(self, amount):
self.cash += amount # changes this object's attribute
return self.cash
first = Account(1000)
second = Account(50)
first.deposit(500)
print(first.cash, second.cash) # 1500 50 (separate objects, separate data)
same = first # a second name for the same object
same.deposit(1)
print(first.cash) # 1501Methoden, die den Zustand ändern oder Fragen beantworten
Manche Methoden beantworten eine Frage über das Objekt, ohne es zu ändern (market_value(price)); sie sollen nur ein Ergebnis zurückgeben und die Attribute in Ruhe lassen. Andere verändern das Objekt (apply_fill), aktualisieren Attribute und geben oft etwas Nützliches zurück, etwa den realisierten Gewinn. Eine Methode kann mit self.andere_methode(...) eine andere aufrufen, was die Regeln an einer Stelle hält: Braucht unrealized_pnl den Marktwert, fragt sie self.market_value(price), statt die Formel zu wiederholen.
class Position:
def __init__(self, symbol, quantity=0, avg_price=0.0):
self.symbol = symbol
self.quantity = quantity
self.avg_price = avg_price
def market_value(self, price):
return self.quantity * price
def unrealized_pnl(self, price):
return self.market_value(price) - self.quantity * self.avg_price
pos = Position("AAPL", 100, 180.0)
print(pos.market_value(185.0)) # 18500.0
print(pos.unrealized_pnl(185.0)) # 500.0Fallen und wann eine Klasse sinnvoll ist
self. zu vergessen ist der klassische Ausrutscher: quantity = 5 in einer Methode erzeugt eine wegwerfbare lokale Variable, kein Attribut. Verwenden Sie CapWords für Klassennamen (Position) und Kleinbuchstaben mit Unterstrichen für Attribute und Methoden; ein führender Unterstrich (_cache) markiert etwas als intern. Nutzen Sie nie einen veränderlichen Standardwert wie def __init__(self, fills=[]): Alle Objekte würden diese eine Liste teilen; nehmen Sie fills=None und erzeugen Sie [] im Inneren. Legen Sie eine Klasse an, wenn Daten und die Regeln dazu zusammengehören; eine einfache Funktion oder ein Dictionary ist oft einfacher.
class Wrong:
def __init__(self, quantity):
quantity = quantity # forgot self.: nothing is stored
class Shared:
def __init__(self, fills=[]): # one list shared by every object
self.fills = fills
class Right:
def __init__(self, fills=None):
self.fills = [] if fills is None else list(fills)
a, b = Shared(), Shared()
a.fills.append(100)
print(b.fills) # [100] (surprise!)
c, d = Right(), Right()
c.fills.append(100)
print(d.fills) # []
print(hasattr(Wrong(5), "quantity")) # Falseclass Name:definiert einen Typ;Name(args)erzeugt ein Objekt und führt__init__aus.self.attr = wertspeichert Daten im Objekt; jede Methode nimmt zuerstself.- Abfragemethoden geben Antworten zurück; Änderungsmethoden ändern Attribute; vermeiden Sie veränderliche Standardwerte.
Als Nächstes: spezielle Methoden wie __repr__ und __eq__, mit denen Ihre Objekte schön ausgegeben und erwartungsgemäß verglichen werden.
Lab: Was bewertet wird
- Mit
__init__eine Position aufbauen25 Pkt. - Mit
market_valuedie Position bewerten25 Pkt. - Mit
unrealized_pnlden Buchgewinn messen25 Pkt. - Mit
apply_filldie Position nach einem Trade aktualisieren25 Pkt.