Par position ou par nom
Les arguments peuvent être passés par position (associés aux paramètres dans l'ordre) ou par nom (quantity=200). Les noms rendent un appel lisible quand une fonction a plusieurs entrées du même type, et permettent de passer les arguments dans n'importe quel ordre. Les arguments positionnels doivent venir en premier ; dès que vous utilisez un nom, les suivants doivent être nommés aussi.
def pnl(entry, exit_price, quantity):
return (exit_price - entry) * quantity
print(pnl(184.0, 185.5, 200)) # 300.0
print(pnl(quantity=200, entry=184.0, exit_price=185.5)) # 300.0Les valeurs par défaut rendent les paramètres facultatifs
Écrivez name=value dans la ligne def et l'appelant peut omettre cet argument ; la valeur par défaut est alors utilisée. Les paramètres avec valeur par défaut viennent après ceux qui n'en ont pas. Les valeurs par défaut conviennent aux réglages le plus souvent identiques, comme un taux de frais ou un minimum, et chacune peut toujours être remplacée par son nom.
# Parameters with a default are optional
def fee(notional, rate=0.001, minimum=1.0):
return max(minimum, notional * rate)
print(fee(36850.0)) # 36.85
print(fee(36850.0, rate=0.0005)) # 18.425
print(fee(100.0, minimum=0.5)) # 0.5Un nombre quelconque d'arguments : *args
Un paramètre écrit *prices rassemble tous les arguments positionnels supplémentaires dans un tuple : average(1, 2, 3) et average(1, 2, 3, 4, 5) fonctionnent donc tous les deux. L'inverse existe à l'appel : average(*quotes) déballe une liste en arguments séparés.
# *prices collects the extra arguments into a tuple
def average(*prices):
return sum(prices) / len(prices)
print(average(184.0, 185.0, 186.0)) # 185.0
quotes = [184.0, 185.0]
print(average(*quotes)) # 184.5Des options nommées quelconques : **options
De même, **options rassemble les arguments nommés supplémentaires dans un dictionnaire de noms et de valeurs (les dictionnaires auront bientôt leur propre sujet). C'est adapté aux fonctions qui acceptent des options facultatives, comme les paramètres d'un ordre. sorted(options) donne les noms par ordre alphabétique, ce qui rend la sortie prévisible.
# **options collects extra named arguments into a dictionary
def describe(symbol, **options):
text = symbol
for name in sorted(options):
text += f" {name}={options[name]}"
return text
print(describe("AAPL", tif="day", limit=184.5)) # AAPL limit=184.5 tif=dayLe piège de la valeur par défaut modifiable
Une valeur par défaut est créée une seule fois, à la définition de la fonction, et non à chaque appel. Avec un nombre ou du texte, c'est sans danger. Avec une liste, tous les appels qui utilisent la valeur par défaut partagent et modifient la même liste. Le remède classique : prendre None par défaut et créer une liste neuve dans la fonction.
# A default list is created once and shared by every call
def add_fill(fill, fills=[]):
fills.append(fill)
return fills
print(add_fill(100)) # [100]
print(add_fill(200)) # [100, 200] <- surprise: the same list
# The fix: default to None and build a new list inside
def add_fill_fixed(fill, fills=None):
if fills is None:
fills = []
fills.append(fill)
return fills
print(add_fill_fixed(100)) # [100]
print(add_fill_fixed(200)) # [200]- Utilisez des noms dans les appels qui ont plusieurs entrées du même type.
- Des valeurs par défaut pour les réglages habituellement identiques ; jamais une liste ou un dictionnaire.
*argspour un nombre quelconque de valeurs,**optionspour des extras nommés.
À suivre : la portée et les fermetures, pour voir quels noms une fonction peut voir et comment elle peut mémoriser des valeurs.
Lab : ce qui est noté
- Rendre la quantité et le sens facultatifs avec
position_pnl25 pts - Accepter un nombre quelconque de prix avec
average25 pts - Prendre des options d'ordre nommées avec
describe_order25 pts - Éviter le piège de la liste partagée avec
add_fill25 pts