第三章 python基础
花了一个星期多看了 《learn python the hard way》,只能说掌握了皮毛的皮毛,今天开始学习看《core python programming》。
同样,也分享自己的学习笔记,督促自己,激励自己。
3.1 语句和语法
Python 语句中有一些基本规则和特殊字符:
井号(#)表示之后的字符为 Python 注释
换行 (\n) 是标准的行分隔符(通常一个语句一行)
反斜线 ( \ ) 继续上一行
冒号 ( : ) 将代码块的头和体分开
语句(代码块)用缩进块的方式体现
不同的缩进深度分隔不同的代码块
Python 文件以模块的形式组织
分号 ( ; )将两个语句连接在一行中
1 print "hello world " ; print " hi world"
反斜线 ( \ ) 继续上一行
Python 语句,一般使用换行分隔,也就是说一行一个语句。一行过长的语句可以使用反斜
杠( \ ) 分解成几行,如下例:
if (weather_is_hot == 1) and \ (shark_warnings == 0): send_goto_beach_mesg_to_pager()
有两种例外情况一个语句不使用反斜线也可以跨行。在使用闭合操作符时,单一语句可以
跨多行,例如:在含有小括号、中括号、花括号时可以多行书写。另外就是三引号包括下的字
符串也可以跨行书写。
3.2 变量赋值
注意,赋值并不是直接将一个值赋给一个变量, 尽管你可能根据其它语言编程经验认为应
该如此。在Python 语言中,对象是通过引用传递的。在赋值时,不管这个对象是新创建的,还
是一个已经存在的,都是将该对象的引用(并不是值)赋值给变量。如果此刻你还不是100%理
解清楚,也不用着急。 在本章的后面部分,我们还会再讨论这个话题, 现在你只需要有这么 ????????????
一个概念即可。
>>> x = 1
>>> y = (x = x + 1) # assignments not expressions! File "<stdin>", line 1
y = (x = x + 1)
^
SyntaxError: invalid syntax
增量赋值通过使用赋值运算符,将数学运算隐藏在赋值过程当中。如果您用过C、C++或者
Java,会觉得下面的运算符很熟悉。
+= -= *= /= %= **=
<<= >>= &= ^= |=
“多元”赋值
另一种将多个变量同时赋值的方法我们称为多元赋值(multuple)。这不是官方Python 术
语, 而是我们将 "mul-tuple"连在一起自造的。因为采用这种方式赋值时, 等号两边的对象
都是元组(我们在2.8 节讲过元组是一种Python 基本数据类型)。
>>> x, y, z = 1, 2, 'a string'
在上面的例子里, 两个整数对象(值分别为1 和2)及一个字符串对象, 被分别赋值给
x, y 和z。通常元组需要用圆括号(小括号)括起来,尽管它们是可选的。我们建议总是加上
圆括号以使得你的代码有更高的可读性。
>>> (x, y, z) = (1, 2, 'a string')
在上面的C 代码片段中,变量x 和变量y 的值被互相交换。 临时变量tmp 用于在将y 赋
值给x 前先保存x 的值。将y 的值赋给x 之后, 才可以将保存在tmp 变量中的x 的值赋给y。
Python 的多元赋值方式可以实现无需中间变量交换两个变量的值。
# swapping variables in Python
>>> x, y = 1, 2
>>> x
1
>>> y
2
>>> x, y = y, x
>>> x
2
>>> y
1
显然, Python 在赋值之前已经事先对x 和y 的新值做了计算。
3.3.4 专用下划线标识符
Python 用下划线作为变量前缀和后缀指定特殊变量。稍后我们会发现,对于程序来说,其
中的有些变量是非常有用的,而其他的则是未知或无用的。这里对Python 中下划线的特殊用法
做了总结:
_xxx 不用'from module import *'导入
__xxx__系统定义名字
__xxx 类中的私有变量名
核心风格:避免用下划线作为变量名的开始
因为下划线对解释器有特殊的意义,而且是内建标识符所使用的符号,我们建议程序员避
免用下划线作为变量名的开始。一般来讲,变量名_xxx 被看作是“私有的”,在模块或类外不
可以使用。当变量是私有的时候,用_xxx 来表示变量是很好的习惯。因为变量名__xxx__对
Python 来说有特殊含义,对于普通的变量应当避免这种命名风格。
缩进
因为缩进对齐有非常重要的作用,您得考虑用什么样的缩进风格才让代码容易阅读。在选
择要空的格数的时候,常识也起着非常大的作用。
1 或 2 可能不够,很难确定代码语句属于哪个块
8 至10 可能太多,如果代码内嵌的层次太多,就会使得代码很难阅读。四个空格非常的
流行,更不用说Python 的创造者也支持这种风格。五和六个也不坏,但是文本编辑器通常不支
持这样的设置,所以也不经常使用。三个和七个是边界情况。
当使用制表符Tab 的时候,请记住不同的文本编辑器对它的设置是不一样。推荐您不要
使用Tab,如果您的代码会存在并运行在不同的平台上,或者会用不同的文本编辑器打开,推
荐您不要使用Tab。
3.5 内存管理
到现在为止, 你已经看了不少 Python 代码的例子。我们本节的主题是变量和内存管理的
细节, 包括:
变量无须事先声明
变量无须指定类型
程序员不用关心内存管理
变量名会被“回收”
del 语句能够直接释放资源
3.5.1 变量定义
大多数编译型语言,变量在使用前必须先声明,其中的 C 语言更加苛刻:变量声明必须位
于代码块最开始,且在任何其他语句之前。其它语言,像C++和Java,允许“随时随地”声明
变量,比如,变量声明可以在代码块的中间,不过仍然必须在变量被使用前声明变量的名字和
类型。在Python 中,无需此类显式变量声明语句,变量在第一次被赋值时自动声明。和其他大
多数语言一样,变量只有被创建和赋值后才能被使用。
3.5.4 引用计数
要保持追踪内存中的对象, Python 使用了引用计数这一简单技术。也就是说Python 内部
记录着所有使用中的对象各有多少引用。你可以将它想像成扑克牌游戏“黑杰克”或“21 点”。
一个内部跟踪变量,称为一个引用计数器。至于每个对象各有多少个引用, 简称引用计数。当
对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的
引用计数变为0 时, 它被垃圾回收。(严格来说这不是100%正确,不过现阶段你可以就这么
认为)
增加引用计数
当对象被创建并(将其引用)赋值给变量时,该对象的引用计数就被设置为1。
当同一个对象(的引用)又被赋值给其它变量时,或作为参数传递给函数, 方法或类实例
时, 或者被赋值为一个窗口对象的成员时,该对象的一个新的引用,或者称作别名,就被创建
(则该对象的引用计数自动加1)。
图3–2 有两个引用的同一对象
请看以下声明:
x = 3.14
y = x
语句 x=3.14 创建了一个浮点数对象并将其引用赋值给 x。 x 是第一个引用, 因此,该
对象的引用计数被设置为1。语句 y=x 创建了一个指向同一对象的别名 y(参阅图3-2)。事
实上并没有为Y 创建一个新对象, 而是该对象的引用计数增加了1 次(变成了2)。这是对象
引用计数增加的方式之一。还有一些其它的方式也能增加对象的引用计数, 比如该对象作为参
数被函数调用或这个对象被加入到某个容器对象当中时。
总之,对象的引用计数在
对象被创建
x = 3.14
或另外的别名被创建
y = x
或被作为参数传递给函数(新的本地引用)
foobar(x)
或成为容器对象的一个元素
myList = [123, x, 'xyz']
下面让我们来看一下引用计数是如何变少的。
减少引用计数
当对象的引用被销毁时,引用计数会减小。最明显的例子就是当引用离开其作用范围时,
这种情况最经常出现在函数运行结束时,所有局部变量都被自动销毁,对象的引用计数也就随
之减少。
当变量被赋值给另外一个对象时,原对象的引用计数也会自动减1:
foo = 'xyz'
bar = foo
foo = 123
当字符串对象"xyz"被创建并赋值给foo 时, 它的引用计数是1. 当增加了一个别名 bar
时, 引用计数变成了2. 不过当foo 被重新赋值给整数对象123 时, xyz 对象的引用计数自
动减1,又重新变成了1.
其它造成对象的引用计数减少的方式包括使用 del 语句删除一个变量(参阅下一节), 或
者当一个对象被移出一个窗口对象时(或该容器对象本身的引用计数变成了0 时)。 总结一下,
一个对象的引用计数在以下情况会减少:
引用离开了其作用范围。比如 foobar()(参见上一下例子)函数结束时。
对象的别名被显式的销毁。
del y # or del x
对象的一个别名被赋值给其它的对象
x = 123
对象被从一个窗口对象中移除
myList.remove(x)
窗口对象本身被销毁
del myList # or goes out-of-scope
del 语句
Del 语句会删除对象的一个引用,它的语法是:
del obj1[, obj2[,... objN]]
例如,在上例中执行del y 会产生两个结果:
从现在的名字空间中删除 y
x 的引用计数减一
引申一步, 执行 del x 会删除该对象的最后一个引用, 也就是该对象的引用计数会减为
0, 这会导致该对象从此“无法访问”或“无法抵达”。 从此刻起, 该对象就成为垃圾回收
机制的回收对象。 注意任何追踪或调试程序会给一个对象增加一个额外的引用, 这会推迟该
对象被回收的时间。