zoukankan      html  css  js  c++  java
  • Python 函数的作用域

    作用域

    标识符的可见范围就是作用域,也就是常说的变量的作用域

     全局作用域

    在整个代码运行环境内都可见

    举例

    x = 5
    
    def fn():
        print(x)
    
    fn()

    运行结果

    5

    局部作用域

    在函数、类内部可见。局部变量的范围不能超过其所在的局部作用域

    def fn():
        x = 5
        return x
    
    print(fn())

    运行结果

    5

    错误的使用作用域(函数内部变量不能被外部引用)

    def fn():
        x = 5
        return x
    
    print(fn())
    
    def fn1():
        print(x)           ## 这里上面fn函数中的x对fn1函数不可见
    
    print(fn1())
    print(x)               ## x对全局不可见

    嵌套函数中的作用域

    def outer():
        x = 10
    
        def inner():
            print("inner {}".format(x))
    
        print("outer {}".format(x))
        inner()
    
    
    outer()

    运行结果

    outer 10
    inner 10

    与上面函数中x变量的对比

    def outer():
        x = 10
    
        def inner():
            x = 5
            print("inner {}".format(x))
    
        print("outer {}".format(x))
        inner()
    
    
    outer()

    运行结果

    outer 10
    inner 5

    换一个执行顺序理解

    def outer():
        x = 10
    
        def inner():
            x = 5
            print("inner {}".format(x))
    
        inner()
        print("outer {}".format(x))
    
    
    outer()

    运行结果

    inner 5
    outer 10

    从结果可以看出:

    (1)外层变量 x 的作用域在内层函数中可见

    (2)内层函数中定义了变量 x,是重新定义的变量x,没有覆盖外层函数中的x。也就是说内层函数有本地定义的变量,优先用自己的

    分析如下代码:

    代码1

    x = 1
    
    def fn():
        y = x + 1
        print(y)
        print(x)
    
    fn()

    运行结果

    2
    1

    代码2

    x = 1
    
    def fn():
        y = x + 1        
        print(y)
        x += 1       ## 这句开始报错
     print(x) fn()

    运行结果

    Traceback (most recent call last):
    y = x + 1 UnboundLocalError: local variable 'x' referenced before assignment

    报错是因为:x+=1等价x = x + 1,在函数本地定义了一个x变量,等式需要先计算右侧,这时本地没有变量x,x还没有赋值就被引用。

    要解决上面的问题,就需要引入如下两个定义:本地变量全局变量

    全局变量 global

    使用global关键字定义变量,将函数内的变量声明为全局作用域中的变量。global关键字后面的变量名必须在全局作用域中定义过

    x = 1
    
    def fn():
        global x
        x += 1
        print(x)
    
    fn()

    运行结果

    2

    全局作用域中没有定义x的情况

    x = 10
    def fn():
    global x x = 1 x += 1 print(x) fn() print(x) ## 由于提升了作用域,外部定义的x值被覆盖了

    运行结果

    2
    2

    注意,这里的x的作用域还是全局的

    不要使用global全局变量,因为这样破坏了函数的隔离性

    global关键字定义变量的作用域

    def outer():
        x = 10
        def inner():
            global x
            x += 1
            return x
        return inner
    
    foo=outer()
    foo()

    运行结果

    Traceback (most recent call last):
    
        x += 1
    NameError: name 'x' is not defined

    global的作用域是当前定义global代码段和函数最外层(outer函数外)

    默认值的作用域

    def fn(abc=1):
        print(abc)
    
    
    fn()
    print(abc)      ## abc是形参,在函数的局部作用域中

    运行结果

    1
    
    Traceback (most recent call last):
      File "C:/Users/ASUS-PC/PycharmProjects/复习/生成器.py", line 117, in <module>
        print(abc)
    NameError: name 'abc' is not defined

    函数的属性

    Python使用元组报错函数默认值的属性

    引用类型

    def fn(abc=[]):
        abc.append(1)
        print(abc)
    
    
    fn()
    fn()

    运行结果

    [1]
    [1, 1]

    默认值可以在函数的属性中查看,函数的属性伴随着整个函数的生命周期

    def fn(abc=[],a=1):
        abc.append(1)
        print(abc)
    
    
    fn()
    print(fn.__defaults__,id(fn))
    fn()
    print(fn.__defaults__,id(fn))

    运行结果

    [1]
    ([1], 1) 2304408771304
    [1, 1]
    ([1, 1], 1) 2304408771304

    非引用类型

    def fn(abc, a=1):
        print(abc, a)
        a = 'xyz'
        print(abc, a)
    
    
    fn('python')
    print(fn.__defaults__, id(fn))
    fn('hello')
    print(fn.__defaults__, id(fn))

    运行结果

    python 1
    python xyz
    (1,) 1279837100776
    hello 1
    hello xyz
    (1,) 1279837100776

    关键字参数的默认值属性

    def fn(abc,*, a=1,b=2):
        print(abc, a)
        a = 'xyz'
        print(abc, a)
    
    
    fn('python')
    print(fn.__defaults__, id(fn))
    fn('hello')
    print(fn.__kwdefaults__, id(fn))

    运行结果

    python 1
    python xyz
    None 1995116403432
    hello 1
    hello xyz
    {'a': 1, 'b': 2} 1995116403432

    使用浅拷贝的方式,避免修改实参的值

    def fn(abc=[], *, a=1, b=2):
        abc = abc[::-1]
        abc.append(1)
        print(abc)
    
    
    fn()
    print(fn.__defaults__, id(fn))
    fn()
    print(fn.__kwdefaults__, id(fn))
    fn([1, 2])
    print(fn.__defaults__, id(fn))
    fn([1, 2, 5])
    print(fn.__defaults__, id(fn))

    运行结果

    [1]
    ([],) 1883111578344
    [1]
    {'a': 1, 'b': 2} 1883111578344
    [2, 1, 1]
    ([],) 1883111578344
    [5, 2, 1, 1]
    ([],) 1883111578344

    通过判断传入参数的值,决定修改传入对象的值还是创建新对象(非常常用)

    def fn(abc=None, *, a=1, b=2):
        if abc is None:
            abc=[]
        abc.append(1)
        print(abc)
    
    
    fn()
    print(fn.__defaults__, id(fn))
    fn([1, 2])
    print(fn.__defaults__, id(fn))
    fn([1, 2, 5])
    print(fn.__defaults__, id(fn))

    运行结果

    [1]
    (None,) 2462419475176
    [1]
    {'a': 1, 'b': 2} 2462419475176
    [1, 2, 1]
    (None,) 2462419475176
    [1, 2, 5, 1]
    (None,) 2462419475176
  • 相关阅读:
    开放不应是唯一的价值观,互联网营销 狼人:
    什么是互联网产品的运营?,互联网营销 狼人:
    十年:邮箱,互联网营销 狼人:
    瘦客户端那些事 开篇,互联网营销 狼人:
    谈谈互动型网站中垃圾贴的应对方案,互联网营销 狼人:
    告诉你一个真实的中国互联网:精英与草根,互联网营销 狼人:
    从Google Wave和XML看软件复杂性之争,互联网营销 狼人:
    构建可伸缩高性能的互联网应用,互联网营销 狼人:
    注册接口使用StructureMap和Autofac等Ioc容器
    备份文件oracle 10g rman备份与恢复 之二
  • 原文地址:https://www.cnblogs.com/zh-dream/p/13836573.html
Copyright © 2011-2022 走看看