函数返回值

多条return语句:

def guess(x):
if x > 3:
return "> 3"
else:
return "<= 3"
def showplus(x):
print(x)
return x + 1
return x + 2
#执行结果
10
11 #从结果来看 出现第一个return后 下面的就不会执行
def fn(x):
for i in range(x):
if i > 3:
return i
else:
print("{} is not greater than 3".format(x))
#fn(5) 执行结构是4
#fn(3) 3 is not greater than 3 #可以看出,我们可以通过条件控制语句来控制return

总结:

  • python函数使用return语句返回“返回值”
  • 所有函数都有返回值,如果没有return语句,隐式调用return None
  • return 语句并不一定是函数的语句块的最后一条
  • 一个函数可以存在多个return语句,但只有一条可以被执行,如果没有一条return语句被执行,隐式调用return None
  • 如果有必要,可以显示调用return None,可以简写return
  • 如果函数执行了return语句,函数就会返回,当前被执行的return语句之后的其他语句就不会被执行了
  • 作用:结束函数调用、返回值

返回多个值:

  • 函数不能同时返回多个值
  • return[1,3,5] 是指明返回一个列表,是一个列表对象
  • return 1,3,5 看似返回多个值,隐式的被python封装成了一个元组

可以使用解构来提前

def showlist():
return 1, 3, 5
x, y, z = showlist()

函数嵌套

def outer():
def inner():
print("inner")
print("outer")
inner()
outer()
#inner() #报错,inner没定义。说有函数是有作用域的
  • 函数有可见范围,这就是作用域的概念
  • 内部函数不能在外部直接使用,会抛NameError异常,因为它不可见

作用域

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

举例,对比案例1和案例2

#案例1
x=5
def foo():
print(x) foo()
#有执行结构,复用了全局的变量x
#案例2
x=5
def foo():
x+=1
print(x) foo()
#报错,x+=1 既是x= x+1 ,这里x被重新赋值了,所有x = x+1 既这里x是没有值的

全局作用域:

  • 在整个程序运行环境中都可见

局部作用域:

  • 在函数、类等内部可见
  • 局部变量使用范围不能超过其所在的局部作用域
def fn1():
x = 1 #局部作用域,在fn1内 def fn2():
print(x) #不可见 print(x) #不可见

嵌套结构作用域例子:

#例子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= 6
def foo():
x += 1
foo()

报错:

  • x += 1 等价于 x = x +1
  • 相当于在foo内部定义一个局部变量x,那么foo内部所有x都是这个局部变量x了
  • 但是x还没有完成赋值,就被右边拿来做加1的操作

解决这个问题 全局变量global 、nonlocal 来解决

全局变量global

案例

#x= 6
def foo():
global x
x = 10
x += 1 #不会报错了,
print(x) #打印11
print(x) #报错,找不到b这个标识符
  • 使用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。学习它就是为了深入理解变量作用域

闭包

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

案例:

def counter():
c = [0]
def inc():
c[0] += 1 #会报错吗?
return c[0]
return inc
foo = counter()
print(foo(),foo()) #打印结果?
c = 100
print(foo()) #打印结果?

代码解析:

  • 不会报错,c已经在counter函数中定义过了,而且inc中的使用方式是为c的元素修改值,而不是重新定义变量
  • 第一个的打印结果是  1, 2
  • 最后一行的打印结果是 3
  • 倒数第二行的c和counter中的c不一样,而inc引用的是自由变量正式counter的变量c
  • 这是python2中实现闭包的方式,python3还可以使用nonlocal关键字

nonlocal关键字

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

例子:

def counter1():
c = 0
def inc():
nonlocal c
c += 1
return c
return inc
foo = counter()
foo()
foo()
  • c 是外层函数的局部变量,被内部函数引用
  • 内部函数使用nonlocal关键字声明c变量在上级作用域而非本地作用域中定义

默认值作用域

案例

#案例1
def foo(xyz=1):
print(xyz)
foo() # 打印 1
foo() # 打印 1
print(xyz) # 报错 NameError 当前作用域没有xyz变量
#案例2
def foo(xyz=[]):
xyz.append(1)
print(xyz)
foo() # [1]
foo() # [1,1]

