Skip to content

Commit 889f030

Browse files
committed
p3
1 parent b5af585 commit 889f030

File tree

6 files changed

+187
-87
lines changed

6 files changed

+187
-87
lines changed

202.md

Lines changed: 1 addition & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,7 @@
186186

187187
所有这些属性,都可以用句点的方式调用。
188188

189-
##概念辨析
190-
191-
有几个概念,是编程的时候常用到的。从某个角度讲,世界就是用概念构成的。如果没有概念,很难准确描述清楚世界。
192-
193-
###参数和变量
189+
##参数和变量
194190

195191
函数的参数,还是很有话题的。比如在别的程序员嘴里,你或许听说过“形参”、“实参”、“参数”等名词,到底指什么呢?
196192

@@ -257,84 +253,6 @@
257253

258254
结合前面学习过的列表能够被原地修改知识,加上刚才说的参数特点,你是不是能理解上面的操作呢?
259255

260-
###全局变量和局部变量
261-
262-
虽然是讲参数,但是关于全局变量和局部变量的区别也要先弄清楚,因为关系到函数内外有别的大事。
263-
264-
下面是一段代码,注意这段代码中有一个函数`funcx()`,这个函数里面有一个`x=9`,在函数的前面也有一个`x=2`
265-
266-
x = 2
267-
268-
def funcx():
269-
x = 9
270-
print "this x is in the funcx:-->", x #Python 3请自动修改为print(),下同,从略
271-
272-
funcx()
273-
print "--------------------------"
274-
print "this x is out of funcx:-->", x
275-
276-
这段代码输出的结果是什么呢?看:
277-
278-
this x is in the funcx:--> 9
279-
--------------------------
280-
this x is out of funcx:--> 2
281-
282-
从输出中可以看出,运行`funcx()`,输出了`funcx()`里面的变量`x`引用的对象9;然后执行代码中的最后一行`print "this x is out of funcx:-->",x`
283-
284-
特别要关注的是,前一个`x`输出的是函数内部的变量`x`;后一个`x`输出的是函数外面的变量`x`。两个变量彼此没有互相影响,虽然都是`x`。两个`x`各自在各自的领域内起到作用。
285-
286-
把那个只在函数体内(某个范围内)起作用的变量称之为**局部变量**
287-
288-
有局部,就有对应的全部,在汉语中,全部变量,似乎有歧义,幸亏汉语丰富,于是又取了一个名词:**全局变量**
289-
290-
x = 2
291-
def funcx():
292-
global x #跟上面函数的不同之处
293-
x = 9
294-
print "this x is in the funcx:-->",x
295-
296-
funcx()
297-
print "--------------------------"
298-
print "this x is out of funcx:-->",x
299-
300-
以上两段代码的不同之处在于,后者在函数内多了一个`global x`,这句话的意思是在声明`x`是全局变量,也就是说这个`x`跟函数外面的那个`x`同一个,接下来通过`x=9`将x的引用对象变成了9。所以,就出现了下面的结果。
301-
302-
this x is in the funcx:--> 9
303-
--------------------------
304-
this x is out of funcx:--> 9
305-
306-
好似全局变量能力很强悍,能够统统率函数内外。但是,要注意,这个东西要慎重使用,因为往往容易带来变量的混乱。内外有别,在程序中一定要注意的。
307-
308-
###命名空间
309-
310-
这是一个比较不容易理解的概念,特别是对于初学者而言,似乎它很飘渺。我在维基百科中看到对它的定义,不仅定义比较好,连里面的例子都不错。所以,抄录下来,帮助读者理解这个名词。
311-
312-
>命名空间(英语:Namespace)表示标识符(identifier)的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。
313-
314-
>例如,设Bill是X公司的员工,工号为123,而John是Y公司的员工,工号也是123。由于两人在不同的公司工作,可以使用相同的工号来标识而不会造成混乱,这里每个公司就表示一个独立的命名空间。如果两人在同一家公司工作,其工号就不能相同了,否则在支付工资时便会发生混乱。
315-
316-
>这一特点是使用命名空间的主要理由。在大型的计算机程序或文档中,往往会出现数百或数千个标识符。命名空间(或类似的方法,见“命名空间的模拟”一节)提供一隱藏區域標識符的機制。通过将逻辑上相关的标识符组织成相应的命名空间,可使整个系统更加模块化。
317-
318-
>在编程语言中,命名空间是对作用域的一种特殊的抽象,它包含了处于该作用域内的标识符,且本身也用一个标识符来表示,这样便将一系列在逻辑上相关的标识符用一个标识符组织了起来。许多现代编程语言都支持命名空间。在一些编程语言(例如C++和Python)中,命名空间本身的标识符也属于一个外层的命名空间,也即命名空间可以嵌套,构成一个命名空间树,树根则是无名的全局命名空间。
319-
320-
>函数和类的作用域可被視作隱式命名空间,它們和可見性、可訪問性和对象生命周期不可分割的联系在一起。
321-
322-
显然,用“命名空间”或者“作用域”这样的名词,就是因为有了函数(后面还会有类)之后,在函数内外都可能有外形一样的符号(标识符),在python中(乃至于其它高级语言),通常就是变量,为了区分此变量非彼变量(虽然外形一样),需要用这样的东西来框定每个变量所对应的值(发生作用的范围)。
323-
324-
前面已经讲过,变量和对象(就是所变量所对应的值)之间的关系是:变量类似标签,贴在了对象上。也就是,通过赋值语句实现了一个变量标签对应一个数据对象(值),这种对应关系让你想起了什么?映射!python中唯一的映射就是dict,里面有“键值对”。变量和值得关系就有点像“键”和“值”的关系。有一个内建函数vars,可以帮助我们研究一下这种对应关系。
325-
326-
>>> x = 7
327-
>>> scope = vars()
328-
>>> scope['x']
329-
7
330-
>>> scope['x'] += 1
331-
>>> x
332-
8
333-
>>> scope['x']
334-
8
335-
336-
既然如此,诚如前面的全局变量和局部变量,即使是同样一个变量名称。但是它在不同范围(还是用“命名空间”这个词是不是更专业呢?)对应不同的值。
337-
338256
------
339257

