函数

随着程序变大,你会在多个地方写相同的逻辑。函数让你写一次逻辑,给它起个名字,然后在任何地方使用它。在一处修复它,所有调用都会自动获得修复。
def greet(name):
return f"Hello, {name}!"
print(greet("王明")) # "Hello, 王明!"
print(greet("李芳")) # "Hello, 李芳!"写一次,到处使用,在一个地方修复。
定义函数
def 关键字开始函数定义,后跟名字、圆括号、冒号和缩进的函数体。函数在调用前什么都不做。用 def 定义它,然后用 () 通过名字调用它。
def say_hello():
print("Hello!")
say_hello() # 调用函数def name(): 并在下面缩进函数体。在用 name() 调用它之前什么都不会发生,def 只是设置它。如果忘记 return,函数会默默地返回 None,这在我早期开发时坑过我不止一次。 参数和实参
参数是函数期望的输入。在圆括号内列出它们。调用函数时,传入的值按顺序匹配到参数。
def greet(name, greeting):
print(f"{greeting}, {name}!")
greet("王明", "你好") # "你好, 王明!"
greet("李芳", "早上好") # "早上好, 李芳!"参数是函数定义中的名字。实参是调用函数时实际传入的值。实际上人们会交替使用这两个词;这种区别主要在读文档时重要。
默认值
你可以给参数一个默认值。如果调用者没有提供该实参,会使用默认值。有默认值的参数必须在没有默认值的参数之后。
def greet(name, greeting="你好"):
print(f"{greeting}, {name}!")
greet("王明") # "你好, 王明!"
greet("王明", "早上好") # "早上好, 王明!"有默认值的参数必须在没有默认值的参数之后。
关键字实参
调用函数时,你可以给实参命名。这使调用可读,尤其对有许多参数的函数,并让你以任何顺序传递它们。
def describe_player(name, score, level):
print(f"{name} | 分数: {score} | 级别: {level}")
describe_player("王明", 87, 5) # 位置实参
describe_player(name="王明", level=5, score=87) # 关键字实参,任意顺序
describe_player("王明", level=5, score=87) # 混合:位置实参首先score=87),调用就解释了自己,加上你可以以任何顺序传递它们。一个规则:任何位置实参必须在命名的实参之前。对于有堆积参数的函数很好。 返回值
return 向调用者发送一个值。没有 return,函数返回 None。一旦 return 运行,函数立即退出。那个代码块之后的任何代码都被跳过。
def add(a, b):
return a + b
result = add(3, 4) # result = 7
print(result)return 也立即退出函数。代码块之后的任何代码都不运行。
return 把一个值返回给任何调用函数的人,函数在那里停止,其后的任何东西都被跳过。留下 return 你得到 None 返回。print 显示一个值,return 把它返回给使用,花我一段时间感受那个差别。 返回多个值
Python 让你通过用逗号分隔来返回多个值。调用者将它们作为元组接收并可以在一行中将它们解包到分离的名字。
def min_max(numbers):
return min(numbers), max(numbers)
low, high = min_max([3, 7, 1, 9, 4])
print(low, high) # 1 9low, high = ... 语法是解包:Python 把每个返回的值分配给对应的名字。
low, high = min_max(...),每个值一个名字。当一个函数自然地产生多个答案时很方便。 作用域
在函数内创建的变量仅在该函数内存在。你不能从外部看到它们。在所有函数外定义的变量随处可见,但在没有显式声明的情况下,你不能从函数内改变它。
global 行。几乎从不到达那个:传入值,返回结果,函数保持简单可跟踪。 def calculate():
result = 42 # 这个函数的局部
return result
calculate()
print(result) # NameError,result 不在这里存在count = 0
def increment():
global count # 声明你想修改全局
count += 1
increment()
print(count) # 1使用 global 应该是最后的手段。它使代码更难推理。偏好传入值并返回它们。作用域直接构建在赋值如何把名字绑定到值上,在变量和类型章中覆盖。
*args 和 **kwargs
有时你不知道函数会收到多少实参。*args 收集任何数量的位置实参到一个元组。**kwargs 收集任何数量的关键字实参到一个字典。名字 args 和 kwargs 是约定;星号很重要。
def total(*args):
return sum(args)
total(1, 2, 3) # 6
total(1, 2, 3, 4, 5) # 15def display(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
display(name="王明", score=87, level=5)你可以用常规参数混合它们。常规参数首先出现:
def describe(title, *tags, **metadata):
print(f"{title} | 标签: {tags} | 元数据: {metadata}")
describe("Python 入门", "初学者", "python", author="王明", year=2024)*args 舀出任何数量的额外位置实参作为元组,**kwargs 舀出额外的命名实参作为字典。单词 args 和 kwargs 仅是约定,* 和 ** 做真实的工作。当你不能提前说有多少东西进来时很方便。 文档字符串
文档字符串是函数顶部的字符串,描述它做什么。Python 编辑器和工具用它来显示帮助当你悬停函数调用上时。使用三个引号,对简单函数写一行。
def normalise(value, min_val, max_val):
"""Scale a value to the 0-1 range given the known min and max."""
return (value - min_val) / (max_val - min_val)def build_url(base, version, resource, *, secure=True):
"""
Build an API endpoint URL.
Returns a fully-qualified URL string. If secure is False,
the URL will use http instead of https.
"""
scheme = "https" if secure else "http"
base = base.replace("https://", "").replace("http://", "")
return f"{scheme}://{base}/{version}/{resource}"为任何函数其目的不清楚从其名字和签名写文档字符串。
类型提示
类型提示让你标注函数期望和返回的类型。Python 在运行时不强制它们,但编辑器用它们在运行任何东西前捕获错误。-> 在冒号前指定返回类型。
def greet(name: str, score: int) -> str:
return f"{name} scored {score}"def log(message: str) -> None:
print(f"[LOG] {message}")def top_scores(scores: list[int], n: int) -> list[int]:
return sorted(scores, reverse=True)[:n]类型提示是可选的但对将被从多个地方调用的任何函数有价值。它们是工具可以验证的文档。
name: str 和 -> str 对返回。Python 当它运行时不会强制它们,但你的编辑器读它们并在你击中运行前警告你。把它们看作工具可以检查的注释。 作为值的函数
Python 中的函数是值,如字符串或数字。你可以把它们赋给变量并传递给其他函数。这是 sorted() 如何接受 key= 函数。
def double(x):
return x * 2
def apply(func, value):
return func(value)
apply(double, 5) # 10通过函数作为实参显示持续地用 sorted()、map() 和 filter()。你也会在Lambda和列表推导式章看到它。
key= 给 sorted()。我第一次感到陌生,然后它点击了并转身几乎处处出现。 实际应用
两个一起工作的函数:letter_grade 转换分数到字母,summarise 对列表中的每个分数调用它:
def letter_grade(score: int) -> str:
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
else:
return "F"
def summarise(scores: list[int]) -> None:
total = sum(scores)
avg = total / len(scores)
grades = []
for s in scores:
grades.append(letter_grade(s))
print(f"平均值: {avg:.1f}")
print(f"等级: {', '.join(grades)}")
summarise([87, 92, 74, 65, 91])
