函数基础
函数 又叫 方法 功能
函数名规范:字母a-z A-Z数字0-9下划线 _ 不能由数字开头 严格区分大小写 不能用关键字 取名字要有意义 同一个文件中的函数名不能重复
1.自定义函数
def 函数名(形参):
你的代码
2.系统提供的函数 叫做内置函数
先把形参传递给实参 返回值 行不行 相当于break
自定义函数写完不调用 函数不发挥他的作用
调用过程中( )小括号代表执行
函数的参数
###形式参数
def sums(num1,num2): #""""""自动补全函数注释
"""
求两个数字的和
:param num1:int/flost #写类型
:param num2: int/float #写类型
:return: int/float #写类型
"""
print(num1+num2)
###实际参数
sums(11,22)
def xinagsheng(p1,p2,p3):
"""
:param p1:str
:param p2: str
:param p3: str
:return: str
"""
print(p1+'唱了一首'+p2)
print(p3+'也唱了一首'+p2)
xinagsheng('张云雷','探清水河','孟鹤堂')
xinagsheng('郭麒麟','探清水河','张鹤伦')
结果:
张云雷唱了一首探清水河
孟鹤堂也唱了一首探清水河
郭麒麟唱了一首探清水河
张鹤伦也唱了一首探清水河
默认参数
def test(age=10):
print('你的年龄:%d'%age)
test() #有了默认值 可以直接调用 不传这个参数
test(age=20) #优先传赋的值
#默认值参数 一定要在 非默认值参数的后面
#前面写法是age = 17 后边就不能只写黄冈 必须city='hg' 但是前面sunf age=17这种是支持的
def say_hi(name,age,city='wuhan'):
# print('大家好,我是{},今年{},来自{}'.format(name,age,city))
print(f'大家好,我是{name},今年{age},来自{city}')
return
say_hi('sunf',17)
say_hi('sunf',17,'hg')
say_hi(name='sunf',age=17,city='hg')
say_hi('sunf',age=17,city='hg')
# print(self, *args, sep=' ', end='\n', file=None)
#print方法中的 sep= end= 缺省参数 也叫默认参数
自定义参数
# 相加
def add_many(nums):
"""
:param num:列表 元组 集合 字典 range() 字符串
:return:
"""
if isinstance(nums,dict): #isinstance(x,数据类型) 判断是否为这个类型
nums = nums.values()
x=0 #存放最终的和
for i in nums:
if type(i)==int:
x+=i
else:
x+=int(i)
return x
print(add_many([11,2,43,56,74])) #186
print(add_many((11,2,43,56,74))) #186
print(add_many({'name':78,'age':23})) #101
print(add_many('356878')) #37
print(add_many(range(1,9))) #36
def test(*num): #代表多个参数
print('num:{}'.format(num)) #num:(1, 2, 3, 4, 5, 6, 7, 8) 是元组
x=0 #存放总和
for i in num: #遍历上面元祖
x+=1
return x
print(test(1,2,3,4,5,6,7,8))
#万能参数 *args接收单个元素 放到元组中
#**kwargs 接收键值 放到字典中
def wanneng(*args,**kwargs):
print('args{}'.format(args)) #args(2, 3, 4, (33, 34), '343dfs', [23, 44])
print('kwargs{}'.format(kwargs)) #kwargs{'sa': 'duyuan', 'han': 'gga'}
#遍历参数
for x in args:
print(x)
for y in kwargs.keys():
print(y)
wanneng(2,3,4,(33,34),'343dfs',[23,44],sa='duyuan',han='gga')
可变类型与不可变类型的传参
#内存地址 16进制表示 0X 0x %X %x 16进制格式化字符
#整形不可变 改变之后地址变化
def test(x):
print('修改之前的内存的地址:0x%x'%id(x)) #id()用来查看变量内存地址 修改之前的内存的地址:0x7ffab9b57110
x = 666 # 修改
print('修改之后的内存的地址:0x%x'%id(x)) #id()用来查看变量内存地址 修改之后的内存的地址:0x19a79798710
test(1)
#列表可变数据 改变之后地址不变
def test(y):
print('修改之前的内存的地址:0x%x'%id(y)) #id()用来查看变量内存地址 修改之后的内存的地址:0x19a79798710
y[0] = 'haha' # 修改
print('修改之后的内存的地址:0x%x'%id(y)) #id()用来查看变量内存地址 修改之后的内存的地址:0x19a79798710
test([1,2,3,4,5,6,7])
函数的返回值
返回值 函数执行的结果
并不是所有的函数都有返回值
如果一个函数没有返回值 那么它的返回值就是None
def adds(x,y):
"""
求两个数字的和
:param x: int/float
:param y: int/float
:return: int/float
"""
print(x+y)
return x+y #return 表示给到你函数执行结果 打印实参加print
print(adds(3,4)) #7
x = print('hello world') #直接打印没有返回值
print(x) #None
多个返回值
一般情况下 函数只执行一个return语句
但是有一个列外 finally 语句下 一个函数可能会执行多个return
return 可以返回元组 字典 列表 默认元祖
def test(x,y):
num1 = x+y
num2 = x*y
num3 = x-y
return num1,num2,num3
# return [num1,num2,num3]
# return {'num1':num1,'num2':num2,'num3':num3}
# return (num1,num2,num3)
print(test(10,15))
a,b,c=test(10,15) #取出对应的元祖
print(a,b,c)
for x in test(10,5): #遍历
print(x)
result = test(10,5)
print('商{},商{},余数{}'.format(result[0],result[1],result[2])) #商15,商50,余数5
a,b,c = test(10,15)
print('数字{},数字{},数字{}'.format(a,b,c)) #数字25,数字150,数字-5
函数调用函数
##三位数相加
def test1(num1,num2): #实际参数传给形式参数
"""
求两个数字的和
:param num1: int/float
:param num2: int/float
:return: int/float
"""
return num1+num2
def test2(x,y,z)
print('开始调用test1')
return test1(y,z)+x #调用test1
print(test2(10,20,30) #60
#求[n,m)之间的和
def sums(n,m):
x=0 #存放最终结果
"""
:param num1: int
:param num2: int
:return: int
"""
for i in range(n,m):
x+=i
return x
print(sums(10,20)
#求n的阶乘
def factorial(n):
x=1
for i in range(1,n+1):
x*=i
return x
print(factorial(6))
#求 1! +2!+3!+4!+5! n的阶乘
def factorial_sum(n):
x=0
for i in range(1,n+1):
x+=factorial(i)
return x
def factorial(i):
y=1
for j in range(1,i+1):
y*=j
return y
print(factorial_sun(6))
函数的全局变量和局部变量
整个.py文件 都可以访问的变量 叫做全局变量
局部变量 这个变量是在函数内部定义的变量 如果函数执行完毕 会从内存中释放空间
globals()#内置函数 用来查看全局变量
locals() #内置函数 用来查看局部变量
对全局变量做修改 用global对局部变量进行声明
局部变量可以调用全局 全局不能调用局部变量
if for while 不存在作用域 也就是他们里边不存在局部变量 全局可以直接调用
a=100 #全局变量
test = 'hello world'
def say_hi():
num=666 #局部变量 这个变量是在函数内部定义的变量
# a=1000 #这个a是新定义的局部变量 不会修改全局变量
global a #声明 我这不是一个新的局部变量 我想对全局变量a做修改
a=1000
# return test+str(num)
print(num+a) #局部变量可以调用全局
# print(say_hi())
say_hi()
print(a)
# print(num) #全局不能调用局部变量 报错
word = '英雄武汉人民' #全局变量
# word = 'haha' 都是全局变量 如果重名 后面将覆盖前面
def test():
x='hello wuhan' #局部变量
print('x={}'.format(x))
# word = '你好湖北' #在函数内容 跟全局变量名重名 不影响
#表示创建一个新的局部变量
global word
word = '你好武汉'
print('函数内部的变量word={}'.format(word))
print('全局变量{},局部变量{}'.format(globals(),locals())) #输出所以全局变量
test()
# print(x)# 这是在全局调用局部变量 报错 不能调用
print('全局变量word={}'.format(word))
递归函数
#用递归实现1-n之间的和
def get(n):
if n==0:
return 0
return n+get(n-1)
print(get(5))
"""
1 get(5) =5+get(4) 10+5=15
2 get(4) =4+get(3) 4+6=10
3 get(3) =3+get(2) 3+3=6
4 get(2) =2+get(1) 2+1=3
5 get(1) =1+get(0) 1+0=1
6 get(0) return 0 0
"""
# n!
def get_factorial(n):
if n==0:
return 1
return n*get_factorial(n-1)
print(get_factorial(5))
"""
1 get(5) =5*get(4) 5*24=120
2 get(4) =4*get(3) 4*6=24
3 get(3) =3*get(2) 3*2=6
4 get(2) =2*get(1) 2*1=2
5 get(1) =1*get(0) 1*1=1
6 get(0) return 1 1
"""
#斐波那契数列
#0 1 1 2 3 5 8 13 21 34 55 89 144
def Fibnacci(n):
if n==0 :
return 0
elif n==1:
return 1
return Fibnacci(n-2)+Fibnacci(n-1)
print(Fibnacci(12))
"""
1 F(12)=F(10)+F(11) 55+89=144
2 F(11)=F(9)+F(10) 34+55=89
3 F(10)=F(8)+F(9) 21+34=55
4 F(9)=F(7)+F(8) 13+21=34
5 F(8)=F(6)+F(7) 8+13=21
6 F(7)=F(5)+F(6) 5+8=13
7 F(6)=F(4)+F(5) 3+5=8
8 F(5)=F(3)+F(4) 2+3=5
9 F(4)=F(2)+F(3) 1 2 =3
10 F(3)=F(1)+F(2) 1 1 =2
11 F(2)=F(0)+F(1) return 0 1 = 1
"""
匿名函数lambda
#换新函数名 地址不变
def add(num1,num2):
return num1+num2
print('函数内存地址:0x%x'%id(add)) #函数内存地址:0x20071bd79d8
x=add(1,3)
print(x)
#给add起了一个别名 地址一样
fn = add
print('新函数名内存地址:0x%x'%id(fn)) #新函数名内存地址:0x20071bd79d8
y =fn(5,6)
print(y)
#匿名 没有名字
#一次性的函数 一般我们就创建一个匿名函数 功能 肯定不会复杂
#调用匿名函数
# 1.给他定义一个名字 这个很少用
test = lambda x,y: x*y
print(test(1,3)) #3
# 2.把他当作参数传给另一个函数
def test(x,y,fn):
"""
:param x: int
:param y: int
:param fn: 方法 函数
:return: int
"""
z=fn(x,y)
return z
def add(a,b): # add也叫回调函数
return a+b
print(test(12,21,add)) #add函数名 不加() 告诉 test 调用函数add ( )代表执行
print(test(10,20,lambda x,y:x+y))
print(test(10,20,lambda x,y:x*y))
print(test(10,20,lambda x,y:x-y))
print(test10,20,lambda x,y:x/y))
应用匿名函数的内置函数和内置类
排序 sort def sort(self,key=None,reverse=False)
key 是用来指定比较规则 是一个方法函数
reverse 是判断正序倒序
studens = [{'name':'zhangsan ','age':16,'score':83},
{'name':'lisi','age':17,'score':89},
{'name':'ergou','age':14,'score':67},
{'name':'baifa','age':13,'score':89},
{'name':'wuyu ','age':17,'score':80},
{'name':'zhah ','age':13,'score':67},
{'name':'zlala ','age':16,'score':87},
{'name':'aipig','age':15,'score':78}
]
def foo(ele): #定义函数
return ele['age']
studens.sort(key=foo) #告诉 sort 按照字典中的 age 进行排序
print(studens)
studens.sort(key=lambda ele:ele['age'],reverse=True)
print(studens)
排序 sorted
sorted 在python2是个方法 在python3 变成内置类
studens = [{'name':'zhangsan ','age':16,'score':83},
{'name':'lisi','age':17,'score':89},
{'name':'ergou','age':14,'score':67},
{'name':'baifa','age':13,'score':89},
{'name':'wuyu ','age':17,'score':80},
{'name':'zhah ','age':13,'score':67},
{'name':'zlala ','age':16,'score':87},
{'name':'aipig','age':15,'score':78}
]
res = sorted(studens,key=lambda ele:ele['age'],reverse=True)
print(studens)
过滤 filter 类 def_init_(self,function_or_None,iterable)
unction_or_None 是一个方法
iterable 是一个可迭代对象
对可迭代对象进行过滤 返回的是一个filter对象 可以对对象转成列表 元组等
filter 在python2是个方法 在python3 变成内置类
studens = [{'name':'zhangsan ','age':16,'score':83},
{'name':'lisi','age':17,'score':89},
{'name':'ergou','age':14,'score':67},
{'name':'baifa','age':13,'score':89},
{'name':'wuyu ','age':17,'score':80},
{'name':'zhah ','age':13,'score':67},
{'name':'zlala ','age':16,'score':87},
{'name':'aipig','age':15,'score':78}
]
print(list(filter(lambda x:x['age']>15,studens))) #list转换为列表形式
#[{'name': 'zhangsan ', 'age': 16, 'score': 83},
# {'name': 'lisi', 'age': 17, 'score': 89},
# {'name': 'wuyu ', 'age': 17, 'score': 80},
# {'name': 'zlala ', 'age': 16, 'score': 87}]
叠加 map def init(self, func, *iterables)
func 是一个函数,方法
iterables 是一个可迭代对象
对列表中的每一项数据执行相同的操作 返回的是一个新的迭代器
studens = [{'name':'zhangsan ','age':16,'score':83},
{'name':'lisi','age':17,'score':89},
{'name':'ergou','age':14,'score':67},
{'name':'baifa','age':13,'score':89},
{'name':'wuyu ','age':17,'score':80},
{'name':'zhah ','age':13,'score':67},
{'name':'zlala ','age':16,'score':87},
{'name':'aipig','age':15,'score':78}
]
res= map(lambda x:x['age']+1,studens)
print(res) #<map object at 0x00000185314863C8>
print(list(res)) #[17, 18, 15, 14, 18, 14, 17, 16]
合并 reduce def reduce(function,sequence,initial=None )
第一个参数是个方法
第二个参数是个列表
第三个参数 initial 表示从几开始
如果不加第三个参数 会抛出类型错误
python3整合到了functools 模块
pip install 模块名 先下载
再导入 from functools import reduce
studens = [{'name':'zhangsan ','age':16,'score':83},
{'name':'lisi','age':17,'score':89},
{'name':'ergou','age':14,'score':67},
{'name':'baifa','age':13,'score':89},
{'name':'wuyu ','age':17,'score':80},
{'name':'zhah ','age':13,'score':67},
{'name':'zlala ','age':16,'score':87},
{'name':'aipig','age':15,'score':78}
]
def add(x,y):
x = 0
y = {'name':'lisi','age':17,'score':89}
return x+y['age']
print(reduce(add,studens,0))
print(reduce(lambda x,y:x+y['age'],studens,0)) #x,y为形参 #0+10+17+...+15
print(reduce(lambda x,y:x+y['age'],studens,1))#1+10+17+...+15
print(reduce(lambda x,y:x+y['age'],studens,-10))#-10+17+...+15
内置函数 any dir help
#any 参数是可迭代对象 判断可迭代参数是否全为假
print(any(['zhangsan',1,[1,2,3]])) #有一个是True 结果返回True
print(any(['',0,[]])) #全为False 结果返回False
#返回参数 范围内的 方法 属性 变量 等
print(dir([]))#['append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
print(dir({}))#['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
print(dir(()))#['count', 'index']
print(dir(""))#['capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
#help 查看注释
help(input)
help(print)
num = [1,23,3]
help(num.sort)
def test(x,y,age=10):
"""
:param x: int
:param y: float
:param age: int
:return:
"""
return x+y+age
help(test)
高阶函数
函数数据类型:int float list dict tuple str set bool function
高阶函数
函数作为另外一个函数的参数
函数作为另外一个函数的返回值
函数内部在定义一个函数 if
#type 查看数据类型
def test(x,y):
return x+y
print(type(test))#<class 'function'>
def test():
print('我是test函数')
return 'hello'
def demo():
print('我是demo函数')
return test
def haha():
print('我是haha函数')
return test()
#返回一个函数 不加()
#返回一个函数的返回值 加()
str2 = test()
print(str2)
print(type(str2)) #<class 'str'>
print(type(demo()))#<class 'function'>
print(demo()())#demo()()=test()
结果:我是demo函数
我是test函数
hello
闭包
#嵌套函数,产生闭包问题
#函数嵌套,函数里面还可以定义函数,执行需要被调用
def outer():
print('outer hello')
def inner(): #inner是函数outer内部定义的
print('inner hello')
inner() #inner函数只在outer函数内部可见
outer()
#闭包 = 函数块 + 引用环境 demo(函数块)(引用环境)
# 如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包
def outer(n):
num = n
def inner():
return num+1
return inner
print(outer(3)()) #4
print(outer(5)()) #6
# 修改外部变量的值 闭包里默认不能修改外部变量。
#使用 nonlocal 关键字 进行声明
def outer():
x = 10 #在外部函数里边定义一个变量 局部变量
def inner():
nonlocal x #声明x不再是新增的局部变量 而是外部的局部变量x
x = 5
print(f'inner里边的x的值{x}')
return inner
outer()() #像这样 函数块+引用环境 组成闭包
def outer(num):
m=100#局部变量
print(m)
print('这是outer函数')
def inner():
print('我是inner函数代码')
if num>18:
inner()
return 'hello'
print(outer(19))
# print(m)报错 全局变量不能调用局部变量
# print(inner())报错
代码运行时间
# 时间戳
# 1970-01-01 00:00:00 开始 一直到现在的秒数 注意不是北京时间 UTC
#获取代码开始时间
#start = time.time()
#获取代码结束时间
#end = time.time()
#结束时间-开始时间 = 代码运行的时间
#start-end
import time
start = time.time() #获取的是时间戳
x=0
for i in range(10000000):
x+=i
end = time.time()
print('1到10000000求和用了%.2f秒'%(end-start)) #1到10000000求和用了1.02秒
print(f'1到10000000求和用了{(end-start):.2f}秒') #1到10000000求和用了1.02秒
print(start) #1617029572.8805504
函数优化计算代码运行时间
import time
def cal_time(fn):
start = time.time()
fn()
end = time.time()
# return '1到10000000求和用了%.2f秒'%(end-start)
return f'1到10000000求和用了{(end-start):.2f}秒'
def demo():
x=0
for i in range(10000000):
x+=i
print(x) #求和 49999995000000
def foo():
print('hello')
time.sleep(1) #代表程序睡一秒
print('world')
print(cal_time(demo)) #1到10000000求和用了0.49秒 fn()=demo()调用
print(cal_time(foo))#1到10000000求和用了1.00秒
装饰器的使用
第一步 调用cal_time
第二步 将demo 传给 cal_time
第三步 获取 start 然后执行fn() 也就是demo() demo需要有参数
第四步 这个参数给到inner 游inner 给到 demo()
import time
def cal_time(fn):
print('我是外部函数我被调用了')
print(f'fn={fn}') #fn=<function demo at 0x000001E525D74798> fn=<function foo at 0x000002AD522C48B8>
def inner():
start = time.time()
fn()
end = time.time()
print(f'1到100000求和用了{(end-start):.2f}秒') #1到100000求和用了0.47秒 1到100000求和用了1.00秒
return inner
@cal_time #在执行demo之前 先调用cal_time 第二件事 把demo当作参数传给cal_time
def demo():
x=0
for i in range(10000000):
x+=i
print(x) #求和 49999995000000
@cal_time
def foo():
print('hello')
time.sleep(1) #代表程序睡一秒
print('world')
demo()
foo()
含参
import time
def cal_time(fn):
print('我是外部函数我被调用了')
print(f'fn={fn}')
def inner(x,*args,**kwargs):
start = time.time()
s = fn(x)
end = time.time()
# print(f'1到100000求和用了{(end-start):.2f}秒')
print('1到100000求和用了%.2f秒'%(end-start))
for i in args: #遍历
print(i)
for j,h in kwargs.items(): 遍历字典
print(j,':',h)
return s ,end-start
return inner
@cal_time #在执行demo之前 先调用cal_time 第二件事 把demo当作参数传给cal_time
def demo(n):
x=0
for i in range(1,n):
x+=i
return x
demo(1000000)
print(demo(5000000,'haha','kangbazi',name='666',age=18))
装饰器的应用
def can_play(fn):
def inner(x,y,*args,**kwargs):
ck = kwargs.get('clock',13) #get获取字典 如果不传clock 默认值就是13
if ck<=22:
fn(x,y)
else:
print('gosleep')
return inner
@can_play
def play_game(name,game):
print(f'{name}play{game}') #GDplayWTF
play_game('GD','WTF',clock = 13)