函数的返回值和作用域

1、返回值

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

  1> Python 函数使用 return 语句返回 "返回值”
  2> 所有函数都有返回值,如果没有 return 语句,隐式调用 return None
  3> return 语句并不一定是函数的语句块的最后一条语句
  4> 一个函数可以存在多个 return 语句,但是只有一条可以被执行。如果没有一条 return 语句被执行到,隐式调用 return None
  5> 如果有必要,可以显示调用return None,可以简写为return
  6> 如果函数执行了 return 语句,函数就会返回,当前被执行的 return 语句之后的其它语句就不会被执行了
  7> 返回值的作用:结束函数调用、返回 "返回值”

2、能一次返回多个值嘛?

def showvalues():
return 1, 3, 5
print(showvalues()) # 返回 (1, 3, 5)

  函数不能同时返回多个值
  return 1, 3, 5 看似返回多个值,隐式的被 python 封装成了一个元组
  x, y, z = showvalues() 使用解构提取返回值更为方便

3、函数作用域**

3.1 作用域

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

x = 20
def fn():
x = 100 # x 的作用域:当前函数
fn()
print(x) # x = 20

  注意:每一个函数都会开辟一个作用域。

3.2 作用域分类

  全局作用域:
    在整个程序运行环境中都可见
    全局作用域中的变量称为全局变量

  局部作用域:
    在函数、类等内部可见
    局部作用域中的变量称为局部变量,其使用范围不超过其所在局部作用域

# 局部变量
def fn1():
x = 1 # 局部作用域,x 为局部变量,使用范围在 fn1 内 def fn2():
print(x) # x 能打印吗?不能 print(x) # x 能打印吗?不能
# 全局变量
x = 5 # 全局变量,也在函数外定义
def foo():
print(x) # 可见吗?可以
foo()

  一般来讲外部作用域变量在函数内部可见,可以使用
  反过来,函数内部的局部变量,不能在函数外部看到

4、函数嵌套

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

def outer():
def inner():
print('inner')
print('outer')
inner()
outer()
inner() # 不可以

  内部函数 inner 不能在外部直接使用,会抛出 NameError 异常,因为它在函数外部不可见。
  其实,inner 不过就是一个标识符,就是一个函数 outer 内部定义的变量而已。

5、嵌套函数的作用域

def outer():
o = 65 # 局部变量、本地 local 变量、临时变量
def inner():
o = 97
print('inner', o)
print('outer 1 ', o)
inner()
print('outer 2 ', o)
outer() # 1:outer 1 65 2:inner 97 3:outer 2 65

  外层变量在内部作用域可见。
  内层作用域中,如果定义了和外层相同的变量,相当于在当前函数作用域中重新定义了一个新的变量,这个内层变量并不能覆盖掉外部作用域中的变量。

6、一个赋值语句的问题

x = 100
def fn():
y = x + 200
print(y)
fn()
x = 100
def fn():
x += 1 # 报错! 赋值即定义,即 x = x + 1 (局部变量 = 局部变量 + 1)!
print(x)
fn()
x = 100
def fn():
print(x) # 报错!该步执行不了!
x += 1 # 只要在该作用域内赋值定义('=')局部变量,在该作用域内的所有该变量都为局部变量!
print(x)
fn()

  能否解决呢?可以,使用 global 语句

x = 100
def fn():
global x # 声明全局变量
print(x) #
x += 1
print(x) #
fn()
print(x) #

  注意:全局变量一般情况不推荐修改,一旦在作用域中使用 global 声明全局变量,那么相当于在对全局变量赋值、定义。

  global 使用原则:

    1> 外部作用域变量会在内部作用域可见,但也不要在这个内部的局部作用域中直接使用,因为函数的目的就是为了封装,尽量与外界隔离。
    2> 如果函数需要使用外部全局变量,请尽量使用函数的形参定义,并在调用传实参解决。
    3> 一句话:不用 global,学习它就是为了深入理解变量作用域。

# 不建议直接传入全局变量!
y = [] def foo(): # x 就是标识符,就是变量,就是本地变量
y.append(1) foo()
foo()
print(y)
# 建议使用传参的方式,在函数内使用全局变量
y = [] def foo(x): # x 就是标识符,就是变量,就是本地变量
x.append(1) foo(y)
foo(y)
print(y)

7、闭包**

  自由变量:未在本地作用域中定义的变量。例如定义在内层函数外的外层函数的作用域中的变量
  闭包:就是一个概念,出现在嵌套函数中,指的是内层函数引用到了外层函数的自由变量,就形成了闭包。很多语言都有这个概念,最熟悉就是 JavaScript。