340258
[总目录](./index.md)   |   [上节:函数(1)](./201.md)   |   [下节:函数(3)](./203.md)

207.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ Python 3:
220220

221221
`girl.color("white")`之所以要给参数传值,是因为`def color(self, color)`中有参数`color`。另外,这个方法里面也使用了`self.name`实例属性。最终该方法返回的是一个字典。所以`print her_color`或者`print(her_color)`的结果是`{'canglaoshi': 'white'}`
222222

223+
刚才以`girl = Person("canglaoshi")`的方式,建立了一个实例,仿照它,还可以建立更多的实例,比如`boy = Person("zhangsan")`等等。也就是一个类,可以建立多个实例。所以“类提供默认行为,是实例的工厂”(源自Learning Python),这句话道破了类和实例的关系。所谓工厂,就是可以用同一个模子做出很多具体的产品。类就是那个模子,实例就是具体的产品。
224+
223225
这就是通过类建立实例,并且通过实例来调用其属性和方法的过程。
224226

225227
------

236.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,6 @@ zip()的参数是可迭代对象。例如:
9494

9595
------
9696

97-
[总目录](./index.md)   |   [上节:函数练习](./205.md)   |   [下节:类(1)](./206.md)
97+
[总目录](./index.md)   |   [上节:函数练习](./205.md)   |   [下节:命名空间](./241.md)
9898

9999
如果你认为有必要打赏我,请通过支付宝:**[email protected]**,不胜感激。

