Python学习打call第十七天:函数的返回值与嵌套函数

1.什么是返回值

  • 返回值指的是函数返回的结果;

  • return执行完毕后面的语句将不会再执行;

def add(x, y):
    print(x, y)   #输出:10 20
    return x + y   # 返回值, return以后的语句将不会再执行
    print(x)
    print(y)
add(10,20)
  • 如果一个函数里面有两个return,前面return执行完毕,后面的return也不会执行;
def add(x, y):
    print(x, y)    # 输出:1 2
    return x + y   # 函数体内,碰到return语句,函数执行完毕,之后的语句将不会再执行
    return x - y   # 不会再次执行
add(1,2)

2.函数的隐式返回和显示返回

  • Python函数都有返回值,如果有return语句,是显式返回;

  • 如果没有return语句,默认返回None,是隐式返回;

3.函数多值返回

  • 如果返回多个值通过逗号分开,会把值进行压缩,封装成一个元组;
def get_data(x,y,z):
    return x + 1, y + 1, z + 1
print(get_data(1,2,3)) # 得到的是一个元组(2, 3, 4)      
  • 如果返回一个列表,得到的就是一个列表;
def get_data(x,y,z):
    return [x + 1, y + 1, z + 1]
print(get_data(1,2,3))  # 得到的是一个列表[2, 3, 4]

4.什么是嵌套函数

def outer_function():
    # 内部函数
    def inner_function():
        print("inner_function")  # 输出:inner_function
    print("outer_function")      # 输出:outer_function
    # 内部调用
    inner_function()
outer_function()
# 注意:inner_function函数只能在outer_function函数内部调用,无法再outer_function函数外部被调用
  • 嵌套函数的内部函数只能在包含它的函数的直接父级调用,也就是只能在包含它的外部函数中调用;

  • 嵌套函数层数不宜过深,一般3层以内即可,太深不够直观,容易造成代码混乱;

5.函数作用域

  • 作用域指的是,一个标识符的作用范围就是这个标识符的作用域;

  • 在函数里面定义的变量(即局部作用域)只能在函数体内部被访问,函数外部不能访问;

def add(x, y):
    z = 100
    print(x, y , z)  #输出:1 2 100
add(1,2)
print(z)  #报错:NameError: name 'z' is not defined
  • 在函数外部定义的变量(即全局作用域)能在函数体外部被访问,也能在函数体内部被访问;
z = 100
def add(x, y):
    print(x, y, z)# 输出:1 2 100
add(1, 2)
print(z)  # 输出:100

6.函数的闭包

  • 闭包:内部函数引用了外部函数的变量,这就是闭包的定义;

  • 如果函数体想访问变量,只能在变量定义之后才能访问;

# 例1
x=5
def add():
    y = x + 1
    print(y)  #输出:6
add()

# 例2
x=5
def add():
    x = x + 1  # 报错:local variable 'x' referenced before assignment
add()

# 报错原因分析:
# 在例1中,函数内部引用的x为函数外部的x, 因此x的值为5
# 在例2中,函数内部重新定义了x的值,那么整个函数内部都会使用这个内部x,
# 因此在运算x + 1的时候,x还没有完成定义就被引用了,这里的x引用的一定是内部正在定义的 x,不是函数外部的 x=5这个x;


# 例3:
x=5
def add():
    print(x) # 这里的x引用的是x = 1的x,但是执行print(x)时,x还没有被定义,所以报错:local variable 'x' referenced before assignment
    x =  1
add()

  • 如果要访问函数体内部的函数,可以先把内部函数的函数名作为外部函数的返回值,把外部函数的引用赋值给变量,再调用变量;
# 例4:
def outer_function():
    x = 100
    def inner_function():
        print(x)        # 内部函数引用了外部函数的自由变量  输出:100
    return inner_function
ret = outer_function()
ret()

7.关键字

  • global关键字:可以指定变量为全局变量,但是global关键字会污染全局变量,也就是会覆盖之前全局变量的值,所以最好慎用;
x=1
def add():
    global x  # 使用global关键字,指定x的引用全局的x变量
    x = x + 1
    print(x)  #输出:2
add()

x = 100
def foo():
    global x  # x被声明了全局变量
    x = 10
    x += 1
    print(x)  # x的值为11
foo()
print(x)      # 输出x的值为:11,原本这里应该引用的是全局变量x = 100 的,因此global关键字污染了全局变量 x
  • nonlocal关键字:可以申明内部函数的变量引用的是外部函数变量的值(作用域在外部函数),不是全局作用域的值,因此不会污染全局作用域;
def outer_function():
    x = 100
    def inner_function():
        x = x + 1       # 这样会报错,函数内部重新定义了x的值,但是还没有完成定义就被引用了
        print(x)
    return inner_function
ret = outer_function()
ret()


def outer_function():
    x = 1
    def inner_function():
        nonlocal x   # 使用nonlocal关键字声明x 为外层函数的x的值
        x = x + 1    #所以这里使用的x 是外层函数的x
        print(x)   #输出:2
    return inner_function
ret = outer_function()
ret()

8.函数默认值的作用域

  • 同一个函数的生命周期相同,函数的默认值会绑定在函数的整个生命周期上,不会因为函数内部对默认值的操作而发生改变;
def add(lst = []):
    lst.append('hello')
    print(lst)
add() # 输出:['hello']
print('id={}'.format(id(add)))   # 函数对象的id值不变,调用的是同一个函数  id=1837000
add() # 输出['hello', 'hello']
print('id={}'.format(id(add)))   # 函数对象的id值不变,调用的是同一个函数  id=1837000

# 查看函数的位置参数的默认值
print(add.__defaults__)    #输出:(['hello', 'hello'],)

# 查看函数的关键字参数的默认值
print(add.__kwdefaults__)  #输出:None

  • 可以使用浅拷贝copy(简写[:])来清空默认值,那每次调用函数,默认值都为初始值;
def add(lst = []):
    lst = lst[:]
    lst.append('hello')
    print(lst)
add() # 输出:['hello']
add() # 输出:['hello']
  • 也可以通过参数值判断来给默认值重新赋值,那每次调用函数,默认值都为初始值;
def add(lst=None):
    if lst is None:
        lst = []
    lst.append(1)
    print(lst)
    
add()    # 输出:[1]
print(add.__defaults__)  # 输出: (None,)

add([1, 2, 3])    # 输出: [1, 2, 3, 1]
print(add.__defaults__)  # 输出:(None,)

add([4, 5, 6])     # 输出:[4, 5, 6, 1]
print(add.__defaults__)    # 输出:(None,)

9.函数销毁

def add():
    print('add')
del add
add()
  • 可以通过 del 函数名 的方式来删除函数,再调用函数时,就会报错不存在;

参考:侠课岛(9xkd.com)Python同学计划

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容