Python函数:函数定义def关键字与调用方式

📅 2026/7/18 18:56:45
Python函数:函数定义def关键字与调用方式
Python函数函数定义def关键字与调用方式一、开篇函数——编程的基石如果说变量是数据的容器那么函数就是逻辑的容器。函数让你把一段代码打包成一个可以反复使用的单元——给它输入它执行特定任务然后返回输出。这就像数学中的函数f(x) x² 2x 1输入x输出计算结果。⌨️ 来看最简单的例子# 定义一个函数defgreet(name):向指定的人打招呼returnf你好{name}# 调用函数print(greet(张三))# 你好张三print(greet(李四))# 你好李四print(greet(王五))# 你好王五三行定义无限次复用——这就是函数的力量。 Python中的函数是一等公民你可以把函数赋值给变量、作为参数传给其他函数、甚至从函数中返回函数。从这篇文章开始我们将进入Python函数编程的系统学习。这是整个Python编程体系中最重要的模块之一。二、函数的定义def关键字2.1 基本语法# 函数定义的基本语法# def 函数名(参数列表):# 文档字符串可选# 函数体# return 返回值可选# 最简单的函数 —— 无参数无返回值defsay_hello():print(Hello, World!)say_hello()# 调用函数say_hello()# 可以多次调用# 带参数的函数defgreet(name):print(f你好{name})greet(张三)# 带返回值的函数defadd(a,b):returnab resultadd(3,5)print(result)# 8# 可以同时有多个参数和返回值defpower(base,exponent):returnbase**exponentprint(power(2,10))# 1024print(power(3,3))# 272.2 函数命名规范# ✅ Python函数命名规范PEP 8# - 使用小写字母# - 单词之间用下划线分隔snake_case# - 名称应该描述函数做什么动词或动词短语# - 避免使用Python关键字和内置函数名# ✅ 好的命名defcalculate_average(scores):passdefget_user_by_id(user_id):passdefis_valid_email(email):passdefsend_notification(user,message):passdefparse_json_file(filename):pass# ❌ 不好的命名# def f(x, y): # 名称无意义# def calc(s): # 使用缩写# def GetUser(id): # 使用了驼峰命名类名才用驼峰# def list(): # 覆盖了内置函数list()# def UserData(): # 看起来像类名2.3 def是一条执行语句# def不是声明而是可执行语句# 当Python执行到def语句时它会创建一个函数对象# 证明在条件中定义函数debug_modeTrueifdebug_mode:deflog(message):print(f[DEBUG]{message})else:deflog(message):pass# 生产环境不输出日志log(这是一条调试信息)# 根据debug_mode的值决定行为# 在循环中定义函数通常不推荐但可行functions[]foriinrange(3):defmake_multiplier(x):returnx*i functions.append(make_multiplier)# ⚠️ 注意所有函数共享同一个iforfinfunctions:print(f(10))# 输出: 20, 20, 20 —— 都是2*10# 因为i最终的值是2所有函数都引用了同一个变量i# 函数也是对象defmy_func():return42print(type(my_func))# class functionprint(my_func.__name__)# my_funcprint(my_func())# 42# 函数可以赋值给变量aliasmy_funcprint(alias())# 42三、函数的组成部分3.1 文档字符串Docstringdefcalculate_bmi(weight,height):计算身体质量指数BMI BMI 体重(kg) / 身高(m)² Args: weight: 体重单位千克 height: 身高单位米 Returns: float: BMI值 Raises: ValueError: 当身高或体重为非正数时 Examples: calculate_bmi(70, 1.75) 22.86 ifweight0orheight0:raiseValueError(体重和身高必须为正数)returnweight/(height**2)# 查看文档字符串print(calculate_bmi.__doc__)help(calculate_bmi)# 在交互式环境中显示格式化文档# ✅ 文档字符串的常见风格# 1. Google风格如上例# 2. NumPy/SciPy风格# 3. Sphinx/reStructuredText风格# 单行docstring简单函数defsquare(x):返回x的平方。returnx**23.2 类型提示Type Hints# Python 3.5 支持类型提示# 它们不影响运行时行为但对IDE和静态检查工具很有用# 基本类型提示defgreet(name:str)-str:returnf你好{name}defadd(a:int,b:int)-int:returnabdefdivide(a:float,b:float)-float:ifb0:raiseValueError(除数不能为零)returna/b# 复杂类型提示fromtypingimportList,Dict,Optional,Union,Tupledefprocess_scores(scores:List[float])-Dict[str,float]:处理分数列表返回统计信息ifnotscores:return{mean:0.0,max:0.0,min:0.0}return{mean:sum(scores)/len(scores),max:max(scores),min:min(scores),}deffind_user(user_id:int)-Optional[Dict[str,Union[str,int]]]:查找用户可能返回None# ...returnNone# None作为默认值和Optional类型defget_config(key:str,default:Optional[str]None)-Optional[str]:pass3.3 函数体与代码块# 函数体是一个代码块有自己的作用域# 缩进决定了哪些代码属于函数defdemonstrate_scope():# 这是函数的局部作用域x100print(f函数内 x {x})# 可以访问外层变量但不推荐依赖这个# 不能修改不可变的外层变量除非用global/nonlocalx10demonstrate_scope()print(f函数外 x {x})# 10 —— 不受函数内影响# 函数可以有多行代码deffactorial(n):计算阶乘ifn0:raiseValueError(n不能为负数)ifn1:return1result1foriinrange(2,n1):result*ireturnresultprint(factorial(5))# 120print(factorial(10))# 3628800四、函数的调用方式4.1 基本调用defintroduce(name,age,city):print(f我叫{name}{age}岁来自{city})# 1. 位置参数调用 —— 最常用的方式introduce(张三,25,北京)# 参数按定义顺序传递# 2. 关键字参数调用 —— 按名称指定introduce(name李四,age30,city上海)introduce(city广州,name王五,age28)# 顺序无所谓# 3. 混合调用 —— 位置参数在前关键字参数在后introduce(赵六,age22,city深圳)# introduce(name钱七, 35, 杭州) # ❌ 错误位置参数不能在关键字参数后面# 4. 解包调用# 从列表/元组解包args[孙八,27,成都]introduce(*args)# 等价于 introduce(孙八, 27, 成都)# 从字典解包kwargs{name:周九,age:33,city:武汉}introduce(**kwargs)# 等价于 introduce(name周九, age33, city武汉)4.2 函数的各种调用模式# 1. 作为另一个函数的参数defapply_operation(x,y,operation):对x和y应用某个操作returnoperation(x,y)defmultiply(a,b):returna*bprint(apply_operation(3,4,multiply))# 12# 结合lambdaprint(apply_operation(3,4,lambdaa,b:ab))# 7# 2. 嵌套调用defsquare(x):returnx**2defsum_of_squares(a,b):returnsquare(a)square(b)print(sum_of_squares(3,4))# 25 ( 9 16)# 3. 链式调用text Hello, World! resulttext.strip().lower().replace(hello,你好)print(result)# 你好, world!# 4. 递归调用函数调用自身deffactorial_recursive(n):ifn1:return1returnn*factorial_recursive(n-1)print(factorial_recursive(5))# 120# 5. 回调函数defprocess_data(data,on_success,on_error):try:resultcomplex_operation(data)on_success(result)exceptExceptionase:on_error(e)defhandle_success(result):print(f✅ 成功:{result})defhandle_error(error):print(f❌ 错误:{error})4.3 获取函数信息defsample_function(a,b10,*args,**kwargs):示例函数returnab# 获取函数信息print(f名称:{sample_function.__name__})print(f文档:{sample_function.__doc__})print(f模块:{sample_function.__module__})# 使用inspect模块获取更详细的信息importinspectprint(f\n签名:{inspect.signature(sample_function)})print(f参数:)forname,paramininspect.signature(sample_function).parameters.items():print(f{name}: kind{param.kind.name}, default{param.default})# 查看函数源码print(f\n源码:)print(inspect.getsource(sample_function))五、函数的设计原则5.1 单一职责原则# ❌ 一个函数做了太多事defprocess_user_data_bad(filename):# 读取文件withopen(filename)asf:dataf.read()# 解析数据linesdata.strip().split(\n)users[]forlineinlines:partsline.split(,)users.append({name:parts[0],age:int(parts[1])})# 计算统计total_agesum(u[age]foruinusers)avg_agetotal_age/len(users)# 打印报告print(f用户数:{len(users)})print(f平均年龄:{avg_age})# 保存结果withopen(report.txt,w)asf:f.write(f用户数:{len(users)}\n平均年龄:{avg_age}\n)returnavg_age# ✅ 每个函数只做一件事defread_user_data(filename):读取用户数据文件withopen(filename)asf:returnf.read()defparse_users(text):解析用户数据users[]forlineintext.strip().split(\n):name,ageline.split(,)users.append({name:name.strip(),age:int(age)})returnusersdefcalculate_average_age(users):计算平均年龄returnsum(u[age]foruinusers)/len(users)defgenerate_report(users,avg_age):生成报告returnf用户数:{len(users)}\n平均年龄:{avg_age:.1f}\ndefsave_report(report,output_file):保存报告withopen(output_file,w)asf:f.write(report)# 组合起来defprocess_user_data(filename,outputreport.txt):textread_user_data(filename)usersparse_users(text)avg_agecalculate_average_age(users)reportgenerate_report(users,avg_age)save_report(report,output)print(report)returnavg_age5.2 纯函数 vs 副作用# 纯函数相同输入始终产生相同输出没有副作用# 优点易测试、易推理、可缓存defpure_add(a,b):returnabdefpure_calculate_tax(income):ifincome5000:return0return(income-5000)*0.2# 有副作用的函数修改了外部状态total_requests0# 全局状态defimpure_handler(request):globaltotal_requests total_requests1# 副作用修改了全局变量print(f处理请求)# 副作用I/O操作returnprocess(request)# ✅ 推荐尽量使用纯函数# 把副作用集中在程序的边缘入口和出口处六、实战案例6.1 数学工具函数库数学工具函数库 —— 函数定义和调用的实践importmathfromtypingimportList,Tuple,Optionaldefis_prime(n:int)-bool:判断一个整数是否为质数ifn2:returnFalseifn2:returnTrueifn%20:returnFalseforiinrange(3,int(math.sqrt(n))1,2):ifn%i0:returnFalsereturnTruedefgenerate_primes(limit:int)-List[int]:生成小于等于limit的所有质数iflimit2:return[]sieve[True]*(limit1)sieve[0]sieve[1]Falseforiinrange(2,int(limit**0.5)1):ifsieve[i]:forjinrange(i*i,limit1,i):sieve[j]Falsereturn[ifori,is_pinenumerate(sieve)ifis_p]defgcd(a:int,b:int)-int:计算最大公约数欧几里得算法whileb:a,bb,a%breturnabs(a)deflcm(a:int,b:int)-int:计算最小公倍数returnabs(a*b)//gcd(a,b)ifaandbelse0defprime_factors(n:int)-List[Tuple[int,int]]:质因数分解返回 (质因数, 指数) 的列表ifn2:return[]factors[]# 处理2count0whilen%20:n//2count1ifcount0:factors.append((2,count))# 处理奇数d3whiled*dn:count0whilen%d0:n//d count1ifcount0:factors.append((d,count))d2ifn1:factors.append((n,1))returnfactors# 使用这些工具函数print(f质数(1-50):{generate_primes(50)})print(fgcd(48, 18) {gcd(48,18)})print(flcm(12, 18) {lcm(12,18)})print(f60的质因数分解:{prime_factors(60)})七、本章小结✅ 本文我们系统学习了Python函数的定义与调用def关键字def 函数名(参数):定义函数。def是执行语句函数是一等公民对象。函数组成部分文档字符串docstring用...描述函数功能类型提示type hintsdef func(x: int) - str:帮助IDE和类型检查函数体缩进的代码块有自己的作用域调用方式位置参数func(1, 2, 3)关键字参数func(a1, c3, b2)混合调用位置在前关键字在后解包调用func(*list)、func(**dict)设计原则单一职责每函数只做一件事、纯函数优于有副作用的函数、函数名应描述操作。函数是Python编程的基石。掌握好函数的定义和调用你就掌握了封装逻辑、复用代码的核心能力。⌨️ 下一篇文章我们将学习函数的返回值——return语句的奥秘。