案例2中为什么第二个foo()会打印2个1

  • 因为函数也是对象,python把函数的默认值放在了属性中,这个属性就伴随着这个函数对象整个生命周期
  • 查看foo.__defaults__

运行下面案例

def foo(xyz=[], u='abc', z=123):
xyz.append(1)
return xyz
print(foo(), id(foo))
print(foo.__defaults__)
print(foo(), id(foo))
print(foo.__defaults__) #执行结果
[1] 139927086673704
([1], 'abc', 123)
[1, 1] 139927086673704
([1, 1], 'abc', 123)

总结:

  • 函数地址并没有变,就是说函数这个对象的没有变,调用它,它的属性__defaults__中使用元组保存默认值
  • xyz默认值是引用类型,引用类型的元素变动,并不是元组的变化

运行下面案例:

def foo(w, u='abc', *, z=123, zz=[456]):
u = 'xyz'
z = 789
zz.append(1)
print(w, u, z, zz)
print(foo.__defaults__)
foo('magedu')
print(foo.__kwdefaults__) 运行结果
('abc',)
magedu xyz 789 [456, 1]
{'z': 123, 'zz': [456, 1]}
  • 属性__defaults__中使用元组保存所有位置参数默认值
  • 属性__kwdefaults__中使用字典保存所有keyword-only参数的默认值

按需修改的案例:

例如案例中列表增加的问题,如果我不想让他增加呢?

def foo(xyz=[], u='abc', z=123):
xyz = xyz[:] # 影子拷贝
xyz.append(1)
print(xyz)
foo()
print(foo.__defaults__)
foo()
print(foo.__defaults__)
foo([10])
print(foo.__defaults__)
foo([10,5])
print(foo.__defaults__)
  • 函数体内,不改默认值
  • xyz都是传入参数或者默认值参数的副本,如果就想修改原参数,无能为力

第二种方法:

def foo(xyz=None, u='abc', z=123):
if xyz is None:
xyz = []
xyz.append(1)
print(xyz)
foo()
print(foo.__defaults__)
foo()
print(foo.__defaults__)
foo([10])
print(foo.__defaults__)
foo([10,5])
print(foo.__defaults__)
  • 使用不可变类型默认值
  • 如果使用缺省值None就创建一个列表
  • 如果传入一个列表,就地修改这个列表

第一种方法

  • 使用影子拷贝创建一个新的对象,永远不能改变传入的参数

第二种方法

  • 通过值的判断就可以灵活的选择创建或者修改传入对象
  • 这种方法灵活,应用广泛
  • 很多函数定义,都可以看到使用None这个不可变的值作为默认参数,可以说这是一种惯用法

变量名解析原则LEGB

  • Local,本地作用域、局部作用域的local命名空间。函数调用时创建、调用结束消亡
  • Enclosing,Python2.2时引入嵌套函数,实现了闭包,这个就是嵌套函数的外部函数的命名空间
  • Global,全局作用域,既一个模块的命名空间,模块被import时创建,解释器退出时消亡
  • Build-in,内置模块的命名空间,生命周期从python解释器启动时创建到解释器退出时消亡。例如:print(open),print和open都是内置变量
  • 所以查找顺序是LEGB

函数销毁

全局函数销毁

  • 重新定义同名函数
  • del语句删除函数对象
  • 程序退出时
def foo(xyz=[], u='abc', z=123):
xyz.append(1)
return xyz
print(foo(), id(foo), foo.__defaults__)
def foo(xyz=[], u='abc', z=123):
xyz.append(1)
return xyz
print(foo(), id(foo), foo.__defaults__)
del foo
print(foo(), id(foo), foo.__defaults__)

局部函数销毁

  • 重新在上级作用域定义同名函数
  • del语句删除函数名称,函数对象的引用计数减1
  • 上级作用域销毁时
def foo(xyz=[], u='abc', z=123):
xyz.append(1)
def inner(a=10):
pass
print(inner)
def inner(a=100):
print(xyz)
print(inner)
return inner
bar = foo()
print(id(foo),id(bar), foo.__defaults__, bar.__defaults__)
del bar
print(id(foo),id(bar), foo.__defaults__, bar.__defaults__)

