python函数总结二

一、 作用域

1、作用域定义

①、全局作用域:在整个程序运行环境中都可见
②、局部作用域:在函数、类等内部可见;局部变量使用范围不能超过其所在的局部作用域

def lovepy():
    x = 1 #局部作用域,在lovepy内
def text():
    print(x) #错误事例,因为x是lovepy中变量,在其它局部作用域无法对其调用

print(x) #错误事例,因为x是lovepy中变量,在外部无法调用

2、全局变量global

①、使用global将函数内(局部作用域)中某一个变量声明为使用外部的全局作用域定义的变量
②、全局作用域中必须有变量的定义
③、函数的目的就是隔离,因此global尽量不要使用。说明只是为了更好的理解作用域
④、如果函数想使用全局变量,请用函数形参传参解决

#例1
x = 1
def lovepy1():
    x = 2
    return x #x输出为2为什么
print(lovepy1())

从例1:对于函数内变量的调用原则:先自己内部找然后往上找,不会向下找

#例2
y = 1
def lovepy2():
    global y
    y = 2
    return y # y输出为2为什么,如果把y=2放在global前为什么会报错
print(lovepy2()
print(y) #输出为2

例2:上述的过程是,声明lovepy2中y是全局变量y,然后又把y从新赋值为y,最后其实改变的是全局变量中的y。而把y = 2放在前面,则在全局声明前将y给了2。(后续博客会专门来说python中变量赋值,和其它语言的差别)

#例3
z = 1
def lovepy3():
    global z
    z += 1
    return z # z输出为2为什么,如果不加global,为什么会报错
print(lovepy3())

例3:如果不声明global z 则在z +=1 时会报错,原因是z +=1,是先引用后赋值(如果不加global声明,本地环境又没有这个变量)。对于python而言,动态语言是赋值才算定义,才能被引用(后续会和例2专门统一一节来讲)

3、nonlocal关键字

①、使用nonlocal关键字,将变量标记为在上级作用域中定义,但不能是全局作用域中定义

#例1;错误事例,nonlocal只能在局部作用域中使用
a = 0
def lovepy1():
    nonlocal a
    a += 1
    return a
print(lovepy1())


#例2
def lovepy2():
    a = 0
    def py():
        nonlocal a
        a += 1
        return a
    return py
a = lovepy2()
print(a(),a()) # 输出为 1,2
print(lovepy2()(),lovepy2()()) # 输出为1,1
#思考两个print输出不同的原因,在本章闭包中会说

4、默认值作用域

①、对于python来说,一切皆对象。
②、对于函数来说,可变类型默认值,就可能修改这个默认值
③、有时候这种特性是好的,有时候不好有副作用。如何做到按需改变,一般有两种方法:1、影子copy 2、通过值的判断灵活创建传入对象

例一:理解默认值作用域

#例1:
def lovepy1(a = []): 
    a.append(1)
    return a
print(lovepy1())  #输出[1]
print(lovepy1.__defaults__)
print(lovepy1([2,3,4])) #输出[2,3,4,1]
print(lovepy1.__defaults__)
print(lovepy1()) #输出[1,1]
print(lovepy1.__defaults__)
print(lovepy1([2,3,4])) #输出[2,3,4,1]
print(lovepy1.__defaults__)
#思考如果缺省值是b = 1效果是怎样的?还会出现上面类似的结果吗

对于例1来说:(1)函数lovepy1(),其本身就是个对象,因此默认值放在属性中会伴随着整个函数的整个生命周期。这里要知道lovepy1()整体才是一个函数。而lovepy1只是标识符。(2)、可以使用 (函数标识符.defaults)属性,查看上例活动过程。

例2:影子copy方法,使用影子copy创建一个新的对象,永远不能改变传入的参数

#例2:
def lovepy2(b = []): 
    b = b[:] #了解 b = b[:] 和b = b.copy()和b = b之间关系
    b.append(1)
    return b
print(lovepy2())  #输出[1]
print(lovepy2([2,3,4])) #输出[2,3,4,1]
print(lovepy2()) #输出[1]

例3:使用不可变类型的默认值

#例3:
def lovepy3(c = None):
    if c is None:
        c = []
    c.append(1)
    return c
print(lovepy3())  #输出[1]
print(lovepy3()) #输出[1]

从例三:(1)、如果使用缺省值None就创建一个列表,如果传入一个列表,就直接修改这个列表。(2)、这种方式更加灵活,很多函数的定义,都可以看到使用None这个不可变的值作为默认参数,可以说这是一种惯用法。

二、闭包

1、相关定义。

①、自由变量:未在本地作用域中定义的变量。例如定义在内存函数外的外层函数作用域的变量
②、闭包:就是一个概念,出现在嵌套函数中,指的是内层函数引用外层函数的自由变量,就行形成了闭包。

2、函数调用函数

#例1:
def lovepy1():
    return lovepy2

def lovepy2():
    return ("他是大聪明")
    
print(lovepy1()()) #输出他是大聪明

3、闭包

#例2:
def lovepy2():
    b = [0]
    def love():
        b[0] += 1 #报错吗,为什么
        return b[0]
    return love
c = lovepy2()
print(c()) #输出1
print(c()) #输出2
b = 10  
print(c())  #输出3
print(lovepy2()())   #输出1,为什么
print(lovepy2()())   #输出1,为什么

从例2:(1)、对于闭包无法直接访问外部函数的局部变量,因此大多会使用容器将上层局部变量传递进去。如例中的b = [0],其实我想实现的是b = 0传递下去。(2)、也可以使用nonlocal关键字,传递变量 (3)、当闭包执行完后,仍然能够保持住当前的运行环境。这就是和lovepy2()()和例1的区别。

4、闭包的作用

①、当闭包执行完后,仍然能够保持住当前的运行环境。
②、闭包可以根据外部作用域的局部变量来得到不同的结果。

三、全局函数的销毁

1、重新定义同名函数

def lovepy():
    return "他是大聪明"

def lovepy():  #覆盖了上面的函数,其实python也有多态,后续在说
    pass
print(lovepy())

2、del 语句删除函数对象

def lovepy():
    return "他是大聪明"

def lovepy():
    pass
    
print(lovepy())
del lovepy
print(lovepy())

3、程序结束时

四、局部函数销毁

1、重新在上级作用域定义同名函数

def lovepy():
    a = 1
    def love():
        nonlocal a
        a +=1
        return a
    def love():
        nonlocal a
        a +=10
        return a
    return love

foo = lovepy()
print(foo())

2、上级作用域销毁

def lovepy():
    a = 1
    def love():
        nonlocal a
        a +=1
        return a
    return love

foo = lovepy()
print(foo())
del foo
print(foo())

3、del语句删除函数对象

def lovepy():
    a = 1
    def love():
        nonlocal a
        a +=1
        return a
    del love
    return love

foo = lovepy()
print(foo())

下一章节讲函数装饰器

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值