Python基础(五) 函数及面向过程编程详解_def sort(x,y,z) if x<y x,y=y,xif x<z x,z=z,xif y<z

58 阅读9分钟

img img img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

res = 1
for i in range(1,n+1):
    res \*= i
return res

print(factoria(5)) print(factoria(20))



120 2432902008176640000


#### 5.1.2 函数的定义及调用


**白箱子:输入——处理——输出**


**三要素:参数、函数体、返回值**


**1、定义**


def  函数名(参数):


  函数体


  return 返回值



求正方形的面积

def area_of_square(length_of_side): square_area = pow(length_of_side, 2) return square_area


**2、调用**


函数名(参数)



area = area_of_square(5) area



25


#### 5.1.3 参数传递


**0、形参与实参**


* 形参(形式参数):函数定义时的参数,实际上就是变量名
* 实参(实际参数):函数调用时的参数,实际上就是变量的值


**1、位置参数**


* 严格按照位置顺序,用实参对形参进行赋值(关联)
* 一般用在参数比较少的时候



def function(x, y, z): print(x, y, z)

function(1, 2, 3) # x = 1; y = 2; z = 3



1 2 3


* 实参与形参个数必须一一对应,一个不能多,一个不能少



function(1, 2)




TypeError Traceback (most recent call last)

in ----> 1 function(1, 2)

TypeError: function() missing 1 required positional argument: 'z'



function(1, 2, 3, 4)




TypeError Traceback (most recent call last)

in ----> 1 function(1, 2, 3, 4)

TypeError: function() takes 3 positional arguments but 4 were given


**2、关键字参数**


* 打破位置限制,直呼其名的进行值的传递(形参=实参)
* 必须遵守实参与形参数量上一一对应
* 多用在参数比较多的场合



def function(x, y, z): print(x, y, z)

function(y=1, z=2, x=3) # x = 1; y = 2; z = 3



3 1 2


* 位置参数可以与关键字参数混合使用
* 但是,位置参数必须放在关键字参数前面



function(1, z=2, y=3)



1 3 2



function(1, 2, z=3)



1 2 3


* 不能为同一个形参重复传值



def function(x, y, z): print(x, y, z)

function(1, z=2, x=3)




TypeError Traceback (most recent call last)

in 3 4 ----> 5 function(1, z=2, x=3)

TypeError: function() got multiple values for argument 'x'


**3、默认参数**


* 在定义阶段就给形参赋值——该形参的常用值
* 在定义阶段就给形参赋值——该形参的常用值
* **默认参数必须放在非默认参数后面**
* **调用函数时,可以不对该形参传值**
* 机器学习库中类的方法里非常常见



def register(name, age, sex="male"): print(name, age, sex)

register("timerring", 18)



timerring 18 male


* 也可以按正常的形参进行传值



register("Kanye", 40, "female")



Kanye 40 female


* 默认参数应该设置为不可变类型(数字、字符串、元组)



def function(ls=[]): print(id(ls)) ls.append(1) print(id(ls)) print(ls)

function()



1759752744328 1759752744328 [1]



function()



1759752744328 1759752744328 [1, 1]



function()



1759752744328 1759752744328 [1, 1, 1]


**由上可见,列表的地址并没有发生变化。每次操作就是在原地址列表上进行操作,内容发生了变化,因此就好像有了记忆功能一样。因为默认参数被设置为列表这种可变类型。**



def function(ls="Python"): print(id(ls)) ls += "3.7" print(id(ls)) print(ls)

function()



1759701700656 1759754352240 Python3.7



function()



1759701700656 1759754353328 Python3.7



function()



1759701700656 1759754354352 Python3.7


**不会产生“记忆功能”,每次增量后到新的地址**


* **让参数变成可选的**



def name(first_name, last_name, middle_name=None): if middle_name: return first_name+middle_name+last_name else: return first_name+last_name

print(name("T","R")) print(name("T", "R", "!"))



TR T!R


\**4、可变长参数 *args**


* 不知道会传过来多少参数 \*args
* 该形参必须放在参数列表的最后



def foo(x, y, z, *args): print(x, y ,z) print(args)

foo(1, 2, 3, 4, 5, 6) # 多余的参数,打包传递给args



1 2 3 (4, 5, 6)


* 实参打散



def foo(x, y, z, *args): print(x, y ,z) print(args)

foo(1, 2, 3, [4, 5, 6]) #列表被打包成元组赋值给args



1 2 3 ([4, 5, 6],)



foo(1, 2, 3, *[4, 5, 6]) # *将这些列表打散,打散的是列表、字符串、元组或集合



1 2 3 (4, 5, 6)


\*\*5、可变长参数 \*\*\*\*kwargs



def foo(x, y, z, **kwargs): print(x, y ,z) print(kwargs)

foo(1, 2, 3, a=4, b=5, c=6) # 多余的参数,以字典的形式打包传递给kwargs



1 2 3 {'a': 4, 'b': 5, 'c': 6}


* 字典实参打散



def foo(x, y, z, **kwargs): print(x, y ,z) print(kwargs)

foo(1, 2, 3, **{"a": 4, "b": 5, "c":6})



1 2 3 {'a': 4, 'b': 5, 'c': 6}


* **可变长参数的组合使用**



def foo(*args, **kwargs): print(args) print(kwargs)

foo(1, 2, 3, a=4, b=5, c=6)



(1, 2, 3) {'a': 4, 'b': 5, 'c': 6}


#### 5.1.4 函数体与变量作用域


* 函数体就是一段只在函数被调用时,才会执行的代码,代码构成与其他代码并无不同
* **局部变量**——仅在函数体内定义和发挥作用



def multipy(x, y): z = x*y return z

