python学习笔记 (5)
函数
1.函数的定义:
def : 定义函数的关键字
xxxx : 函数名
参数 : 需要传进来的值
可选择性地使用return返回一个值给调用方,不 return 相当于返回 None,在Python中不需要定义返回值类型,可自动推断。
例子:
PI = 3.14
def circle_area(r: float): # circle_area是函数名 r是参数
"""
:param r: 半径
:return: ⚪的面积
"""
s = PI * r * r
return s
2.函数的参数:
在上面的例子中,r是必选参数/位置参数,必须传入参数。pi是默认参数,不传参数时以默认值计算 传参是以给定值计算。除定义的必选参数外,还可使用默认参数、可变参数、关键字参数和命名关键字参数。
可变参数:可变参数允许传入0个或任意个参数,可变参数在函数调用时自动组装为一个tuple
def get_num_avg2(*args):
mean_num2 = sum(args) / len(args)
print(mean_num2)
关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。
def get_student_info2(name, age, id, **kwargs):
print(f"学生姓名是{name},年龄为{age},身份证为{id},其他信息为{kwargs}")
for k, v in kwargs.items():
print(f"学生想展示的其他信息为{k} 为 {v}")
对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查。如果要限制关键字参数的名字,就可以用命名关键字参数,和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。
def get_student_info3(name, age, *, addr, height):
print(f"学生姓名是{name},年龄为{age},住址为{addr},身高{height}")
注意参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
3.函数的调用:
if __name__ == '__main__':
# 直接写函数名 就是调用函数
4.lambda函数
lambda函数是匿名函数,所谓匿名函数,通俗地说就是没有名字的函数。lambda函数没有名字。
由于lambda语法是固定的,其本质上只有一种用法,那就是定义一个lambda函数。
在实际中,根据这个lambda函数应用场景的不同,可以将lambda函数的用法扩展为以下几种:
1、将lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数。
2、将lambda函数赋值给其他函数,从而将其他函数用该lambda函数替换。
lambda函数用法之高阶函数:
1.映射(map)
print(list(map(lambda x: x ** 2, li)))
2.规约(reduce)
from functools import reduce
li = [1, 2, 3, 4, 5, 6, 7, 8, 9]
print(reduce(lambda x, y: x + y, li))
reduce用于字符串反转:
strs = 'abcdefghijklmnopqrstuvwxyz'
print(reduce(lambda x, y: y + x, strs))
命名空间
命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过 Python 字典来实现的。
命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重名而没有任何影响。
例如在一个计算机系统中,一个文件夹(目录)中可以包含多个文件夹,每个文件夹中不能有相同的文件名,但不同文件夹中的文件可以重名。
1.内置名称(built-in names): Python 语言内置的名称,比如函数名 abs、chr 和异常名称 BaseException、Exception 等等。
2.全局名称(global names) 模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量
3.局部名称(local names) 函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量(类中定义的也是)。
命名空间的查找顺序
局部的命名空间 -> 全局命名空间 -> 内置命名空间
如果找不到,它将放弃查找并引发一个错误。
命名空间的生命周期: 命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束 因此无法从外部命名空间访问内部命名空间的对象。
a = 10 #两次打印的a的值会改变
print(a)
a = 20
print(a)
print(str)
# <class 'str'>
str = 10
print(str)
# 10
作用域
Python程序中可直接访问到命名空间的正文区域,直接访问在这里指的是尝试在命名空间找到这个名称并且无限制的引用它,说白了就是变量可作用的范围 。
在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。
Python 的作用域一共有4种:
L(Local):包含局部变量,比如一个函数/方法内部
E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量
G(Global):最外层,比如当前模块的全局变量
B(Built-in):包含内建变量/关键字等,最后被搜索
在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问。
for i in range(10): #for 、if、 try 都不会引入新的作用域
print(i)
# 0 1 2 3 4 5 6 7 8 9
print(i)
# 9
递归
在Python中,函数内部可以调用其他函数,如果一个函数在内部调用自身本身,这个函数就是递归函数。
# 在自己的函数里面调用自己
# def c():
# print("xxxxxx")
# c()
递归函数需要满足两个条件: 1.自己调用自己 2.有停止条件。
一些是递归的经典例子:
# 用于递归计算阶乘
def d(num):
if num == 1:
return 1
return num * d(num-1)
if __name__ == '__main__':
print(d(10))
# 3840
斐波那契数列:
def fib(ind):
if ind <= 2:
return 1
return fib(ind-1) + fib(ind-2)
if __name__ == '__main__':
print(fib(6))
#8
一球从100m落下,每次落地反跳回原高度的一半,再落下,求它在第十次落地时,反弹多高?
# 出口 =》 100米
# f(10) => f(9)/2 => f(8)/2
def boll_down(n):
if n == 1:
return 100
return boll_down(n - 1) / 2
pass
if __name__ == '__main__':
print(boll_down(10))
#0.1953125
其他:
# 有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。
# 问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。
# 问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。
# 请问第五个人多大
# 出口: 第一个人十岁
# 条件: f(5) => f(4) + 2 f(4) => f(3) + 2
def ques_age(num):
if num == 1:
return 10
return ques_age(num - 1) + 2
pass
if __name__ == '__main__':
print(ques_age(5))
# 18
# 猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个
# 第二天早上又将剩下的桃子吃掉一半,又多吃了一个。
# 以后每天早上都吃了前一天剩下的一半零一个。
# 到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少
# 出口 : 第十天 只剩一个桃
# 条件 : f(10) = f(9) / 2 -1 f(9) = (f(10) + 1) * 2
def peach_num(n):
if n == 10:
return 1
return (peach_num(n + 1) + 1) * 2
if __name__ == '__main__':
print(peach_num(1))
#1534