函数/匿名函数

函数的定义

def func():
    print(1)
    print(2)
    print(3)
    return
    print(4)
func()

结果:
1
2
3
4
View Code

定义:def 关键字开头,空格之后接函数名和圆括号(),最后为冒号:,def 是固定的不能改变,空格将def关键字和函数名分开,函数名的命名规则和变量一样

调用:就是 函数名()

rerutn : 当函数遇到return是,函数结束执行

函数的执行流程

函数只有在调用时才会执行,由上到下逐行执行

函数的返回值

return 关键字 ,谁调用就返回给谁

def func():
    s = 1+2
    print(s)
sum1 = func()
print(sum1)
View Code

 不写retnrn时,会默认返回一个None

def func():
    s = 1+2
    print(s)
sum1 = func()
print(sum1)

结果:
3
None
View Code

只写return,后面不写其他内容,也会返回None

def func():
    s = 1+2
    print(s)
    return
sum1 = func()
print(sum1)

结果:
3
None 
View Code

写return和不写return的区别,当函数中遇到return时,此函数结束,不会在继续执行

def func():
    s = 1+2
    return
    print(s)   #print(s)并没有执行
sum1 = func()
print(sum1)

结果:
None
View Code

返回一个值,返回的是值,而不是某个变量,返回的数据类型是其本身的数据类型

def func():
    s = 1+2
    return s,1,2,['a','b']
sum1 = func()
print(sum1)
 结果: 3
View Code

返回多个值

def func():
    s = 1+2
    return s,1,2,['a','b']
sum1 = func()
print(sum1)

结果:
(3, 1, 2, ['a', 'b'])  
View Code

返回的多个值会被组织成一个元组被返回,也可以用多个值来接受

def func():
    return 1,2,['q','w'],3
a,b,c,d = func()
print(a,b,c,d)
结果:
1 2 ['q', 'w'] 3
View Code

注意:return和返回值之间要有空格,可以返回任意数据类型的值

 函数的参数

 参数:也就是函数括号里的内容  函数在调用的时候指定一个具体的变量的值 就是参数

def func(n):    #形参
    print("hello"+n)
func("world")  #实参    #将wolrd传入到n的过程叫传参
View Code

传入多个参数,参数之间用逗号分隔

def func(x,y):
    max1 = x if x > y else y
    return max1
n = func(3,4)
print(n)
View Code

位置参数

按照位置传值,实参的角度

def func(x,y):
    # 此时 x=3 y=4
    max1 = x if x > y else y
    return max1
n = func(3,4)
print(n)
View Code

按照关键字传值

def func(x,y):
    # 此时 x=4 y=3
    max1 = x if x > y else y
    return max1
n = func(y=3,x=4)
print(n)
View Code

混合传参

def func(x,y):
    # 此时 x=4 y=3
    max1 = x if x > y else y
    return max1
n = func(4,y=3)
print(n)
View Code

注意:位置参数必须在关键字参数前面,对于一个形参只能赋值一次

默认参数

将变化比较小的值设置为默认参数

默认参数

def func(name,state = "CN"):
    print(name,state)
func('wanglan')
View Code

想要修改默认参数,传值即可

def func(name,state = "CN"):
    print(name,state)
func('wanglan','USA')
View Code

默认参数陷阱

def func(a,l=[]): # 当函数执行时,发现有默认参数,会在内存中生成一个列表,l=[]只会创建一次,并不会多次创建,在函数内部使用时相当于全局变量,只是其它函数无法使用
    l.append(a)
    print(l)
func(1) #当函数调用时,会在列表中添加1
func(2) #第二次调用,会继续添加
func(3) #第三次调用,继续添加

结果:
[1]
[1, 2]
[1, 2, 3]
View Code
def func(a,l=[]): #只要是默认参数是一个可变数据类型,通过默认参数对其修改,修改的就是同一个
    l.append(a)
    print(l)
func(1) #使用默认参数修改
func(2,[]) #不在使用默认参数,传入一个空列表
func(3)  #使用默认参数修改

结果:
[1]
[2]
[1, 3]
View Code

动态位置参数

 按位置传值多余的参数由args统一接受,保存成一个元组的形式

def func(*args):
    print(args)
func('Hello','world','wang','lan')

结果:
('Hello', 'world', 'wang', 'lan')  #收到的结果是一个元组
View Code