multipy(2, 9) print(z) # 函数执行完毕,局部变量z已经被释放掉了




NameError Traceback (most recent call last)

in 5 6 multipy(2, 9) ----> 7 print(z) # 函数执行完毕,局部变量z已经被释放掉了

NameError: name 'z' is not defined


* **全局变量**——外部定义的都是全局变量
* 全局变量可以在函数体内直接被使用



n = 3 ls = [0] def multipy(x, y): z = n*x*y ls.append(z) return z

print(multipy(2, 9)) ls



54

[0, 54]


* 通过global 在函数体内定义全局变量



def multipy(x, y): global z z = x*y return z

print(multipy(2, 9)) print(z)



18 18


#### 5.1.5 返回值


**1、单个返回值**



def foo(x): return x**2

res = foo(10) res



100


**2、多个返回值**——以元组的形式



def foo(x): return 1, x, x**2, x**3 # 逗号分开,打包返回

print(foo(3))



(1, 3, 9, 27)



a, b , c, d = foo(3) # 解包赋值 print(a) print(b) print(c) print(d)



1 3 9 27


**3、可以有多个return 语句,一旦其中一个执行,代表了函数运行的结束**



def is_holiday(day): if day in ["Sunday", "Saturday"]: return "Is holiday" else: return "Not holiday" print("欢迎订阅") # 不会运行

print(is_holiday("Sunday")) print(is_holiday("Monday"))



Is holiday Not holiday


**4、没有return语句,返回值为None**



def foo(): print("我是孙悟空")

res = foo() print(res)



我是孙悟空 None


#### 5.1.6 建议


**1、函数及其参数的命名参照变量的命名**


* 字母小写及下划线组合
* 有实际意义


**2、应包含简要阐述函数功能的注释,注释紧跟函数定义后面**



def foo(): # 这个函数的作用是为了。 pass


**3、函数定义前后各空两行**



def f1(): pass

             # 空出两行,以示清白

def f2(): pass

def f3(x=3): # 默认参数赋值等号两侧不需加空格 pass

...


**4、默认参数赋值等号两侧不需加空格**


### 5.2 函数式编程实例


**模块化编程思想**


* 自顶向下,分而治之


**【问题描述】**


* 小丹和小伟羽毛球打的都不错,水平也在伯仲之间,小丹略胜一筹,基本上,打100个球,小丹能赢55次,小伟能赢45次。
* 但是每次大型比赛(1局定胜负,谁先赢到21分,谁就获胜),小丹赢的概率远远大于小伟,小伟很是不服气。
* **能通过模拟实验,揭示其中的原理**


**【问题抽象】**


1、在小丹Vs小伟的二元比赛系统中,小丹每球获胜概率55%,小伟每球获胜概率45%;


2、每局比赛,先赢21球(21分)者获胜;


3、假设进行n = 10000局独立的比赛,小丹会获胜多少局?(n 较大的时候,实验结果≈真实期望)


**【问题分解】**



def main(): # 主要逻辑 prob_A, prob_B, number_of_games = get_inputs() # 获取原始数据 win_A, win_B = sim_n_games(prob_A, prob_B, number_of_games) # 获取模拟结果 print_summary(win_A, win_B, number_of_games) # 结果汇总输出


**1、输入原始数据**



def get_inputs():
# 输入原始数据 prob_A = eval(input("请输入运动员A的每球获胜概率(0~1):")) prob_B = round(1-prob_A, 2) number_of_games = eval(input("请输入模拟的场次(正整数):")) print("模拟比赛总次数:", number_of_games) print("A 选手每球获胜概率:", prob_A) print("B 选手每球获胜概率:", prob_B) return prob_A, prob_B, number_of_games


**单元测试**



prob_A, prob_B, number_of_games = get_inputs() print(prob_A, prob_B, number_of_games)



请输入运动员A的每球获胜概率(0~1):0.55 请输入模拟的场次(正整数):10000 模拟比赛总次数: 10000 A 选手每球获胜概率: 0.55 B 选手每球获胜概率: 0.45 0.55 0.45 10000


**2、多场比赛模拟**



def sim_n_games(prob_A, prob_B, number_of_games): # 模拟多场比赛的结果 win_A, win_B = 0, 0 # 初始化A、B获胜的场次 for i in range(number_of_games): # 迭代number_of_games次 score_A, score_B = sim_one_game(prob_A, prob_B) # 获得模拟依次比赛的比分 if score_A > score_B: win_A += 1 else: win_B += 1 return win_A, win_B



import random def sim_one_game(prob_A, prob_B): # 模拟一场比赛的结果 score_A, score_B = 0, 0 while not game_over(score_A, score_B): if random.random() < prob_A: # random.random() 生产[0,1)之间的随机小数,均匀分布 score_A += 1
else: score_B += 1 return score_A, score_B



def game_over(score_A, score_B): # 单场模拟结束条件,一方先达到21分,比赛结束 return score_A == 21 or score_B == 21


**进行单元测试 用assert——断言**


* assert expression
* 表达式结果为 false 的时候触发异常



assert game_over(21, 8) == True
assert game_over(9, 21) == True assert game_over(11, 8) == False assert game_over(21, 8) == False





![img](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/5af2a18240f24872b28cbe9a35376a24~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771321771&x-signature=zZQLiILT6IPhc8kAI%2FdYkZyTmZ0%3D)
![img](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/4b9bed9735b142b5aba4c363631cb35e~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg55So5oi3MzM5MTQ5MjgwNjA=:q75.awebp?rk3s=f64ab15b&x-expires=1771321771&x-signature=N%2FykEAkYF8fzw90mwVhcxT9DXTg%3D)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化资料的朋友,可以戳这里获取](https://gitee.com/vip204888)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**