目录
1、函数的定义与调用
1.1、什么是函数
1.2、使用函数的好处
1.3、函数的定义
1.3.1、函数的赋值
2、函数参数
2.1、什么是函数参数
2.2、参数的形式
2.3、参数分类
2.3.1、参数的注意事项(⭐⭐⭐)
2.3.2、可变长位置参数
2.3.3、可变长关键字参数
2.3.4、参数定义顺序⭐
2.3.5、小练习
2.3.6、解包
3、函数返回值
3.1、函数return的语句
4、匿名函数
4.1、匿名函数及其定义
4.1.1、map
4.2、匿名函数——小练习(round的使用)
5、递归函数
5.1、递归函数练习——使用递归实现斐波拉契数列
5.2、递归函数练习——兔子繁衍问题
5.4、 递归函数练习——爬楼梯问题
6、函数的参数传递
6.1、不可变数据类型
6.2、可变数据类型
6.3、 定义参数的时候,默认参数避免定义成一个可变数据类型⭐⭐⭐
7、变量作用域
7.1、局部变量和全局变量
7.2、内建变量
7.3、变量名的解析原则(查找顺序为:LEGB)
8、文档注释(Document String)
9、内建函数与工厂函数
9.1、函数和方法
9.2、内建
9.3、工厂函数
9.3.1、工厂函数主要与数据类型相关
9.4、builtins有哪些?
9.5、常用的内建函数(Built-in Functions)
在开发语言中:函数是指实现某个功能的一段代码
def add(a,b): # 要传入的参数,就在括号里边写参数;要是不传入的话,就不写
print("exec add function") # 这里只是函数的内容,也算是把这些内容封装成函数
return a+b # 这里只是定义了这个函数,没有执行
print(add(1,2))
result = add(3,4)
print(result)
# 1、方便维护,模块化设计
# 2、减少代码冗余
1、模块化程序设计; 2、减少代码冗余 ;3、维护方便
def func1():
print("hello")
a = func1
b = func1()
print("##############")
a()
print(b)
函数取得的参数是你提供给函数的值;这些参数就像变量一样,只不过它们的值是我们调用函数的时候定义的
参数在函数定义的圆括号对内指定,用逗号分割
1、形参:函数定义的时候,指定的参数
2、实参:函数调用的时候,传递的参数
按形参来分:1、必选参数;2、默认参数;3、可变长位置参数:4、可变长关键字参数
按实参来分:1、位置参数;2、关键字参数
# 必选参数
def stuinfo1(name, age, sex): #必选参数
print(f"myname is {name},my age is {age},my sex is {sex}")
# 位置参数
stuinfo1('sc','4','man') # 位置参数一一对应
# 默认参数
def stuinfo2(name, age, sex ='f'): # 这个sex就是默认参数,如果有没传递参数,就默认这个
print(f"myname is {name}, my age is {age}, my sex is {sex}")
stuinfo2("sc",4)
stuinfo2('sc',4,'man')
# 关键字参数
stuinfo2('sc',sex='m',age=6) # 这后边两个就是关键字参数,注意要是有位置参数存在,那就必须把位置参数放在最前面
# 常见错误
#1、
stuinfo2('sc','m',age=6) #如果是这样,'m'会给到age,然后后边又有一个age=6,这样是不行的
# ⭐⭐⭐注意定义顺序,默认参数放在必选参数后边;注意调用顺序,关键字参数必须放在位置参数后边
总的来说:1、注意定义顺序,默认参数放在必选参数后边;2、注意调用顺序,关键字参数必须放在位置参数后边
# 可变长位置参数,就是形参前边接个 '*'.可传递0-n个位置参数
def myargs(name, *num):
print("*"*30)
print(f"{name}:{num}") # 默认是打包成一个元组的
print(type(num),*num) # -->print(type(num),1,2)
myargs("sc")
myargs("sc1",1)
myargs("sc2",1,2)
# 这是内部机制
# packing(打包) 和 unpacking(解包)
# packing
# 1,2 -->元组(1,2)
# *num unpacking -->解包成print(1,2)
# 可变长关键字参数
def myargs2(**num):
print(num)
myargs2(a=1,b=2)
myargs2(a=1)
myargs2(a=1,b=2,c=3)
# packing --> a=1, b=2 --> {"a":1,"b":2} 打包成字典
# unpacking -->{"a":1,"b":2} --> a=1,b=2。所以不可以使用print(**num)
>>> d1 = {'a':1,'b':2}
>>> "{a}..{b}".format(**d1)
'1..2'
>>> "{a}..{b}".format(a=1,b=2)
'1..2'
# 形参定义顺序
# func01(必选参数,可变长位置参数,默认参数,可变长关键字参数)
# 实参定义
# func02(位置参数,关键字参数)
# method1
def sum1(*args):
sum0 = 0
for i in args:
sum0 += i
print(f"可变长位置参数的和为{sum0}")
def sum2(**kwargs):
sum3 = 0
for i,j in kwargs.items():
sum3 += j
print(f"可变长关键字参数的和为{sum3}")
sum1(1,2,3,4,5)
sum2(a=1,b=2,c=3)
# method2 ⭐⭐
def add(*num):
print(f"和为:{sum(num)}")
add(1,2,3,4)
def add2(**num):
print(f"字典和为:{sum(num.values())}")
add2(a=1,b=2,c=3)
容器类型都可以解包
(1)*num
list1 = ["a","1",3]
print(*list1)
d1 = {"a":1,"b":2}
print(*d1)
(2)**num
d1 = {"a":1}
d2 = {"b":2}
d3 = {"a":2,"b":4}
print(dict(d1, **d2)) # -->dict(d1,b=2)
print(dict(d1, b=2))
print("a is {a}, b is {b}".format(a=1, b=2))
print("a is {a}, b is {b}".format(**d3))
# 函数的return语句
# 退出函数,并且返回结果的
# 一个函数一旦执行到return就退出,就不会执行后边的语句
# 如果函数没有return语句,默认返回None。如果return后边不接任何表达式,也是返回None
# return可以有多个
# return 一次也可以返回多个值
def maxnum(x, y):
print("return 语句...")
if x > y:
print("return x")
return x
elif x < y:
print("return y")
return y
return x, y
print("return end....") # 由结果可以看到这个语句并没有执行
result = maxnum(2, 3)
result = maxnum(3, 3)
print(f"结果为:{result}") # 这里可以看到我们若是return两个值,它会返回一个元组
def maxnum(x, y):
print("return 语句...")
if x > y:
print("return x")
# return x
elif x < y:
print("return y")
# return y #没有'return y'这个语句等价于'return',所以返回值为None
# return x, y
print("return end....")
result = maxnum(2, 3)
result = maxnum(3, 3)
print(f"结果为:{result}")
# 匿名函数
# 不需要创建函数名
# 只能有一个表达式,不用写return,该表达式的结果就是是返回值
def add(a,b):
return a+b
print(add(1,3))
# 匿名函数不是这么用的,这里'add2'只是给出例子,更有利于理解匿名函数的用法。
add2 = lambda x,y: x+y # 这个匿名函数就等价于上述的函数
print(add2(1,3))
格式:map(func,*iterables)
map(),是一个可调用对象func依次映射到序列的每个元素上,并返回一个可迭代的马匹对象。得到的map对象可以转化为列表、元组或者集合,不转化的话,就无法看到结果。其中每个元素是原序列中元素经过可调用对象func处理后的结果,但该函数不对原函数做任何修改。
b = map(str, range(5))
print(b)
# 执行结果:
高阶函数
# 将列表中的元素全部平方
lst = [1,2,3,4]
print(list(map(lambda x:x*x, lst))) # 把lst里边的值放入前边这个函数处理
# 使用map将列表中的数保留两位小数
lst1 = [0.23333, 3.14159, 7.256816]
print(list(map(lambda x:round(x,2),lst1)))
# 使用匿名函数返回两个数之间的最大值
# max1 = lambda x, y: x if x > y else y
# max1 = lambda x, y: max(x, y)
max1 = lambda x, y: x > y and x or y
print(max1(7, 6))
# 使用匿名函数,将传入的浮点数保留两位小数
# reserve = lambda x: float('%.2f'%x) # 这里边的是一个字符串,所以要进行转化
# reserve = lambda x: float("{0:.2f}".format(x)) #
reserve = lambda x:round(x,2) # 使用round,来进行保留两位小数
print(type(reserve(2.165654456)),reserve(2.165654456))
# 递归函数
# 自己调用自己,形成循环
# 定义出口条件,什么时候结束递归
# 通常是把一个大问题通过寻找规律可以缩小规模的时候使用的才能够使用的
# 求取n的阶乘
# n! = 1*2*3*...*n
# f(n) = n* f(n-1)
# 有最大递归深度 996(可以改)
# 尽量避免使用递归,除非没有更好的算法,或者是某种特定的情况下使用递归。
# 每次递归都会保存结果在内存中,非常占内存,效率低下。
# 所以能不用递归就不用递归
def func01(n):
if n == 1:
return 1
return n * func01(n-1)
print(func01(3)) # 这是打印结果
# 推算过程:func01(3) = 3 * func01(2) = 3 * 2 *func01(1) = 3 * 2 * 1
# 使用递归实现斐波拉契数列
# 1,1,2,3,5,8,13.....
def fblq(n):
if n == 1 or n == 2:
return 1
return fblq(n - 1) + fblq(n - 2)
a = input("请输入数列项目:")
str1 = ''
for i in range(1, int(a) + 1):
str1 += str(fblq(i)) + ','
print(str1)
# 有一对雌雄兔,每两个月就繁衍雌雄兔一队,问n个月之后有多少对兔子
# 第1,2月:1对
# 第3,4月:2对
# 第5,6月:4对
# 第7,8月:8对
# f(n) = f(n-2) *2
def robbit(n):
if n == 1 or n == 2:
return 1
return robbit(n-2) * 2
print(robbit(int(input("请输入你想要知道的月份"))))
# 有一个人爬楼梯,他每一次都可以选择爬一阶或者两阶,他要爬n阶,有多少种选择
# 比如:他在第九阶的时候,可能从第七阶或者第八阶爬上来
# 规律:f(n) = f(n-1) + f(n-2)
# 递归方法
def climb(n):
if n == 0:
return 0
elif n == 1:
return 1
elif n == 2:
return 2
else:
return climb(n - 1) + climb(n - 2)
print(climb(int(input("请输入你想要爬的楼层:"))))
# 动态规划方法
def f1(n):
dp = [0] * n # [0,0,0,0...0],n个0
dp[0] = 1
dp[1] = 2
for i in range(2, n):
dp[i] = dp[i - 1] + dp[i - 2]
return dp[n - 1]
print(f1(5))
从动态类型看函数的参数传递,函数的参数传递,本质上传递的是引用
def func1(x):
print("第一个x",x)
# 局部变量
x = 100
print("第二个x",x)
# 全局变量
x = 1
func1(x)
print(x) # 这能说明局部变量只是在那个函数里有用
# 可变数据类型
def f1(x):
x.append(1) x不会改变x的本身,只是改变了x的内容
print(x)
a = [12]
f1(a)
f1(a)
f1(a)
# 参数定义的时候,默认参数避免定义成一个可变数据类型
# a=[] 在创建函数的时候就已经创建好了
def f(a=[]): # 这样会造成每个调用都相关联,因为[]是一个可变数据类型
a.append(1)
print(a)
f()
f()
f()
# 变量的作用域
def f(): # 形参不能够与后边这个定义的全局变量同名
# 这里边第一个x就是为局部变量
# x = 2 # 如果你要申明全局变量,那就不要在前面又定义个同名的局部变量
global x # 申明x为全局变量,最好直接放在函数最上边
x = 5
x = 1
f()
print(x) # 这里打印的是全局变量
output:5
内建变量是由双下划线开头和双下划线结尾的
1)在本地变量中找 -- local
2)在任意上层函数中找 -- enclosing
3)在全局作用域中找 -- global
4)在内置作用域中找 -- built-in(python内建变量,解释器创建的)
# 要是在以上作用域中找到了就输出,要是都没有找到就报错
# print(a)
# print(__name__)
def f():
x = 2 # {2,1}
def f2():
x = 3 # 不注释的时候输出'3',x的注释顺序以及输出结果{1,2}
print(x)
print(__name__)
f2()
x = 1 # {3,报错} 然后换__name__实验,把x语句都注释掉
__name__ = 'sc' # 没注释,就输出'sc';注释了就输出'__main__',因为这是一个内置函数
f()
文档注释是包、模块、类或者是函数第一个用三引号引起来的字符串
def f():
"""
this is test func
f()
:return:
"""
print("hello")
print(help(f)) # 函数的文档注释会被help识别
一般就是类型转换函数。工厂函数属于内建函数
builtins主要是四个方面:1、内建异常;2、内建变量;3、工厂函数;4、内建函数