py_15 名称空间 作用域 嵌套函数

一 名称空间
    1.1 内建名称空间:内置函数名,1个
    1.2 全局名称空间:函数外部的变量 函数名 类名 导入的模块名。1个
    1.3 局部名称空间:函数内变量,多个
    `名称空间的加载顺序是:内置名称空间->全局名称空间->局部名称空间`

    `查找顺序为:局部名称空间->全局名称空间->内置名称空间
二 作用域
    全局作用域与局部作用域
    作用域与名字查找的优先级
三 嵌套函数
    1、嵌套函数简单的理解可以看作是在函数的内部再定义函数,实现函数的“私有”。
    2、特点:
    <1> 函数内部可以再次定义函数。
    <2> `只有被调用时才会执行(外部函数被调用后,被嵌套函数调用才有效)`

一 名称空间

名称空间即存放名字与对象映射/绑定关系的地方。对于x=3,Python会申请内存空间存放对象3,然后将名字x与3的绑定关系存放于名称空间中,del x表示清除该绑定关系。

在程序执行期间最多会存在三种名称空间

1.1 内建名称空间:内置函数名,1个

伴随python解释器的启动/关闭而产生/回收,因而是第一个被加载的名称空间,用来存放一些内置的名字,比如内建函数名

>>> max
<built-in function max>

>>> sorted
<built-in function sorted>

存活周期:python解释器启动--产生, 解释器关闭--灭亡

1.2 全局名称空间:函数外部的变量 函数名 类名 导入的模块名。1个

伴随python文件的开始执行/执行完毕而产生/回收,是第二个被加载的名称空间,文件执行过程中产生的名字都会存放于该名称空间中,如下名字

存活周期:python文件执行--产生, python文件运行完毕后--灭亡

import sys #模块名sys

x=1 #变量名x

if x == 1:
    y=2 #变量名y

def foo(x): #函数名foo
    y=1
    def bar():
        pass

Class Bar: #类名Bar
    pass

1.3 局部名称空间:函数内变量,多个

伴随函数的调用/结束而临时产生/回收,函数的形参、函数内定义的名字都会被存放于该名称空间中

局部变量在函数调用时才能够被创建,在函数调用之后会自动销毁

存活周期:调用函数--产生, 调用完毕--灭亡

def foo(x):
    y=3 #调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中

1.4 加载顺序和查找顺序

名称空间的加载顺序是:内置名称空间->全局名称空间->局部名称空间

查找顺序为:局部名称空间->全局名称空间->内置名称空间。``L-E-G-B E:闭包作用域

画图理解:

image.png

二 作用域

image.png

2.1 全局作用域与局部作用域

按照名字作用范围的不同可以将三个名称空间划分为两个区域:

  1. 全局作用域:位于全局名称空间、内建名称空间中的名字属于全局范围,该范围内的名字全局存活(除非被删除,否则在整个文件执行过程中存活)、全局有效(在任意位置都可以使用);
  2. 局部作用域:位于局部名称空间中的名字属于局部范围。该范围内的名字临时存活(即在函数调用时临时生成,函数调用结束后就释放)、局部有效(只能在函数内使用)。

2.2 作用域与名字查找的优先级

在局部作用域查找名字时,起始位置是局部作用域,所以先查找局部名称空间,没有找到,再去全局作用域查找:先查找全局名称空间,没有找到,再查找内置名称空间,最后都没有找到就会抛出异常

x=100 #全局作用域的名字x
def foo():
    x=300 #局部作用域的名字x
    print(x) #在局部找x
    print(globals())
    print(locals())
foo()#结果为300
print(globals())
print(locals())

提示:可以调用内建函数locals()和globals()来分别查看局部作用域和全局作用域的名字,查看的结果都是字典格式。在全局作用域查看到的locals()的结果等于globals()

Python支持函数的嵌套定义,在内嵌的函数内查找名字时,会优先查找自己局部作用域的名字,然后由内而外一层层查找外部嵌套函数定义的作用域,没有找到,则查找全局作用域

x=1
def outer():
    x=2
    def inner(): # 函数名inner属于outer这一层作用域的名字
        x=3
        print('inner x:%s' %x)

    inner()
    print('outer x:%s' %x)

outer() 
#结果为
inner x:3
outer x:2

在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值为不可变类型时,则需要用到global关键字

x=1
def foo():
    global x #声明x为全局名称空间的名字
    x=2
foo()
print(x) #结果为2

当实参的值为可变类型时,函数体内对该值的修改将直接反应到原值,

num_list=[1,2,3]
def foo(nums):
    nums.append(5)

foo(num_list)
print(num_list)
#结果为
[1, 2, 3, 5]

对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外部嵌套函数定义的作用域(非全局)

def  f1():
    x=2
    def f2():
        nonlocal x
        x=3
    f2() #调用f2(),修改f1作用域中名字x的值
    print(x) #在f1作用域查看x

f1()

#结果
3

nonlocal x会从当前函数的外层函数开始一层层去查找名字x,若是一直到最外层函数都找不到,则会抛出异常。

三 嵌套函数

1、嵌套函数简单的理解可以看作是在函数的内部再定义函数,实现函数的“私有”。

2、特点:

<1> 函数内部可以再次定义函数。

<2> 只有被调用时才会执行(外部函数被调用后,被嵌套函数调用才有效)

def func1():
    print('hello world!')
    def func2():
        print('everyone...')

func1() # 输出:hello world! ,此时func2未被调用并不执行

age = 21
def func1():
    age = 19
    print('func1输出:',age) # 输出:19
    def func2():
        print('func2输出:',age) # 输出:19
    return func2  # 返回函数名

val = func1()  # 调用func1并将返回值赋给变量val,val = func2
print(val)  # 输出:<function func1.<locals>.func2 at 0x000002CE667298C8>
val() # 等于调用func2,返回函数定义处执行
print('全局输出:',age)  # 输出:21
1 #!/usr/bin/env python3
 2 #-*- coding:utf-8 -*-
 3 
 4 #情形1
 5 name = 'cc'
 6 def func1():
 7     name = 'sc'
 8     print(name)
 9     def func2():
10         #name = 'df'
11         print(name)
12     func2()
13 func1() #输出:sc  df,当第10行被注释时,输出:sc  sc,
14         # 嵌套函数中的变量层层调用,当前函数中没有便向上一级函数查找
15 
16 #情形2
17 age = 21
18 def func1():
19     def func2():
20         print(age) #输出:18,当前函数中并没有定义(‘第二层局部变量’)age,向第一层找
21     age = 18 #与func2位于同一层,‘第一层局部变量’
22     func2()
23 print(func1(),age)  #输出:None ,21,此时,函数外输出的age只能是全局变量
24 
25 #情形3
26 age = 21
27 def func1():
28     def func2():
29         print(age)
30     func2()
31     #age = 18
32 func1() #当31行不被注释时,运行会报错,打印age时会混淆全局age和局部age;
33         #当31行被注释时,输出: 21,此时func2调用全局age
34 
35 #情形4
36 age = 21
37 def func1():
38     global age #声明全局变量
39     def func2():
40         print('func2中的:',age) #输出>>func2中的: 21, age此时引用的是36行的全局变量
41     func2()
42     age = 18 #由于已经声明age是全局变量,所以此处的重新赋值就是对全局修改
43 func1()
44 print('全局中的:',age)  #输出>>全局中的: 18, 变量age在函数func1中被修改
45 
46 #情形5
47 age = 21
48 def func1():
49     global age
50     def func2():
51         print('func2中的:',age) #输出>>func2中的: 18,  age此时引用的是47行的全局变量
52     age = 18  #由于已经声明age是全局变量,所以此处的重新赋值就是对全局修改
53     func2()
54 func1()
55 print('全局中的:',age) #输出>>全局中的: 18, 变量age在函数func1中被修改
'''    情形4和情形5的区别在于age变量的修改在程序中的执行顺序,在func2调用前还是在func2调用之后,如果是在func2调用前修改age,则func2中输出的则是修改后的;如果是在func2调用后修改age,则func2中输出的就是未修改时的全局变量age,所以两者func2函数中输出的age值不同,但最后的全局输出相同。'''
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343