按位置或按名称
实参既可以按位置传入(依次对应形参),也可以按名称传入(quantity=200)。当函数有多个同类型的输入时,使用名称能让调用更易读,也允许以任意顺序传入。位置参数必须放在前面;一旦用了名称,后面的也必须都带名称。
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.0默认值让参数变成可选
在 def 行写 name=value,调用方就可以省略这个实参,此时使用默认值。带默认值的形参要放在没有默认值的形参之后。默认值适合通常保持不变的设置,比如费率或最低收费,仍然可以按名称覆盖其中任何一个。
# 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.5任意数量的参数:*args
写成 *prices 的形参会把所有多余的位置实参收集成一个元组,所以 average(1, 2, 3) 和 average(1, 2, 3, 4, 5) 都能用。调用时则有相反的写法:average(*quotes) 会把列表解包成单独的实参。
# *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.5任意命名选项:**options
同样,**options 会把多余的命名实参收集到一个由名称和值构成的字典里(字典很快会有专门的一节)。它适合接受可选附加项的函数,比如订单设置。sorted(options) 按字母顺序给出名称,使输出可预测。
# **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=day可变默认值的陷阱
默认值只在定义函数时创建一次,而不是每次调用都重新创建。对数字或文本来说这没有问题;但对列表而言,所有使用默认值的调用都会共享并修改同一个列表。标准的解决办法是把默认值设为 None,在函数内部再新建列表。
# 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]让调用与定义保持一致给形参设置默认值会改变简短调用的含义,所以要选那些即使被悄悄套用也不会出问题的值。如果某个值确实必须由调用方决定,就不要给它默认值:这样 Python 会报告缺少实参,而不是自行猜测。
- 有多个同类型输入时,调用时使用名称。
- 默认值用于通常不变的设置;绝不要用列表或字典。
- 任意数量的值用
*args,命名的附加项用**options。
下一节:作用域与闭包,了解函数能看到哪些名字,以及它如何记住值。
实验:评分内容
- 用
position_pnl让数量与方向成为可选参数25 分 - 用
average接收任意数量的价格25 分 - 用
describe_order接收命名的订单选项25 分 - 用
add_fill避开共享列表的陷阱25 分