一、函数的初识
函数是以功能为导向,函数内部尽量不要有print
def func(): #def 关键字,定义函数,空格 函数名(变量)
# 函数体
return 1,2,[123,2]
ret1,ret2,ret3 = func() #函数名 + ()就要执行此函数
print(ret1,ret2,ret3)
二、return 功能
1.函数里面遇到return,此函数结束,下面就不再走了,终止函数
2.return 返回值: 不写return None
return None
return 单个
return 多个 将多个值包在元组中,返回给调用者,然后打印出打印者的值
例子1
def func():
count = 2
l1 = []
l1.append(count)
return l1,2,count
ret = func()
# print(ret) 元组类型
ret1,ret2,ret3 = func()
print(ret1,ret2,ret3)
三、函数的传参
1.函数的参数分为实体参数和形式参数
def my_len(x): #形参:形式参数
count = 0
for i in l1:
count += 1
return count
l1 =[1,2,3,4,5,6]
ret = my_len(l1) #实参:实体参数
print(ret)
2.实参:实体参数
从实参的角度:
(1)按位置传参,必须一一对应。
例子1
def func(x):
if len(li) > 2:
return True
else:
return False
li = [1,2,3,4]
print(func(li))
例子2
def func(x,y):
# if x > y:
# return x
# else:
# return y
z = x if x > y else y #三元运算法
return z
i = 5
j = 6
print(func(i,j))
(2)按关键字传参
def func(x,y):
z = x if x > y else y #三元运算法
return z
func(y = 2,x = 3)
(3)混合传参,位置参数在前面,关键字传参在后
def func(x,y,a,b):
print(x,y)
print(a,b)
return x,y,a,b
ret = func(1,2,a = 3,b = 4)
print(ret)
2.形参传参:
(1)位置传参
(2)默认参数
例题:
def func(name,sex="男"):
with open("name_list","a",encoding = "utf-8") as f1:
f1.write("{},{}".format(name,sex))
while 1:
name = input("请输入名字=")
if "xue" in name:
sex = input("请输入性别")
func(name,sex)
else:
func(name)
name = input("请输入名字")
sex = input("请输入性别")
print(func(name))
四、函数的动态传参
1、 *args 动态参数,不定长参数
他包含了你所有的位置参数,打印出来的元素类型是是元组类型
args 需要放在位置参数前,否则会报错
例子1
args 需要放在位置参数前,否则会报错
def func(a,b,c,*args):
print(a,b,c,*args)
func(1,2,3,4,5,6)
例子2
def func(*args):
print(args,type(args))
func(1,2,3,4,"alex",5)
例子3
def func(*args):
sum = 0
for i in args:
sum = sum + i
return sum
print(func(1,2,3,6,78))
例子4
def func(*args):
print(args,type(args))
func(1,2,"alex",3,4,5,6,7,8) #(1, 2, 'alex', 3, 4, 5, 6, 7, 8) <class 'tuple'>
*args不给他传参,也不会报错,是个空元组
def func(a,b,c,*args):
print(a) #1
print(b) #2
print(c) #alex
print(args,type(args)) #()
func(1,2,"alex")
位置参数,*args,默认参数
def func(a, b, c,*args, sex= "nan"):
print(a) #1
print(b) #2
print(c) #3
print(sex) #女
print(args) #(4, 5, 6, 5, 7)
print(a,b,c,sex,args)
func(1,2,3,4,5,6,5,7,sex = "女")
2、**kwargs()默认参数
例子1:打印出来的是字典数据类型,实参接受不定长的关键字参数
def func(**kwargs):
print(kwargs)
func(a = 1 , b = 2, c = 3) #{'a': 1, 'b': 2, 'c': 3}
例子2:位置参数,*args,默认参数,**kwargs
def func(a,b,c,*args,sex="nan",**kwargs):
print(a)
print(b)
print(c)
print(args,type(args)) #(4, 5, 6, 5, 6, 4) <class 'tuple'>
print(sex) #nv
print(kwargs,type(kwargs)) #{'name': 'taibai', 'name2': 'taibai2'} #字典类型
func(1,2,3,4,5,6,5,6,4,sex = "nv",name = "taibai",name2 = "taibai2")
例子3:万能参数
def func(*args,**kwargs):
print(args)
print(kwargs)
func(1,2,3,4,5,name = "alex",age =15 )
3、魔法运算:打散
*args传入一个可迭代的对象就可以打散
例子1:
def func2(*args,**kwargs):
print(args)
print(kwargs)
l1 = [1,2,3]
l2 = [1,2,3,4,5,6,7]
func2(*l1,*l2)
例子2:*args
def func(*args,**kwargs):
print(args,type(args))
print(kwargs,type(kwargs))
dic1 = {"name":"alex","name1":"xue"}
dic2 = {"a":1,"b":2,"c":3}
func(*dic1,*dic2) #('name', 'name1', 'a', 'b', 'c') <class 'tuple'>
**kwargs传入对象被打散
def func(*args,**kwargs):
print(args,type(args))
print(kwargs,type(kwargs))
dic1 = {"name":"alex","name1":"xue"}
dic2 = {"a":1,"b":2,"c":3}
func(**dic1,**dic2, name3 = "xue")
结果
() <class 'tuple'>
{'name': 'alex', 'name1': 'xue', 'a': 1, 'b': 2, 'c': 3, 'name3': 'xue'} <class 'dict'>
五、python的内部原理
python代码运行的时候
从python解释器开始执行之后,就可以在内存中开辟了一个空间,
每当遇到一个变量的时候,就把变量名和值之间对应的关系记录起来。
但是当遇到函数定义的时候,解释器只是象征性的将函数名读在内存,表示知道这个函存在了。
至于函数内部的变量和逻辑,解释器根本不关心。
等执行函数调用的时候,python解释器会再开辟一块内存储存这个函数里面的内容,
这个时候,才关注函数里面有哪些变量,而函数中的变量会储存再新开辟出来的内存中,
函数中的变量只能在函数内部使用,并且会随着函数执行完毕,这块内存的所有内容也会被清空。
“存放名字和值的关系“” 的空间 起了一个名字 命名空间
代码在运行开始,创建的存储“变量名和值的关系”的空间叫做 全局命名空间
在函数的运行中开辟的临时的空间叫做 局部命名空间
六、命名空间
命名空间:名称空间,全局名称空间,局部名称空间,内置名称空间
内置命名空间:input print sum len
加载顺序:内置名称空间---》全局名称空间 ---》局部名称空间(执行函数时)
取值顺序:局部空间找---》全局名称空间---》内置名称空间找
例子1:
name = "wusir"
def func():
name = "alex"
print(name) #alex
func()
例子2:
name = 1
def func():
n = 2
print(666) #NameError: name 'n' is not defined
print(n)
例子3:return后面是什么就返回什么
def len(x):
return x
print(len([1,2,3])) #[1, 2, 3]
七、作用域
作用域就是作用范围,按照生效范围可以分为全局作用域和局部作用域
全局作用域:全局名称空间,内置名称空间。在整个文件的任意位置都能被引用、全局有效
局部作用域:局部名称空间,只能在局部范围内生效
name = "wusir"
print(globals())
def func():
name = "alex"
# print(globals())
print(locals()) #{'name': 'alex'}
func()
def func1():
print(222)
def func2():
print(111)
func1() #222
func2() #name 'func2' is not defined
例子2:
def func1():
print(111)
def func2():
print(222)
def func3():
print(444)
func2() #222
例子3:
print(111)
def func2():
print(222)
def func3():
print(666)
print(444)
func3()
print(888)
print(333)
func2()
print(555)
八、global:
1.声明一个全局变量
2.在局部作用域想要对全局作用域的全局变量进行修改时,需要global(限于字符串、数字)
在局部作用域,对全局变量进行修改
def func():
global a
a = 3
func()
print(a) # 3
例子2
count = 1
def search():
global count
count = 2
search()
print(count) #2
对可变数据类型(list,dict,set)可以直接引用不用通过global
l1 = [1,2,3] def func(): l1.append(444) func() print(l1) #[1, 2, 3, 444]
九、nonlocal:
1.不能修改全局变量
2.在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的那层,
从那层及以下此变量全部发生改变。
例子1 def add_b(): b = 42 def do_global(): b = 10 print(b) def dd_nonlocal(): nonlocal b b = b + 20 print(b) dd_nonlocal() print(b) do_global() print(b) add_b() 例子2: a = 1 def func(): nonlocal a a = 2 print(a) func() #SyntaxError: no binding for nonlocal 'a' found 例子2: def func(): name = "wusir" def inner(): nonlocal name name = "taibai" print(name) inner() print(name) func()
十、补充知识:
陷阱参数
def func(name,l = []):
l.append(name)
return l
print(func("alex")) #['alex']
print(func("wusir")) #多次调用函数,保存了上次的值 #['alex', 'wusir']