# python 2 实现闭包
def counter():
c = [0]
def inc():
c[0] += 1 # 是赋值即定义嘛?不是!是修改值
return c[0]
return inc # 返回标识符,即函数对象 m = counter()
m() # 调用函数 inc(),但是 c 消亡了嘛?没有,内层函数没有消亡,c 不消亡(闭包)
m()
m()
print(m())
# 不推荐使用 global !
def counter():
global c
c = 0
def inc():
global c
c += 1 # 不是闭包!
return c
return inc m = counter()
m()
m()
m()
print(m())
# 推荐使用 nonlocal,python 3 实现闭包
def counter():
c = 0
def inc():
nonlocal c # 非当前函数的本地变量,当前函数之外的任意层函数的变量,绝非 global
c += 1 # 是闭包吗?是!
return c
return inc m = counter()
m()
m()
m()
print(m())

  nonlocal 语句:将变量标记为不在本地作用域定义,而是在上级的某一级局部作用域中定义,但不能是全局作用域中

8、默认值的作用域

def foo(x=1):
x += 1
print(x)
foo() #
foo() # def bar(x=[]): # x = [],引用类型
x.append(1) # [1]
print(x)
bar() # [1]
bar() # [1, 1]

  为什么上列 bar 函数第二次调用打印的是 [1, 1]?
    因为函数也是对象,每个函数定义被执行后,就生成了一个函数对象和函数名这个标识符关联。
    python 把函数的默认值放在了函数对象的属性中,这个属性就伴随着这个函数对象的整个生命周期。

# 查看 foo.__defaults__ 属性,它是个元组
def bar(x=[]):
x.append(1)
print(x)
print(bar.__defaults__)
bar() # [1]
print(bar.__defaults__)
bar() # [1, 1]
print(bar.__defaults__) # 执行结果:
([],)
[1]
([1],)
[1, 1]
([1, 1],) # 元组不变,记录的是地址,引用类型变化
def foo(x, m=123, n='abc'):
m=456
n='def'
print(x)
print(foo.__defaults__) # (123, 'abc')
foo('yang')
print(foo.__defaults__) # (123, 'abc')
def foo(x, m=123, *, n='abc', t=[1,2]):
m=456
n='def'
t.append(12)
#t[:].append(12) # t[:],全新复制一个列表,避免引用计数
print(x, m, n, t) print(foo.__defaults__, foo.__kwdefaults__) #(123,) {'n': 'abc', 't': [1, 2]}
foo('yang')
print(foo.__defaults__, foo.__kwdefaults__) #(123,) {'n': 'abc', 't': [1, 2, 12]}
def x(a=[]):
a = a + [5] # 加法的本质:返回新列表、新地址;赋值即定义
print(x.__defaults__) # ([],)
x()
x()
print(x.__defaults__) # ([],) def y(a=[]):
a += [5] # += 即 extend => a.extend([5])
print(y.__defaults__) # ([],)
y()
y()
print(y.__defaults__) # ([5, 5],) # 列表的 + 和 += 的区别:
# + 表示两个列表合并并返回一个全新的列表。
# += 表示,就地修改前一个列表,在其后追加后一个列表,就是 extend 方法。
# 例:
l1 = [1, 2]
l2 = [3, 4]
l3 = l1 + l2
print(id(l1), id(l2), id(l3))
l3 += l2 # 就地修改
print(id(l3)) 执行结果:
2279905055304 2279905055816 2279906334216
2279906334216

9、变量名解析原则 LEGB**

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

  所以一个名词的查找顺序就是 LEGB

  