241.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
>Let the word of Christ dwell in you richly in all wisdom; teaching and admonishing one another in psalms and hymns and spiritual songs, singing with grrace in your hearts tto the Lord. And whatsoever ye do in word or deed, do all in the name of the Lord Jesus, giving thanks to God and the Father by him. (COLOSSIANS 3:14-15)
2+
3+
#命名空间
4+
5+
命名空间,英语叫做namespace,是很多编程语言中都会出现的术语。所以,有必要了解。
6+
7+
##全局变量和局部变量
8+
9+
全局变量和局部变量,是理解命名空间的起始。
10+
11+
下面是一段代码,注意这段代码中有一个函数`funcx()`,这个函数里面有一个`x=9`,在函数的前面也有一个`x=2`
12+
13+
x = 2
14+
15+
def funcx():
16+
x = 9
17+
print "this x is in the funcx:-->", x #Python 3请自动修改为print(),下同,从略
18+
19+
funcx()
20+
print "--------------------------"
21+
print "this x is out of funcx:-->", x
22+
23+
这段代码输出的结果是什么呢?看:
24+
25+
this x is in the funcx:--> 9
26+
--------------------------
27+
this x is out of funcx:--> 2
28+
29+
从输出中可以看出,运行`funcx()`,输出了`funcx()`里面的变量`x`引用的对象9;然后执行代码中的最后一行`print "this x is out of funcx:-->",x`
30+
31+
特别要关注的是,前一个`x`输出的是函数内部的变量`x`;后一个`x`输出的是函数外面的变量`x`。两个变量彼此没有互相影响,虽然都是`x`。两个`x`各自在各自的领域内起到作用。
32+
33+
把那个只在函数体内(某个范围内)起作用的变量称之为**局部变量**
34+
35+
有局部,就有对应的全部,在汉语中,全部变量,似乎有歧义,幸亏汉语丰富,于是又取了一个名词:**全局变量**
36+
37+
x = 2
38+
def funcx():
39+
global x #跟上面函数的不同之处
40+
x = 9
41+
print "this x is in the funcx:-->",x
42+
43+
funcx()
44+
print "--------------------------"
45+
print "this x is out of funcx:-->",x
46+
47+
以上两段代码的不同之处在于,后者在函数内多了一个`global x`,这句话的意思是在声明`x`是全局变量,也就是说这个`x`跟函数外面的那个`x`同一个,接下来通过`x=9`将x的引用对象变成了9。所以,就出现了下面的结果。
48+
49+
this x is in the funcx:--> 9
50+
--------------------------
51+
this x is out of funcx:--> 9
52+
53+
好似全局变量能力很强悍,能够统统率函数内外。但是,要注意,这个东西要慎重使用,因为往往容易带来变量的混乱。内外有别,在程序中一定要注意的。
54+
55+
局部变量和全局变量是在不同的范围内起作用。所谓的不同范围,就是变量产生作用的区域,简称作用域。
56+
57+
##作用域
58+
59+
所谓作用域,是“名字与实体的绑定保持有效的那部分计算机程序”(引自《维基百科》),用直白的方式说,就是程序中变量与对象存在关联的那段程序。如果用前面的例子说明,`x = 2``x = 9`是处在两个不同的作用域中。
60+
61+
通常,把作用域还分为静态作用域和动态作用域两种,虽然Python是所谓的动态语言(不很严格的划分),但它的作用域属于静态作用域,意即Python中变量的作用域由它在程序中的位置决定,如同上面例子中的`x = 9`位于函数体内,它的作用域和`x = 2`就不同。
62+
63+
那么,Python的作用域是怎么划分的呢?可以划分为四个层级:
64+
65+
1. Local:局部作用域,或称本地作用域
66+
2. Enclosing:嵌套作用域
67+
3. Global:全局作用域
68+
4. Built-in:内建作用域
69+
70+
对于一个变量,Python也是按照上述从前到后的顺序,在不同作用域中查找。在刚才的例子中,对于`x`,首先搜索的是函数体内的本地作用域,然后是函数体外的全局作用域。
71+
72+
#!/usr/bin/env python
73+
#coding:utf-8
74+
75+
def outer_foo():
76+
a = 10
77+
def inner_foo():
78+
a = 20
79+
print "inner_foo,a=", a #a=20
80+
#Python 3的读者,请自行修改为print()函数形式,下同,从略
81+
inner_foo()
82+
print "outer_foo,a=", a #a=10
83+
84+
a = 30
85+
outer_foo()
86+
print "a=", a #a=30
87+
88+
运行结果
89+
90+
inner_foo,a= 20
91+
outer_foo,a= 10
92+
a= 30
93+
94+
仔细观察上述程序和运行结果,你会看出对变量在不同范围进行搜索的规律的。
95+
96+
在Python程序中,变量的作用域是有在函数、类中才能被改变,或者说,如果不是在函数或者类中,比如在循环或者条件语句中,变量都是在同一层级的作用域中。可以再次参考上述的示例,并且可以在上述示例中修改,检测你的理解。
97+
98+
##命名空间
99+
100+
“命名空间是对作用域的一种特殊的抽象”(引自《维基百科》)。下面就继续理解这种抽象。
101+
102+
先看来自《维基百科》的定义,这个定义通俗易懂。
103+
104+
>命名空间(英语:Namespace)表示标识符(identifier)的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。
105+
106+
>例如,设Bill是X公司的员工,工号为123,而John是Y公司的员工,工号也是123。由于两人在不同的公司工作,可以使用相同的工号来标识而不会造成混乱,这里每个公司就表示一个独立的命名空间。如果两人在同一家公司工作,其工号就不能相同了,否则在支付工资时便会发生混乱。
107+
108+
>这一特点是使用命名空间的主要理由。在大型的计算机程序或文档中,往往会出现数百或数千个标识符。命名空间(或类似的方法,见“命名空间的模拟”一节)提供一隱藏區域標識符的機制。通过将逻辑上相关的标识符组织成相应的命名空间,可使整个系统更加模块化。
109+
110+
>在编程语言中,命名空间是对作用域的一种特殊的抽象,它包含了处于该作用域内的标识符,且本身也用一个标识符来表示,这样便将一系列在逻辑上相关的标识符用一个标识符组织了起来。许多现代编程语言都支持命名空间。在一些编程语言(例如C++和Python)中,命名空间本身的标识符也属于一个外层的命名空间,也即命名空间可以嵌套,构成一个命名空间树,树根则是无名的全局命名空间。
111+
112+
>函数和类的作用域可被視作隱式命名空间,它們和可見性、可訪問性和对象生命周期不可分割的联系在一起。
113+
114+
在这段定义中,已经非常清晰地描述了命名空间的含义,特别是如果你已经理解了作用域之后,对命名空间就没有什么陌生感了。
115+
116+
为了凸显命名空间之对Python程序员的重要价值,请在交互模式下,输入:`import this`,可以看到:
117+
118+
>>> import this
119+
The Zen of Python, by Tim Peters
120+
121+
Beautiful is better than ugly.
122+
Explicit is better than implicit.
123+
Simple is better than complex.
124+
Complex is better than complicated.
125+
Flat is better than nested.
126+
Sparse is better than dense.
127+
Readability counts.
128+
Special cases aren't special enough to break the rules.
129+
Although practicality beats purity.
130+
Errors should never pass silently.
131+
Unless explicitly silenced.
132+
In the face of ambiguity, refuse the temptation to guess.
133+
There should be one-- and preferably only one --obvious way to do it.
134+
Although that way may not be obvious at first unless you're Dutch.
135+
Now is better than never.
136+
Although never is often better than *right* now.
137+
If the implementation is hard to explain, it's a bad idea.
138+
If the implementation is easy to explain, it may be a good idea.
139+
Namespaces are one honking great idea -- let's do more of those!
140+
141+
这就是所谓《python之禅》,请看最后一句: Namespaces are one honking great idea -- let's do more of those!
142+
143+
简而言之,命名空间是从所定义的命名到对象的映射集合。
144+
145+
不同的命名空间,可以同时存在,当彼此相互独立互不干扰。
146+
147+
命名空间因为对象的不同,也有所区别,可以分为如下几种:
148+
149+
1. 本地命名空间(Function&Class: Local Namespaces):模块中有函数或者类,每个函数或者类所定义的命名空间就是本地命名空间。如果函数返回了结果或者抛出异常,则本地命名空间也结束了。
150+
2. 全局命名空间(Module:Global Namespaces):每个模块创建它自己所拥有的全局命名空间,不同模块的全局命名空间彼此独立,不同模块中相同名称的命名空间,也会因为模块的不同而不相互干扰。
151+
3. 内置命名空间(Built-in Namespaces):Python运行起来,它们就存在了。内置函数的命名空间都属于内置命名空间,所以,我们可以在任何程序中直接运行它们,比如前面的id(),不需要做什么操作,拿过来就直接使用了。
152+
153+
从网上盗取了一张图,展示一下上述三种命名空间的关系
154+
155+
![](./2images/20803.png)
156+
157+
那么程序在查询上述三种命名空间的时候,就按照从里到外的顺序,即:Local Namespaces --> Global Namesspaces --> Built-in Namesspaces
158+
159+
>>> def foo(num,str):
160+
... name = "qiwsir"
161+
... print locals()
162+
...
163+
>>> foo(221,"qiwsir.github.io")
164+
{'num': 221, 'name': 'qiwsir', 'str': 'qiwsir.github.io'}
165+
>>>
166+
167+
这是一个访问本地命名空间的方法,用`print locals()` 完成,从这个结果中不难看出,所谓的命名空间中的数据存储结构和字典是一样的。
168+
169+
根据习惯,读者一定已经猜测到了,如果访问全局命名空间,可以使用 `print globals()`
170+
171+
对于不同的命名空间,除了存在查找的顺序之外,还有不同的生命周期,即什么时候它存在,什么时候它消失了。对此,在理解上比较简单,那就是哪个部分被读入内存,它相应的命名空间就存在了。比如程序启动,内置命名空间就创建,一直到程序结束;而其它的,比如本地命名空间,就是在函数调用时开始创建,函数执行结束或者抛出异常时结束。
172+
173+
关于命名空间,读者还需要在日后的开发实践中慢慢体会,它会融会到你的编程过程中,有时候你是觉察不到的,正所谓“随风潜入夜,润物细无声”。
174+
175+
------
176+
177+
[总目录](./index.md)   |   [上节:zip()补充](./201.md)   |   [下节:类(1)](./206.md)
178+
179+
如果你认为有必要打赏我,请通过支付宝:**[email protected]**,不胜感激。

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ From beginner to master.
5959
##第叁章 函数
6060

6161
1. [函数(1)](./201.md)==>定义函数方法,调用函数方法,命名方法,使用函数注意事项
62-
2. [函数(2)](./202.md)==>函数返回值,函数文档,形参和实参,命名空间,全局变量和局部变量
62+
2. [函数(2)](./202.md)==>函数返回值,函数文档,形参和实参
6363
3. [函数(3)](./203.md)==>收集参数:`*``**`,及其逆过程,复习参数知识
6464
4. [函数(4)](./204.md)==>递归、传递函数、嵌套函数和装饰器
6565
5. [函数(5)](./237.md)==>filter、map、reduce、lambda、yield
6666
6. [函数练习](./205.md)==>解一元二次方程,统计考试成绩,找素数
6767
7. [zip()补充](./236.md)==>对zip()函数的用法进行补充说明
68-
68+
8. [命名空间](./241.md)==>全局变量和局部变量,作用域,命名空间
6969
#第贰季 进阶
7070

7171
##第肆章 类

0 commit comments

Comments
 (0)