注意:动态参数要写在位置参数后面

 动态默认参数

 按默认传值多余的参数由kwargs统一接受,保存成一个字典的形式

def func(**kwargs):
    print(kwargs)
func(a = 'Hello',b = 'world',c = 'wang',d = 'lan')

结果:
{'a': 'Hello', 'b': 'world', 'c': 'wang', 'd': 'lan'}  #收到的结果是一个字典
View Code

最终顺序: 位置参数 > *args(动态位置参数)  > 默认值参数 > **kwargs(动态默认参数)

 其他传参方式

 接受所有的参数

def func(*args,**kwargs):
    print(args,kwargs)
 func(1,23,5,a=1,b=6)
View Code

动态参数其他传参

st = [1,4,7]
# 方法一
def func(*args):
    print(args)
 func(lst[0],lst[1],lst[2])
 
# 方法二
def func(*args):# 在形参的位置上用*把收到的参数组合成一个元祖
    print(args) 
func(*lst)  #在实参的位置上用*将lst(可迭代对象)按照顺序打散
View Code

字典也可以进行打散,不过需要**

def func(**kwargs):
    print(kwargs)  #返回字典
func(**dic)


def func(**kwargs):
    print(*kwargs) #加上*返回的就是字典的key
func(**dic)
View Code

命名空间和作用域

 在python解释器开始执行之后, 就会在内存中开辟一个空间, 每当遇到一个变量的时候, 就把变量名和值之间的关系记录下来, 但是当遇到函数定义的时候, 解释器只是把函数名读入内存, 表示这个函数存在了,  至于函数内部的变量和逻辑, 解释器是不关心的. 也就是说一开始的时候函数只是加载进来, 仅此而已, 只有当函数被调用和访问的时候, 解释器才会根据函数内部声明的变量来进行开辟变量的内部空间. 随着函数执行完毕, 这些函数内部变量占用的空间也会随着函数执行完毕而被清空

def fun():   
    a = 10
    print(a)
fun()
print(a)    # a不不存在了了已经

结果:
NameError: name 'a' is not defined
View Code

命名空间:
    内置命名空间 :作用域 全局和局部,加载是在运行之后,代码之前
    全局命名空间 :作用域 全局和局部,加载是在运行代码的时候
    局部命名空间 :作用域 在局部,加载是在调用的时候

