def | return | *args | **kwargs | lambda …
# 定义
def 函数名(形参):
函数体
if xxx:
return 返回值
else:
return 返回值
# 调用
返回值 = 函数名(实参)
[1,4,5,6,112,445,656] 调用函数,计算任意一个数字列表的和
# 列表求和
li = [1, 2, 3, 4, 1.2, 3.4, 9.12]
def sum_li(li):
sum_num = 0
for i in li:
sum_num += i
return sum_num
res = sum_li(li)
print(res)
升级 如果传过来的数据类型是一个字典 {‘key’:[1,2,3],‘k2’:[1234,4566]}
# 字典值求和
def sum_li(li):
sum_num = 0
for i in li:
sum_num += i
return sum_num
def sum_dict(dic):
sum_num = 0
for k in dic:
sum_l = sum_li(dic[k])
sum_num += sum_l
return sum_num
dic = {'k1': [1, 2, 3, 4], 'k2': [5, 6, 7, 8]}
res = sum_dict(dic)
print(res)
login函数
# 完成3次登录,如果登录成功,返回True,如果登录失败,返回False
# 结合文件操作完成
# 用户信息存储
with open('user_info', mode='w', encoding='utf-8') as f:
f.write('admin|admin\n')
f.write('andy|andy\n')
def login():
login_times = 3
while login_times > 0:
login_times -= 1
user = input('请输入用户名:')
pwd = input('请输入密码:')
with open('user_info', mode='r', encoding='utf-8') as f:
for line in f:
name, password = line.strip().split('|')
if user == name and pwd == password:
return True
if login_times > 0:
print(f'用户名或密码错误,你还有{login_times}次机会')
else:
print('登录失败!')
user_login = login()
if user_login:
print('登录成功!')
函数的返回值:默认是None,可以是任意数据类型。
return 返回值有几种情况:分别是没有返回值、返回一个值、返回多个值
#函数定义
def mylen():
"""计算s1的长度"""
s1 = "hello world"
length = 0
for i in s1:
length = length+1
print(length)
#函数调用
str_len = mylen()
#因为没有返回值,此时的str_len为None
print('str_len : %s'%str_len)
# 11
# str_len : None
只写return,后面不写其他内容,也会返回None
def ret_demo():
print(111)
return
print(222)
ret = ret_demo()
print(ret)
# 111
# None
#函数定义
def mylen():
"""计算s1的长度"""
s1 = "hello world"
length = 0
for i in s1:
length = length+1
return length
#函数调用
str_len = mylen()
print('str_len : %s'%str_len)
# str_len : 11
return和返回值之间要有空格,可以返回任意数据类型的值
def ret_demo1():
'''返回多个值'''
return 1,2,3,4
def ret_demo2():
'''返回多个任意类型的值'''
return 1,['a','b'],3,4
ret1 = ret_demo1()
print(ret1)
# (1, 2, 3, 4) # 元组
ret2 = ret_demo2()
print(ret2)
# (1, ['a', 'b'], 3, 4)
返回的多个值会被组织成元组被返回,也可以用多个值来接收
def ret_demo2():
return 1,['a','b'],3,4
# 返回多个值,用一个变量接收
ret2 = ret_demo2()
print(ret2)
# (1, ['a', 'b'], 3, 4)
# 返回多个值,用多个变量接收
a,b,c,d = ret_demo2()
print(a,b,c,d)
# 1 ['a', 'b'] 3 4
# 用多个值接收返回值:返回几个值,就用几个变量接收
a,b,c,d = ret_demo2()
print(a,b,c,d)
# 1 ['a', 'b'] 3 4
补充:为啥 多个 元素就被返回 成元组了呢??
>>> 1,2 # python中把用逗号分割的多个值就认为是一个元组。
(1, 2)
>>> 1,2,3,4
(1, 2, 3, 4)
>>> (1,2,3,4)
(1, 2, 3, 4)
#序列解压一
>>> a,b,c,d = (1,2,3,4)
>>> a
1
>>> b
2
>>> c
3
>>> d
4
#序列解压二
>>> a,_,_,d=(1,2,3,4)
>>> a
1
>>> d
4
>>> a,*_=(1,2,3,4)
>>> *_,d=(1,2,3,4)
>>> a
1
>>> d
4
#也适用于字符串、列表、字典、集合
>>> a,b = {'name':'eva','age':18}
>>> a
'name'
>>> b
'age'
参数的分类:形参和实参
#函数定义
def mylen(s): # 形式参数,形参
"""计算s的长度"""
length = 0
for i in s:
length = length+1
return length
#函数调用
str_len = mylen("hello world") # 实际参数,实参
print('str_len : %s'%str_len)
# str_len : 11
参数可以传递多个,多个参数之间用逗号分割
def mymax(x,y):
the_max = x if x > y else y
return the_max
ma = mymax(10,20)
print(ma)
# 20
实参,可以是任意数据类型,实参和形参的个数是一一对应的
def mymax(x,y): # 10 --> x ; 20 --> y
#此时x=10,y=20
the_max = x if x > y else y
return the_max
ma = mymax(10,20) # 10 --> x ; 20 --> y
print(ma)
# 20
def mymax(x,y):
#此时x = 20,y = 10
print(x,y)
the_max = x if x > y else y
return the_max
ma = mymax(y = 10,x = 20)
print(ma)
def div(a,b,c):
print(a) # 4
print(b) # 4
print(c) # 2
ret = div(4,c = 2,b = 4)
print(ret)
总结:
问题一: 位置参数必须在关键字参数的前面
问题二: 对于一个形参只能赋值一次
位置参数必须传值
def mymax(x,y):
#此时x = 10,y = 20
print(x,y)
the_max = x if x > y else y
return the_max
#调用mymax不传递参数
ma = mymax()
print(ma)
#结果
TypeError: mymax() missing 2 required positional arguments: 'x' and 'y'
将变化比较小的值设置成默认参数
def stu_info(name, country = "CN"):
"""打印学生信息函数,由于班中大部分学生国籍都是中国,
所以设置默认参数 country 的默认值为'CN'
"""
print(name,country)
# 这里,默认参数在调用时不指定,那默认就是CN,指定了的话,就用你指定的值
stu_info('admin')
# admin CN
stu_info('andy','EN')
# andy EN
【Interview questions】
这块就看 你对 函数 执行顺序 是否 真正了解 ??
执行顺序:从上往下 顺序执行,当程序 走到 def 函数定义时先划分def涉及到的内存空间,然后继续往下运行,直到函数被调用时,才会给函数其内部划分出内存空间。
l = []
def func(a,l=l):
l.append(a)
print(l)
func(1) # [1]
func(2) # [1, 2]
func(3) # [1, 2, 3]
def func(a,l=[]):
l.append(a)
print(l)
func(1) # [1]
func(2,[]) # [2]
func(3) # [1,3]
动态参数也称为非固定参数,若你的函数在定义时不确定用户想传入多少个参数,就可以使用动态参数
*args 会把多传入的参数变成一个 元组 形式
def stu_register(name,age,*args): # *args 会把多传入的参数变成一个元组形式
print(name,age,args)
stu_register("andy",22)
# 输出
# andy 22 () # 后面这个()就是args,只是因为没传值,所以为空
stu_register("Jack",32,"CN","Python")
# 输出
# Jack 32 ('CN', 'Python')
**kwargs 会把多传入的 关键字参数 变成一个 字典 形式
def stu_register(name,age,*args,**kwargs): # *kwargs 会把多传入的参数变成一个dict形式
print(name,age,args,kwargs)
stu_register("andy",22)
# 输出
# andy 22 () {} # 后面这个{} 就是kwargs,只是因为没传值,所以为空
stu_register("Jack",32,"CN","Python",sex="Male",province="ShangHai")
# 输出
# Jack 32 ('CN', 'Python') {'province': 'ShangHai', 'sex': 'Male'}
def print_info(*args, **kwargs):
print('info'.center(30, '-'))
print(f'Name:{kwargs["name"]}')
print(f'Age:{kwargs["age"]}')
hobby = kwargs["hobby"] if 'hobby' in kwargs.keys() else 'piano'
print(f'Hobby:{hobby}')
print_info(name='andy', age=18)
print_info(name='jack', age=23, hobby='学习')
参数的分类:形参和实参
# 参数是没有固定的名字的,顺序是必须固定的
# print(1,2,3,4,5)
# print(*list)
# 顺序是不固定的,参数的名字是固定的
# open(url = '',mode = '',encoding='')
# open(**{'url':'','mode':'r','encoding':''})
# 必须位置参数在前,关键字参数在后
# 同一个关键字不能被传两个值
# *list *tuple 将列表中的值一个一个取出来,按照位置传递参数
# **dict 将字典中的key、value值一个一个取出来变成key=value的形式,按照关键字传递参数
# 所有除了位置参数接收的其他按照位置传递来的参数
# args就是一个元组
# 如果用户传了,就用用户传的
# 如果用户没传,就用默认的
# 陷阱
# def func(l = [],d = {}): # 大部分情况下都不成立
# pass
# 所有除了位置参数、默认参数之外其他按照关键字传递而来的参数
# kwargs就是一个字典
函数名的本质 就是一个内存地址,在我们的程序中 所有的值、变量都有一个所在的内存地址
# 本质就是一个内存地址
# 内存地址+()就是执行这个函数
# 函数名可以赋值、可以作为其他容器类型的元素
def func1():
print(123)
def func2():
print(234)
print(func1) # 函数名的本质 就是一个内存地址
#
def func1():
print(123)
a = func1
a() # 123
print(a) #
print(func1) #
def func1():
print(123)
def func2():
print(234)
# 1、列表方式调用执行
l = [func1,func2]
l[0]() # 输出 123
l[1]() # 输出 234
# 2、循环调用执行
for i in l:
i()
# 输出 123
# 输出 234
1、命名空间:内置的命名空间、全局的命名空间、局部命名空间
2、作用域
3、两个关键字(在内部打破了外部的生态、尽量的少用)
4、刚才提到函数及程序的加载顺序:
# 所有的函数名的本质都是内存地址
# 所有的变量到底是什么时候被加载到内存里来的?
print(123) # 最先加载的就是内置的函数、变量
# 再从上到下将函数名、变量名加载到内存中
a = 1
b = 2
print(a,b)
def func(): # 在函数调用的过程中,才分配一块空间,在函数内部使用
print(a) # 在函数的内部可以引用函数外部的变量
print(b)
func()
a = 1
a = 2
print(a)
# 程序的加载顺序,加载进来的都是全局变量
# 1.先加载内置的名字
# 2.继续加载文件级别(在函数外部定义的)
# 函数的加载
# 函数内部的变量进入内存需要通过调用
# 函数内部的数据会随着函数的结束而被销毁
# 函数内部的数据是不可以在外部被使用的
举例:程序从上往下执行的执行顺序
a = 1
def func():
b = 2
print('in func', a, b)
def inner():
print('in inner', a, b)
inner()
func()
# 输出
# in func 1 2
# in inner 1 2
# 从局部作用域来说,内部的作用域永远可以引用外部作用域中的变量
红线代表第一次程序加载(加载全局变量,函数的定义,函数的执行,注意函数定义可变参数的陷阱),青色代表是调用 func 函数内加载,紫色代表 函数 func 内部调用 inner 函数加载顺序
举例:局部变量 与 全局变量的 关联 情况
a = True
def func():
a = False
return a
ret = func()
print(ret) # False ,因为只是修改函数内部的 a ,并未修改全局变量 a
print(a) # True ,全局变量 a 从未被修改过
变量关系 大概 如下,内层的变量总是可以使用外层的变量,反之不行。就好比,你可以使用你、你爸、你爷爷、你祖爷爷…的资源,反之不行
a = 10
def func():
b = a - 1 # 引用
print(b) # 9
print(a) # 10
func()
a = 10
def func():
global a # 在一个局部内声明要改变外部的变量
a = a - 1 # 引用
print(a) # 9
func()
print('-->', a) # --> 9
引用并修改当前局部外的最近一层有b的局部的b变量
a = 10
def func():
b = 9
def inner():
nonlocal b # 引用并修改当前局部外的最近一层有b的局部的b变量
b = b - 1
inner()
print('in func', b)
func() # in func 8
a = 10
def func():
b = 9
def inner():
b = 8
def inn():
nonlocal b
b -=1
inn()
print('in inner', b) # 7?8
inner()
print('in func', b) # 9
func()
# in inner 7
# in func 9
当前层的上一层未找到 b,则 继续往上找,直到找到或者未找到报错为止
a = 10
def func():
b = 9
def inner():
def inn():
nonlocal b
b -= 1
inn()
print('in inner', b) #
inner()
print('in func', b) #
func()
# in inner 8
# in func 8
# 局部可以引用全局作用域的变量
# 如果是嵌套函数
# 内部的函数可以引用外部函数中定义的变量
# 可以通过global和nonlocal关键字声明之后修改
# 少用、会有隐患
匿名函数 也叫 lambda 表达式
定义:变量 = lambda 参数:返回值
执行:变量(参数)
普通函数是有名的,而 匿名函数就是不需要显式的指定函数名,即匿名函数是一个表达式,并没有函数名,故又称 lambda 表达式
def wahaha():
pass
print(wahaha.__name__) # 函数名为: wahaha
# 定义:变量 = lambda 参数:返回值
# 执行:变量(参数)
In [10]: func = lambda a,b : a if a > b else b
In [11]: ret = func(1,3)
In [12]: print(ret)
3
In [13]: print(func.__name__)
<lambda>
def cal(a, b):
return a * b
print(cal(2, 3))
cal = lambda a, b: a * b
print(cal(2, 3))
1、先熟悉下 map() 函数
map(函数, 可迭代的数据类型)
ret = map(lambda a: a ** 2, [1, 2, 3, 4])
for i in ret:
print(i)
输出
1
4
9
16
# lambda表达式
# 变量名 = lambda 参数1,参数2 : 返回值or有返回值的表达式
# 返回值 = 变量名(实参1,实参2)