变量作用域

一个程序的所有变量并不是在哪个位置都可以访问的。访问权限取决于这个变量是在哪里赋值的。

变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。

如下为两种最基本的变量的作用域:

  • 全局变量
  • 局部变量

定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。

局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。

举例:

num = 0 #全局变量
def sum(arg1,arg2):
    #返回两个参数的和
    num = arg1 + arg2   #num在这里是局部变量
    print('局部变量:',num)
    return num
sum(10,5)
print('全局变量:',num)

执行结果:

局部变量: 15
全局变量: 0

python中的作用域分4种情况

  • L:local,局部作用域,即函数中定义的变量;
  • E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
  • G:globa,全局变量,就是模块级别定义的变量;
  • B:built-in,系统固定模块里面的变量,比如int, bytearray等。 搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
x = int(3.9)    #int built-inf ,系统固定模块里面的变量;
g_count = 10    #globa,全局变量;
def outer():
    e_count = 1 #enclosing,包含此函数的上级函数的局部作用域,但不是全局;
    def inner():
        l_count = 2 #local,局部作用域,函数中定义的变量;
        print(o_count)
    inner()
outer()

local和enclosing是相对的,enclosing变量相对上层来说也是local;

作用域产生

在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如if、try、for等)是不会引入新的作用域的,如下代码,if并没有引入一个新的作用域,x仍处在当前作用域中,后面代码可以使用:

if 2>1:
    x = 1
print(x)    #结果为 1

def、class、lambda是可以引入新作用域的:

def test():
    x = 2
print(x) #NameError: name 'x' is not defined

global关键字

当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下,代码如下:

count = 20
def outer():
    global count
    print(count)
    count = 200
    print(count)
outer()

执行结果:

20
200

nonlocal关键字 

global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量就需要nonlocal关键字了:

def outer():
    num = 20
    def inner():
        nonlocal num
        num = 100
        print(num)
    inner()
    print(num)
outer()

执行结果:

100
100

总结:

(1)变量查找顺序:LEGB,作用域局部>外层作用域>当前模块中的全局>python内置作用域;

(2)只有模块、类、及函数才能引入新作用域;

(3)对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量;

(4)内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关键字。nonlocal是python3新增的关键字,有了这个 关键字,就能完美的实现闭包了。 

高阶函数

变量可以指向函数,函数的参数可以接收变量,那么函数可以接收另一个函数作为参数,这种函数称为高阶函数

1、函数名可以作为参数输入
2、函数名可以作为返回值

把函数作为实参:

def fun(f):
    return f()
def hello():
    return "hello world"
print(fun(hello))
hello world

把函数作为返回值:

def foo():
    def hello():
        return "hello world"
    return hello
f = foo()
print(f())
hello world

系统内置高阶函数

1、map函数:接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并且把结果作为新的列表返回

def f(x):
    return x**2
ty = map(f,(1,2,3,4))
li = list(ty)
print(ty)
print(li)

执行结果

<map object at 0x0141EA70>
[1, 4, 9, 16]

2、reduce函数:把一个函数作用到一个序列上,这个函数必须接收两个参数,reduce把结果和序列的下一个元素做累积计算

from functools import reduce
def add(x, y):
    return x + y
print(reduce(add,range(1,5)))   # 累加1+2+3+4
print(reduce(add, range(1, 10)))  ## 4950 (注:1+2+...+9)
print(reduce(add, range(1, 10), 20))  ## 4970 (注:1+2+...+9+20)

执行结果:

10
45
65

3、filter函数:也接收一个函数和一个序列,和map函数不同的是,filter函数把传入的函数依次作用于每个元素,然后返回返回值是True的元素

例一:

str = ['a','b','c','d']
def fun(s):
    if s != 'a':
        return s
ret = filter(fun,str)
print(list(ret))
['b', 'c', 'd']

例二:

def str(k):
    if k % 2 == 0:
        return True
    else:
        return False
ret = filter(str,range(1,11))
print(list(ret))

打印结果:

[2, 4, 6, 8, 10]