10、函数的销毁

  定义一个函数就是生成一个函数对象,函数名指向的就是函数对象。
  可以使用del语句删除函数,使其引用计数减 1。
  可以使用同名标识符覆盖原有定义,本质上也是使其引用计数减 1。
  Python程序结束时,所有对象销毁。
  函数也是对象,也不例外,是否销毁,还是看引用计数是否减为 0。

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

  1. Python函数之返回值、作用域和局部变量

    一.函数返回值 说到返回值,相信大家肯定都认识,没错,就是return. 所谓返回值可以这样理解:函数外部的代码要想获取函数的执行结果,就可以在函数里用return语句把结果返回. 那具体怎么用呢?接 ...

  2. Python入门篇-返回值和作用域

    Python入门篇-返回值和作用域 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.返回值 1>.返回值概述 Python函数使用return语句返回“返回值” 所有函数都 ...

  3. 『无为则无心』Python函数 — 27、Python函数的返回值

    目录 1.返回值概念 2.return关键字的作用 3.返回值可以返回的数据类型 4.函数如何返回多个值 5.fn5 和 fn5()的区别 6.总结: 1.返回值概念 例如:我们去超市购物,比如买饮料 ...

  4. Python 函数作为返回值

    函数作为返回值高阶函数除了可以接收函数作为参数外,还可以把函数作为结果值返回. def lazy_sum(*args): def sum(): ax=0 for n in args: ax = ax ...

  5. 第八天pyhton3 函数的返回值、作用域

    返回值 pthon函数使用return语句返回"返回值": 所有函数都有返回值,如果没有return语句,隐式调用return None: return 语句并不一定是函数的语句块 ...

  6. python函数的返回值 讲解

    我们一起来聊聊python函数返回值的特殊情况,之前我也碰到过类似方面的问题,到后来查阅了一些资料后,发现原来是这样. 首先,写函数的时候,一定要写函数的文档,这样方便我们识别函数是做什么的.我记得很 ...

  7. python函数的返回值

    返回值:return1.没有返回值    #不写return    #只写return:结束一个函数    #return None2.有一个返回值    #可以返回任何数据类型    #只要返回就可 ...

  8. Python 基础之返回值与函数使用与局部变量和全局变量locals() 和 globals()

    一.函数的返回值 return return: 自定义返回值,返回到哪里? 返回到函数的[调用处]1.return 后面可以跟上六个标准数据类型,除此之外,可以跟上 类对象,函数,如果不写return ...

  9. Python的函数式编程-传入函数、排序算法、函数作为返回值、匿名函数、偏函数、装饰器

    函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计.函数就是面向过程的程序设计的基本单元. ...

随机推荐

  1. P5020 货币系统 题解

    原题链接 简要题意: 求一个长度最小的货币系统与给出的货币系统等价.求这个货币系统的长度.等价的定义详见题目,不再赘述. 本文可能用到一些集合论,请放心食用. 算法一 \(n=2\) 时,只需判断两个 ...

  2. sql-lib闯关31-40

    第三十一关 此关用WAF防护 和第三十关基本一样,在双引号后面添加括号进行闭合 语句可以有两种,?id=-1")union select 1,2,database() --+    或者   ...

  3. office的高级应用

    Word高级应用:设置斜线表头(一根:边框:多根:插入形状,按住鼠标拖动). 注意:1.用好样式功能 2.大量重复工作懂得批量处理 3.反复要做的固定操作固化成“模板”“套路” 4.碰到异常情况,知道 ...

  4. 福利,OpenCV最新中文版官方教程来了

    OpenCV 中文版官方教程来了. OpenCV是计算机视觉中经典的专用库,然而其中文版官方教程久久不来.近日,一款最新OpenCV4.1 版本的完整中文版官方教程出炉,读者朋友可以更好的学习了解Op ...

  5. 记录一个不同的流媒体网站实现方法,和用Python爬虫爬它的坑

    今天找到一片电影,想把它下载下来. 先开Networks工具分析一下: 初步分析发现,视频加载时会拉取TS格式的文件,推测这是一个m3u8的索引,记录着几百段TS文件,这样方便快进时加载. 但是实际分 ...

  6. Python python lamda 表达式

    '''关键字lambda表示匿名函数,冒号前面的x表示函数参数. 匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果. 用匿名函数有个好处,因为函数没有名字,不必担心 ...

  7. TCP连接与HTTP请求

    一道经典面试题: 从 URL 在浏览器被被输入到页面展现的过程中发生了什么? 相信大多数准备过的同学都能回答出来,但是如果继续问:收到的 HTML 如果包含几十个图片标签,这些图片是以什么方式.什么顺 ...

  8. 如何获取 bing 每日壁纸(超高清版)

    目录 需求描述 实现方式 简单粗暴 如何下载 如何更高清 排坑指南 初级 优点 给有好奇心的孩子 进阶 接口 自动保存 网站集成 爬虫 需求描述 必应作为一个在壁纸圈做搜索引擎最优秀的站点,其每日壁纸 ...

  9. Java读源码之ReentrantLock

    前言 ReentrantLock 可重入锁,应该是除了 synchronized 关键字外用的最多的线程同步手段了,虽然JVM维护者疯狂优化 synchronized 使其已经拥有了很好的性能.但 R ...

  10. 老技术新谈,Java应用监控利器JMX(3)

    各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 上期我们深入的聊了聊 JMX,把 JMX 的架构了解了七七八八,最后通过代码实战,解决系列疑问,实现远程动态修改应用参 ...