引言
:在通常认知中,变量是一段具有特定格式的内存,变量名是内存别名,因为在编码阶段,无法确定内存的具体位置,故事用名称层符号代替.
注意:变量名和指针不同
接下来,静态编译和动态解释性语言对于变量名的处理方式完全不同,静态编译器或连接器会以固定地址,或者直接间接寻址执行代替变量名,也就是说变量名不参与执行过程,可以被剔除 ;但是在解释性语言中,名字和对象通常是两个运行期试题,名字不但有自己的类型,还需要分配内存,并且介入执行过程,甚至可以说,名字才是动态模型的基础.(比如 C#,JAVA,Python,PhP都是动态语言).
如果将内存寻址比喻成为顾客按照编号寻找服务柜台,那么名字就是一个接待员,任何时候,顾客都只能够通过他间接与目标服务互动.从表面看这好像是高级会员才有的东西,但是实际上增加了中间环节和额外的开销,于性能不利,但是好处是,接待员和服务之间拥有更多的调整空间,可以用来增加代理和安全机制,甚至为缓存管理提供机会,后续会更新出有关元变成的内容.
当然名字必须和目标对象关联起来才有意义.
In [1]: x
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-6fcf9dfbd479> in <module>
----> 1 x
NameError: name 'x' is not defined
In [2]:
最直接的关联操作就是赋值,然后对名字的引用都被解释为对目标对象进行操作
In [2]: x = 100
In [3]: x
Out[3]: 100
In [4]: x +=2
In [5]: x
Out[5]: 102
In [6]:
赋值步骤,
- 将准备好右值目标对象(100)
- 准备好名字 (x)
- 在名字空间里为两者建立关联(namespace {x:100})
即便如此,名字与目标对象之间也仅仅是引用关联,名字只负责找人,但对于此人一无所知.只有在运行期间才知道名字引用的目标类型,所以说Python是一种动态语法/
name have no type,but objects do
名字空间
名字空间(namespace) 是上下文环境中专门用来储存名字和目标引用关联的容器,如图所示
对于Python而言,每个模块(源码文件)都有一个全局名字空间,而根据代码作用域,又有当前名字或者本地名字空间一说.如果在模块级别执行,那么当前名字空间和全局名字空间相同,但是在函数中,当前名字就是专值函数作用域.
名字空间默认使用字典(dict) 数据结构,有多个键值(key/value) 组成.
内置函数globals和locals分别返回全局名字空间,和本地名字空间字典.
In [6]: x = 100
In [7]: id(globals())
Out[7]: 140077279009480
In [8]: id(locals())
Out[8]: 140077279009480
In [9]: globals()
Out[9]:
{'In': ['',
'x',
'x = 100',
........
In [11]: def test():
...: x = 'hello world'
...: print(locals()) # 指向本地命名空间
...: print("locals:",id(locals()))
...: print("globals",id(globals())) # 指向全局命名空间
...:
...:
In [12]: test() # 在函数作用域调用
{'x': 'hello world'} # 此时,locals 输入函数名字空间
locals: 140077240118024 # locals != globals
globals 140077279009480
可见,globals 总是固定指向模块名字空间,而locals 则指向当前作用域环境
在初步了解后,我们甚至可以直接修改名字空间建立关联医用,这与传统变量定义方式有何不同.
In [17]: globals()["hello"] = "hello,world"
In [18]: globals()["number"] = 123455
In [19]: hello
Out[19]: 'hello,world'
In [20]: number
Out[20]: 123455
并非所有时候都能直接操作命名空间,函数执行使用缓存机制,可以直接修改本地名字空间未必有效,在正常编码时,应该尽可能避免直接修改名字空间
在名字空间的字典中,名字只是简单字符串主键,其自身数据结构里面没有任何目标对象信息,通过名字访问目标对象,无非是以名字为主键去字典中读取目标对象指针引用.也正因为如此,名字可以重新关联另外一个对象,完全不在于其类型是否与前任相同.
In [21]: x = 100
In [22]: x
Out[22]: 100
In [23]: id(x)
Out[23]: 10922592
In [24]: globals()
Out[24]:
{'In': ['',
'x',
'x = 100',
......
In [25]: x = "abc" #重新关联一个对象
In [26]: x
Out[26]: 'abc'
In [27]: id(x) # 通过输出的id可以看出关联新对象,并非修改原对象内容
Out[27]: 140077358909568
In [28]: globals() # 名字空间的引用变更
Out[28]:
{'In': ['',
'x',
'x = "abc",
赋值操作仅仅是让名字在命名空间中重新关联,并非是修改原对象
和一个名字只能够引用一个对象不同,单个对象可以拥有多个名字,无论是在相同或者不相同的名字空间中
一个人在公司中,他可以是老王,王大叔,王哥哥等..这时这个人在办公室中就拥有了多个名字,出了办公司,在全公司,(另外一个命名空间)范围中,他还可以有王处长,王老板等其他名字.
命名规则
名字应该有实际含义,并且阅读和理解的字母或者单词组合
- 以字母或者下划线开头
- 区分大小写
- 不能够使用保留关键字
In [3]: x = "abc"
In [4]: X = "1"
In [5]: X is x
Out[5]: False
In [6]:
为了统一命名风格
- 类型名称使用CapWords 格式
- 模块文件名,函数,方法成员等使用lower_case_with格式
- 全局变量名通常使用全部大写格式
- 避免与内置变量或者标准库的常用类型同名,因为这样容易造成误解
尽管Python3 中可以使用汉字作为变量名,但是并不推荐
In [7]: import keyword
In [8]: keyword.kwlist # 打印出Python3中的保留关键词
Out[8]:
['False',
'None',
'True',
'and',
'as',
'assert',
'break',
'class',
'continue',
'def',
'del',
'elif',
'else',
'except',
'finally',
'for',
'from',
'global',
'if',
'import',
'in',
'is',
'lambda',
'nonlocal',
'not',
'or',
'pass',
'raise',
'return',
'try',
'while',
'with',
'yield']
注意 python3中print 不再是关键字,是一个函数,但是在python2中仍旧是保留关键字