def 关键字用于定义函数。 它后面依次是函数名、参数列表, 以及一个用于开始函数体的冒号:
# a_function.py
def a_function(response):
val = 0
if response == "yes":
print("affirmative")
val = 1
print("continuing...")
return val
print(a_function("no"))
#: continuing...
#: 0
print(a_function("yes"))
#: affirmative
#: continuing...
#: 1
这里的函数 signature 只指定了函数名和参数名, 没有指定参数类型或返回类型 (静态类型会介绍这些内容)。 Python 是动态类型语言, 所以类型错误会在运行时而不是编译时暴露出来。 因此,同一个函数可以接受和返回不同类型:
# flexible_args_and_returns.py
def flexible_args_and_returns(arg):
if arg == 1:
return "Hello"
if arg == "one":
return 2
print(flexible_args_and_returns(1))
#: Hello
print(flexible_args_and_returns("one"))
#: 2
print(flexible_args_and_returns(2))
#: None
每一个 Python 函数都会返回一个值。 第三次调用没有匹配任何测试条件, 因此函数执行到结尾而没有返回任何东西,最终产生 None。 裸写 return 和完全没有 return 都会产生 None。
一个带多个表达式的 return 会产生 tuple, 调用方通常会把它解包:
def minmax(values):
return min(values), max(values)
low, high = minmax([3, 1, 4])
这些逗号构造了 tuple。 函数本身仍然只返回一个对象。
这里,同一个函数把 + 运算符同时应用于整数和字符串:
# add.py
def add(arg1, arg2):
return arg1 + arg2
print(add(42, 47))
#: 89
print(add("spam ", "eggs"))
#: spam eggs
try:
add(42, "spam")
except TypeError as e:
print(e)
#: unsupported operand type(s) for +: 'int' and 'str'
只要函数能够把自己的操作应用到某个参数上,这个参数就可以工作。 失败发生在调用内部执行 + 的地方,而不是函数调用动作本身。 参数进入函数时,没有任何东西会预先检查它们。
参数可以具有默认值, keyword argument 允许调用者按名称、以任意顺序传入它们, 从而让函数调用具有自解释性:
# default_args.py
def connect(host, port=5432, timeout=30):
return f"{host}:{port} (timeout{timeout}s)"
print(connect("db.example.com")) # Uses both defaults
#: db.example.com:5432 (timeout 30s)
# Skip to a keyword
print(connect("db.example.com", timeout=5))
#: db.example.com:5432 (timeout 5s)
# Any order by name
print(connect(port=80, host="web.example.com"))
#: web.example.com:80 (timeout 30s)
按名称传参并不要求这个参数必须有默认值:host 没有默认值, 但最后一次调用仍然按名称传入了它。 在调用位置,所有 keyword argument 都必须位于 positional argument 之后。 connect(port=80, "web.example.com") 是 SyntaxError: positional argument follows keyword argument。
带默认值的参数不能位于没有默认值的参数之前。 def f(a=1, b): 是 SyntaxError: parameter without a default follows parameter with a default。 keyword-only 参数 不受这一限制,因为调用者本来就必须显式写出它们的名称。
Python 会在函数定义时只计算一次默认值。 因此,所有调用会共享同一个可变默认值:
# mutable_default.py
def bad_append(item, target=[]): # The same list every call
target.append(item)
return target
print(bad_append(1))
#: [1]
print(bad_append(2)) # Surprise, the default kept the 1
#: [1, 2]
print(bad_append.__defaults__)
#: ([1, 2],)
def good_append(item, target=None):
if target is None:
target = [] # A fresh list each call
target.append(item)
return target
print(good_append(1))
#: [1]
print(good_append(2))
#: [2]