Python 函数返回值、作用域的更多相关文章

  1. python函数返回值

    2016-08-09  15:01:38 python函数返回值使用return语句,可以返回任意类型的数.如果return语句执行,它之后的所有语句都不再执行. def func(x,y): pri ...

  2. Python 函数返回值

    本章详细介绍 返回值: 0x 00 返回值简介 0x 01 指定返回值与隐含返回值 0x 02 return 语句位置与多条 return 语句 0x 03 返回值类型 0x 04 函数嵌套 0x 0 ...

  3. python 函数返回值笔记

    今天学习python时候学习到闭包和柯里化 感觉看概念时候不好理解,自己写下大概就明白点了 柯里化如下 定义一个加法函数 def add(x, y): return x + y 这是没有柯里化之前的函 ...

  4. day09 python函数 返回值 参数

    day09 python   一.函数     1.函数         函数是对功能的封装         语法:         定义函数:             def 函数名(形参):    ...

  5. python 函数返回值(总结)

    关键字:return 没有返回值的叫过程 def test1(): msg="我是一个过程" print(msg) 有return的叫函数 def test02(): msg=&q ...

  6. Python 函数返回值类型

    [ i for i in dir(set) if not i.startswith('_') ]   

  7. Python学习教程(learning Python)--2.3.4Python函数返回值

    本节讨论Python函数返回值问题. Python和C语言一样,也可以在函数结束时返回一个值.但在定义自己的Python函数时,是不需要指定返回值数据类型的,这和Python不关心变量的数据类型是一致 ...

  8. Python return语句 函数返回值

    return语句是从python 函数返回一个值,在讲到定义函数的时候有讲过,每个函数都要有一个返回值.Python中的return语句有什么作用,今天就来仔细的讲解一下. python 函数返回值 ...

  9. python学习——函数返回值及递归

    返回值 return语句是从python 函数返回一个值,在讲到定义函数的时候有讲过,每个函数都要有一个返回值.Python中的return语句有什么作用,今天小编就依目前所了解的讲解一下.pytho ...

随机推荐

  1. certbot更新错误

    自动更新老是提示这个错误. root@vultr:~/certbot# ./certbot-auto Upgrading certbot-auto 0.29.1 to 0.34.2... Couldn ...

  2. 19 Jquery 属性

    从 jQuery 1.6 开始, .prop()方法 方法返回 property 的值,而 .attr() 方法返回 attributes 的值. 例如, selectedIndex, tagName ...

  3. msaa mrt load store action unity

    unity buildin renderpipeline 和lightweight rp 对于开了msaa的rt 的load store action设置失效 buildin的时候set render ...

  4. 编写一个c程序来计算整数中的设置位数?

    回答: unsigned int NumberSetBits(unsigned int n) { ; while (n) { ; ; } return CountSetBits; } 本质上就是计算n ...

  5. 基于JS的高级脚本语言 Sara

    Sara-基于JS的高级脚本语言 欢迎使用Sara,Sara是一款基于JavaScript的全新的高级脚本语言! Sara不像我们工作室上一款编程语言作品-Ginit一样,他属于更高级的语言 Sara ...

  6. CF C. Vladik and fractions——构造题

    题目 构造一组 $x, y, z$,使得对于给定的 $n$,满足 $\frac{1}{x}  + \frac{1}{y} + \frac{1}{z} =  \frac{2}{n}$. 分析: 样例二已 ...

  7. 29、[源码]-AOP原理-AnnotationAwareAspectJAutoProxyCreatovi

    29.[源码]-AOP原理-AnnotationAwareAspectJAutoProxyCreatovi

  8. 071_关闭 SELinux

    #!/bin/bashsed -i '/^SELINUX/s/=.*/=disabled/' /etc/selinux/configsetenforce 0

  9. 6、transformation和action1

    一.transformation和action入门 1.介绍 Spark支持两种RDD操作:transformation和action.transformation操作会针对已有的RDD创建一个新的R ...

  10. gulp4配置多页面项目编译打包

    又开始公司的新项目了... 那当我们拿到公司新项目的时候我们需要做些什么呢? 下面就来分享一下我的工作步骤吧(仅使用于初学者,大神勿见怪- -,有不好的地方希望指出,十分感谢) 1. 整版浏览 这是一 ...