加载顺序:

    内置命名空间(程序运行前加载)->全局命名空间(程序运行中:从上到下加载)->局部命名空间(程序运行中:调用时才加载

取值 :

    在局部调用:局部命名空间->全局命名空间->内置命名空间 

x = 1
def func():
    x = 2      #局部存在使用局部
    print(x)
func()

结果
2

x = 1
def func():
    x = 2
    def func1():  #不存在调用父级,找到就使用,找不到就使用全局
        print(x)   
    func1()
func()

结果
2
View Code

覆盖 :
    同一个名字 : 局部覆盖全局和内置,全局覆盖内置
    永远不要起和你知道的内置命名空间中重名的名字 

可以通过globals()函数来查看全局作用域中的内容,  也可以通过locals()来查看局部作用域中的变量量和函数信息

def func():
    a = 40
    b = 20
    print("哈哈")
    print(a, b)     # 这里使用的是局部作用域
    print(globals())    # 打印全局作用域中的内容
    print(locals())     # 打印局部作用域中的内容
func()
View Code

函数的嵌套

def f1():
    def f2():
        def f3():
            print("in f3")
        print("in f2")
        f3()
    print("in f1")
    f2()
f1()
View Code
def max2(x,y):
    m  = x if x>y else y
    return m
def max4(a,b):
    res1 = max2(a,b) #调用max2函数
    return res1
n = max4(6,2)
print(n)
View Code

global和nonlocal

global:在局部改全局

a = 10
def func():   
    global a    # 加了个global表示将局部变量改为全局变量
    a = 20   
print(a)
func()
print(a)
View Code

nonlocal:在小局部改大局部,两个局部之间一定有嵌套关系(修改父级变量),如果父级没有继续向上找,直到函数的第一层,如果还没有就保错,nonlocal不能修改全局变量

def f1():
    a = 1
    def f2():
        nonlocal a  #更改父级变量
        a = 2   #将父级变量的a=1 修改为a =2 
    f2()
    print('a in f1 : ',a)

f1()
View Code

函数名的本质

1. 函数名可以被引用

def func():
    print('in func')
f = func
print(f)
View Code

2函数名可以被当作容器类型的元素

def f1():
    print('f1')


def f2():
    print('f2')


def f3():
    print('f3')

l = [f1,f2,f3]
d = {'f1':f1,'f2':f2,'f3':f3}

#调用
l[0]()
d['f2']()
View Code

3.函数名可以当作函数的参数和返回值,就是可以当普通变量用

def login_failed():
    print('登陆失败')

def index():
    print('欢迎来到首页')

def login(usr,pwd):
    if usr == 'wanglan' and pwd == '123':
        return index
    else:
        return login_failed
res_func = login('wanglan','123')
res_func()
View Code

4.函数名可以作为函数的参数

def login():
    print('欢迎登陆')

def index(auth):
    auth()
    print('欢迎来到首页')

index(login)
View Code

闭包

内部函数使用了外部函数的变量,内部函数就是一个闭包

def func():
    name = 'wanglan'
    def inner():
        print(name)

闭包常用的用法

def func():
    name = 'wanglan'
    def inner():
        print(name)
    return inner
f = func()
f()
View Code

可以通过__closure__ 来查看是不是闭包,有值就是,没值就不是

def func():
    name = 'wanglan'
    def inner():
        print(name)
    print(inner.__closure__)
    return inner
f = func()
f()
View Code

闭包嵌套

def wrapper():    #1加载
    money = 1000
    def func():    #3.加载
        name = 'wanglan'
        def inner():  #6.加载
            print(name,money) #9.打印
        return inner  #7.返回内存地址
    return func   #4.返回内存地址
f = wrapper()  #2.调用
i = f() #5.调用
i() #8.调用
View Code

匿名函数

匿名函数:为了解决那些功能很简单的需求而设计的一句话函数

 def calc(n):
    return n ** n
print(calc(10))

# 换成匿名函数
calc = lambda n: n ** n   #lambda:关键字   n:形参   n ** n :返回值,就是return后面的内容
print(calc(10))
View Code

 

小结

函数的定义规则

1.定义:def 关键词开头,空格之后接函数名称和圆括号()。
2.参数:圆括号用来接收参数。若传入多个参数,参数之间用逗号分割。
    参数可以定义多个,也可以不定义。
    参数有很多种,如果涉及到多种参数的定义,应始终遵循位置参数、*args、默认参数、**kwargs顺序定义。
    如上述定义过程中某参数类型缺省,其他参数依旧遵循上述排序
3.注释:函数的第一行语句应该添加注释。
4.函数体:函数内容以冒号起始,并且缩进。
5.返回值:return [表达式] 结束函数。不带表达式的return相当于返回 None

def 函数名(参数1,参数2,*args,默认参数,**kwargs):
        """注释:函数功能和参数说明"""
        函数体
        ……
        return 返回值
View Code

函数的调用规则

1.函数名()
    函数名后面+圆括号就是函数的调用。
2.参数:
    圆括号用来接收参数。
    若传入多个参数:
        应按先位置传值,再按关键字传值
        具体的传入顺序应按照函数定义的参数情况而定
3.返回值
    如果函数有返回值,还应该定义“变量”接收返回值
    如果返回值有多个,也可以用多个变量来接收,变量数应和返回值数目一致

无返回值的情况:
函数名()

有返回值的情况:
变量 = 函数名()

多个变量接收多返回值:
变量1,变量2,... = 函数名()
View Code

命名空间

一共有三种命名空间从大范围到小范围的顺序:内置命名空间、全局命名空间、局部命名空间
小范围的可以用大范围的
但是大范围的不能用小范围的
范围从大到小(图)

在小范围内,如果要用一个变量,是当前这个小范围有的,就用自己的
如果在小范围内没有,就用上一级的,上一级没有就用上上一级的,以此类推。
如果都没有,报错

函数的嵌套:

  嵌套调用

  嵌套定义:定义在内部的函数无法直接在全局被调用

函数名的本质:

  就是一个变量,保存了函数所在的内存地址

闭包:

  内部函数包含对外部作用域而非全剧作用域名字的引用,该内部函数称为闭包函数

 

 

posted @ 2018-11-03 22:49  答&案  阅读(325)  评论(0编辑  收藏  举报