week04_python函数返回值、做用域

函数的返回值:python

  Python函数使用return语句返回"返回值"闭包

  全部函数都有返回值,若是没有return语句,隐式调用return Noneide

  return语句并不必定是函数的语句块的最后一条语句函数

  一个函数能够存在多个return语句,可是只有一条能够被执行;若是没有一条return语句被执行到,学习

隐式调用return Noneui

  若是有必要,能够显示调用return None,能够简写returnspa

  若是函数被扫行了return语句,函数就会返回,当前被执行的return语句以后的其它语句就不会被执行了orm

  做用:结束函数调用、返回值对象


举例:生命周期

def showplus(x):
    print(x)
    return x + 1
    return x + 2

print(showplus(5))# 只执行第一条return

def guess(x):
    if x > 3:
        return "> 3"
    else:
        return "<= 3"

print(guess(2))# 条件知足,只执行其中一条return


def fn(x):
    for i in range(x):
        if i > 3:
            return i
        else:
            print("{} is not greater than 3".format(i))

print(fn(5))# 打印什么?
print(fn(3))# 打印什么?


函数不能同时返回多个值:

def showlist():
    return [1, 3, 5]

print(showlist()) #[1, 3, 5] 指明返回一个列表,是一个列表对象

def showlist():
    return 1, 3, 5

print(showlist()) #(1, 3, 5) 看似返回多个值,隐式被python封装成了一个元组


函数的嵌套:

  在一个函数中定义了另外一个函数

def outer():
    def inner():
        print("inner")
    print("outer")

outer()# outer
inner()# NameError: name 'inner' is not defined

函数有可见范围,这就是做用域的概念;

内部函数不能被外部直接使用,会抛NameError异常;



做用域###

  一个标识符的可见范围,这就是标识符的做用域。通常常说的是变量的做用域

对比一下,下面2个函数,x究竟是可见仍是不可见?

(1)
x = 5

def foo():
    print(x)

foo()# 5


(2)
x = 5

def foo():
    x += 1
    print(x)


foo()# UnboundLocalError: local variable 'x' referenced before assignment

全局做用域

  在整个程序运行环境中均可见;

局部做用域

  在函数、类等内部可见;

  局部变量使用范围不能超过其所在的的局部做用域;

def fn1():
    x = 1 # 局部做用域,在fn1内

def fn2():
    print(x)# x可见吗?

print(x)# x可见吗?

嵌套结构:

对比下面两个代码中变量o的差异:
(1).

def outer1():
    o = 65
    def inner():
        print("inner {}".format(o))
        print(chr(o))
    print("outer {}".format(o))
    inner()

outer1()

(2).

def outer2():
    o = 65
    def inner():
        o = 97
        print("inner {}".format(o))
        print(chr(o))
    print("outer {}".format(o))
    inner()

outer2()

从上面的例子中能够看出:

  外层变量做用域在内层做用域可见

  内层做用域inner中,若是定义了o = 97 ,至关于当前做用域中从新定义了一个新的变量o,可是

这个o并无覆盖外层做用域outer中的o

x = 5
def foo():
    # y = x + 1
    x += 1# UnboundLocalError: local variable 'x' referenced before assignment
    print(x)
foo()

x += 1 实际上是 x = x + 1
至关于在foo内部定义一个局部变量x,那么foo内部全部x都是这个局部变量了;
可是这个x尚未彻底赋值,就被右边拿来作加1操做了;
该如何解决???

全局变量global

x = 5
def foo():
    global x
    x += 1
    print(x)

foo()

使用global关键字的变量,将foo内的x声明为使用外部的全局做用域中定义的x; 
全局做用域中必须有x的定义
若是全局做用域中没有x定义会怎么样???
x = 5

def foo():
    global x
    x = 10
    x += 1# 会报错吗?
    print(x)# 打印什么?

print(x)
foo()

使用global关键字的变量,将foo内的x声明为使用外部的全局做用域中定义的x; 

可是,x = 10 赋值即定义,x在内部做用域为一个外部做用域的变量赋值,因此x += 1不会报错。 

注意:这里x的做用域仍是全局的;


global总结:

  x += 1这种是特殊形式产生的错误的缘由?先引用后赋值,而python动态语言是赋值和算定义;

  才能被引用。解决方法,在这条语句前增长x = 0之类的赋值语句,或者使用global告诉内部做

  用域,去全局做用域查找变量定义;

  内部做用域使用x = 5之类的赋值语句会从新定义局部做用域使用的变量x,可是,一旦这个做用

  域中使用global声明x为全局的,那么x = 5至关于在为全局做用域的变量x赋值;


global使用原则:

  外部做用域变量会内部做用域可见,但也不要在这个内部的局部做用域中直接使用,由于

  函数的目的就是为了封装,尽可能与外界隔离;

  若是函数须要使用外部全局变量,请使用函数的形参传参解决;

  一句话:不用global。学习它就是为了深刻理解变量的做用域;




闭包#

  自由变量:未在本地做用域中定义的变量。例如定义在内存函数外的外层函数的做用域中的变量;

  闭包:就是一个概念,出如今嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就造成

了闭包。不少语言都有这个概念,最熟悉就是JavaScript

def counter():
    c = [0]
    def inc():
        c[0] += 1
        return c[0]
    return inc

foo = counter()
print(foo(), foo())
c = 100
print(foo())

代码解析:

  第4行不会报错,由于c已经在counter函数中定义过了。而inc中的使用方式是为c的元素修改值,而不是从新定义。

  第8行 会打印 1 2

  第10行会打印 3

  第9行的c和counter中的c不同,而inc引用的是自由变量正式counter的变量c; 

这就是python2中实现闭包的方式,python3还能够使用nonlocal关键字



nonlocal关键字

  使用nonlocal关键字,将变量标记为不在本地做用域定义,而是上级的某一级局部做用域中定义,但不能是

全局做用域中定义

def counter():
    count = 0
    def inc():
        nonlocal count
        count += 1
        return count
    return inc
foo = counter()
print(foo())
print(foo())

代码解析:

  count是外层函数的局部变量,被内部函数引用;

  内部函数使用nonlocal关键字声明count变量在上级做用域而非本地做用域中定义;

  代码能够正常使用,且造成闭包;



变量名解析原则LEGB

Local,本地做用域、局部做用域的local命名空间。函数调用时建立,调用结束消亡。

Enclosing,Python2.2时引入嵌套函数,实现了闭包,这个就是嵌套函数的外部函数的命名空间。

Global,全局做用域,即一个模块的命名空间。模块被import时建立,解释器退出时消亡。

Build-in,内置模块的命名空间,生命周期从python解释器启动时建立到解释器退出时消亡。

因此一个名词的查找顺序就是LEGB

blob.png

相关文章
相关标签/搜索