您所在的位置:小祥子 » 编程 » Python » 正文

03 Python 基础

时间:2015-08-13 编辑:《Python 核心编程》 来源:CnBlogs
?? 语句和语法 ?? 变量赋值 ?? 标识符和关键字 ?? 基本风格指南 ?? 内存管理 ?? 第一个 Python 程序 3.1语句和语法 Python 语句中有一些基本规则和特殊字符:
    ?? 井号(#)表示之后的字符为 Python 注释
    ?? 换行 (\n) 是标准的行分隔符(通常一个语句一行)
    ?? 反斜线 ( \ ) 继续上一行
    ?? 分号 ( ; )将两个语句连接在一行中
    ?? 冒号 ( : ) 将代码块的头和体分开
    ?? 语句(代码块)用缩进块的方式体现 (缩进四个空格宽度,避免使用制表符)
    ?? 不同的缩进深度分隔不同的代码块
    ?? Python 文件以模块的形式组织 (当一个模块变得过大,并且驱动了太多功能的话,就应该考虑拆一些代码出来另外建一个模块.) 注释( # )     和很多 Unix 脚本类似,Python 注释语句从 # 字符开始,注释可以在一行 的任何地方开始,解释器会忽略掉该行 # 之后的所有内容。要正确的使用注释。 继续( \ )     Python 语句,一般使用换行分隔,也就是说一行一个语句。一行过长的语句可以使用反斜 杠( \ ) 分解成几行,如下例:         # check conditions         if (weather_is_hot == 1) and \         (shark_warnings == 0):             send_goto_beach_mesg_to_pager()     有两种例外情况一个语句不使用反斜线也可以跨行。         在使用闭合操作符时,单一语句可以 跨多行,例如:在含有小括号、中括号、花括号时可以多行书写。         另外就是三引号包括下的字符串也可以跨行书写。     如果要在使用反斜线换行和使用括号元素换行作一个选择,我们推荐使用括号,这样可读 性会更好。 多个语句构成代码组(:):     缩进相同的一组语句构成一个代码块,我们称之代码组。     像if、while、def 和class 这样 的复合语句,首行以关键字开始,以冒号( : )结束,该行之后的一行或多行代码构成代码组。我们将首行及后面的代码组称为一个子句(clause)。 代码组由不同的缩进分隔     代码的层次关系是通过同样 深度的空格或制表符缩进体现的。     核心风格:缩进四个空格宽度,避免使用制表符          对一个初次使用空白字符作为代码块分界的人来说,遇到的第一个问题是:缩进多大宽度 才合适?两个太少,六到八个又太多,因此我们推荐使用四个空格宽度。         需要说明一点,不同的文本编辑器中制表符代表的空白宽度不一,如果你的代码要跨平台应用,或者会被不同的编辑器读写,建议你不要使用制表符。         使用空格或制表符这两种风格都得到了Python 创始人Guido  van Rossum 的支持,并被收录到Python 代码风格指南文档。 同一行书写多个语句(;)     分号( ; )允许你将多个语句写在同一行上,语句之间用分号隔开,而这些语句也不能在这 行开始一个新的代码块。     必须指出一点, 同一行上书写多个语句会大大降低代码的可读性,Python 虽然允许但不 提倡你这么做。 模块     每一个Python 脚本文件都可以被当成是一个模块。模块以磁盘文件的形式存在。当一个模 块变得过大,并且驱动了太多功能的话,就应该考虑拆一些代码出来另外建一个模块。     模块里的代码可以是一段直接执行的脚本,也可以是一堆类似库函数的代码,从而可以被别的模块导入(import)调用。     模块可以包含直接运行的代码块、类定义、函数定义或这几者的组合。

3.2 变量赋值

赋值运算符     Python 语言中, 等号(=)是主要的赋值运算符。     注意,赋值并不是直接将一个值赋给一个变量, 尽管你可能根据其它语言编程经验认为应该如此。在Python 语言中,对象是通过引用传递的。在赋值时,不管这个对象是新创建的,还是一个已经存在的,都是将该对象的引用(并不是值)赋值给变量。同样的, 如果你比较熟悉C, 你会知道赋值语句其实是被当成一个表达式(可以返回值)。不过这条并不适合于 Python, Python 的赋值语句不会返回值。 链式赋值
>>> y = x = x + 1 >>> x, y (2, 2)
增量赋值
>>> x = 1 >>> x += 1 >>> x 2

多元赋值 (采用这种方式赋值时, 等号两边的对象都是元组)

>>> x, y, z = 1, 2, 'a string' >>> x 1 >>> y 2 >>> z 'a string' Python 的多元赋值方式可以实现无需中间变量交换两个变量的值。

3.3 标识符

合法的Python 标识符     Python 标识符字符串规则和其他大部分用C 编写的高级语言相似:         ?? 第一个字符必须是字母或下划线(_)
        ?? 剩下的字符可以是字母和数字或下划线
        ?? 大小写敏感 关键字

内建

    除了关键字之外,Python 还有可以在任何一级代码使用的“内建”的名字集合,这些名字 可以由解释器设置或使用。     虽然built-in 不是关键字,但是应该把它当作“系统保留字”,不做他用。         然而,有些情况要求覆盖(也就是:重定义,替换)它们。     Python 不支持重载标识符,所以任何时刻都只有一个名字绑定。      我们还可以告诉高级读者built-in 是__builtins__模块的成员,在你的程序开始或在交互 解释器中给出>>>提示之前,由解释器自动导入的。     把它们看成适用在任何一级Python 代码的全局变量。 专用下划线标识符     Python 用下划线作为变量前缀和后缀指定特殊变量。
总结: ?? _xxx 不用'from module import *'导入 ?? __xxx__系统定义名字
?? __xxx 类中的私有变量名
    核心风格:避免用下划线作为变量名的开始         因为下划线对解释器有特殊的意义,而且是内建标识符所使用的符号,我们建议程序员避免用下划线作为变量名的开始。         一般来讲,变量名_xxx 被看作是“私有的”,在模块或类外不可以使用。         当变量是私有的时候,用_xxx 来表示变量是很好的习惯。因为变量名__xxx__对Python 来说有特殊含义,对于普通的变量应当避免这种命名风格。 3.4 基本风格指南     注释,文档,缩进,标识符     模块结构和布局         # (1) 起始行(Unix)         # (2) 模块文档         # (3) 模块导入         # (4) 变量定义         # (5) 类定义         # (6) 函数定义         # (7) 主程序         (1) 起始行             通常只有在类Unix 环境下才使用起始行,有起始行就能够仅输入脚本名字来执行脚本,无         需直接调用解释器。         (2)模块文档             简要介绍模块的功能及重要全局变量的含义,模块外可通过 module.__doc__ 访问这些内 容。          (3)模块导入             导入当前模块的代码需要的所有模块;每个模块仅导入一次(当前模块被加载时);函数内部的模块导入代码不会被执行, 除非该函数正在执行。          (4)变量定义             这里定义的变量为全局变量,本模块中的所有函数都可直接使用。             从好的编程风格角度说, 除非必须,否则就要尽量使用局部变量代替全局变量,如果坚持这样做,你的代码就不但容易维护,而且还可以提高性能并节省内存。          (5)类定义语句             所有的类都需要在这里定义。当模块被导入时class 语句会被执行, 类也就会被定义。类的文档变量是class.__doc__。          (6)函数定义语句             此处定义的函数可以通过module.function()在外部被访问到,当模块被导入时 def 语句会被执行,函数也就都会定义好,函数的文档变量是function.__doc__。          (7) 主程序             无论这个模块是被别的模块导入还是作为脚本直接执行,都会执行这部分代码。通常这里 不会有太多功能性代码,而是根据执行的模式调用不同的函数。                            Figure 3–1 Typical Python file structure     推荐代码风格:主程序调用main()函数 
        主程序代码通常都和你前面看到的代码相似,检查 __name__ 变量的值然后再执行相应的 调用(参阅下一页的核心笔记)。
        主程序中的代码通常包括变量赋值, 类定义和函数定义,随后检查__name__来决定是否调用另一个函数(通常调用main()函数)来完成该模块的功能。             主程序通常都是做这些事。(我们上面的例子中使用test()而不是main()是为了避免你在读到核心笔记前感到迷惑。) 
        不管用什么名字,我们想强调一点那就是:这儿是放置测试代码的好地方。大部分的Python 模块都是用于导入调用的,直接运行模块应该调用该模块的回归测试代码。         请记住,绝大部分的模块创建 的目的是为了被别人调用而不是作为独立执行的脚本。         只有一个模块,也就是包含主程 序的模块会被直接执行,或由用户通过命令行执行,或作为批处理执行, 或由Unix cron 任务定时执行,或通过Web 服务器调用,或通过GUI 执行。     核心笔记:__name__ 指示模块应如何被加载         如果模块是被导入, __name__ 的值为模块名字          如果模块是被直接执行, __name__ 的值为 '__main__' 3.5 内存管理
?? 变量无须事先声明
?? 变量无须指定类型
?? 程序员不用关心内存管理
?? 变量名会被“回收”
?? del 语句能够直接释放资源
变量定义
    在Python 中,无需显式变量声明语句,变量在第一次被赋值时自动声明。
    和其他大多数语言一样,变量只有被创建和赋值后才能被使用。
动态类型
    Python 中不但变量名无需事先声明,而且也无需类型声明。
    Python 语言中, 对象的类型和内存占用都是运行时确定的。
    尽管代码被编译成字节码,Python 仍然是一种解释型语言。
    在创建--也就是赋值时,解释器会根据语法和右侧的操作数来决定新对象的类型。
    在对象创建后,一个该对象的引用会被赋值给左侧的变量。 内存分配     作为一个负责任的程序员,我们知道在为变量分配内存时,是在借用系统资源,在用完之 后, 应该释放借用的系统资源。     Python 解释器承担了内存管理的复杂任务, 这大大简化了应用程序的编写。     你只需要关心你要解决的问题,至于底层的事情放心交给Python 解释器去做就行了。 引用计数     每个对象各有多少个引用, 简称引用计数。

    一个引用计数内部跟踪变量,称为一个引用计数器。

    当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。 增加引用计数     当对象被创建并(将其引用)赋值给变量时,该对象的引用计数就被设置为1。     当同一个对象(的引用)又被赋值给其它变量时,         或作为参数传递给函数, 方法或类实例 时,         或者被赋值为一个窗口对象的成员时,该对象的一个新的引用,或者称作别名,就被创建(则该对象的引用计数自动加1)。 对象的引用计数在      ?? 对象被创建         x = 3.14     ?? 或另外的别名被创建         y = x     ?? 或被作为参数传递给函数(新的本地引用)         foobar(x)     ?? 或成为容器对象的一个元素         myList = [123, x, 'xyz'] 减少引用计数     当对象的引用被销毁时,引用计数会减小。         最明显的例子就是当引用离开其作用范围时,这种情况最经常出现在函数运行结束时,所有局部变量都被自动销毁,对象的引用计数也就随之减少。     当变量被赋值给另外一个对象时,原对象的引用计数也会自动减1:         foo = 'xyz'   #'xyz'  1         bar = foo     #'xyz'  2         foo = 123    #'xyz'  1     其它造成对象的引用计数减少的方式包括使用 del 语句删除一个变量(参阅下一节), 或 者当一个对象被移出一个窗口对象时(或该容器对象本身的引用计数变成了0 时)。     一个对象的引用计数在以下情况会减少:         ?? 一个本地引用离开了其作用范围。比如 foobar()(参见上一下例子)函数结束时。         ?? 对象的别名被显式的销毁。             del y # or del x                 ?? 从现在的名字空间中删除 y                 ?? x 的引用计数减一         ?? 对象的一个别名被赋值给其它的对象             x = 123         ?? 对象被从一个窗口对象中移除             myList.remove(x)         ?? 窗口对象本身被销毁             del myList # or goes out-of-scope 垃圾收集     不再被使用的内存会被一种称为垃圾收集的机制释放。     虽然解释器跟踪对象 的引用计数, 但垃圾收集器负责释放内存。     垃圾收集器是一块独立代码, 它用来寻找引用计数为0 的对象。         它也负责检查那些虽然引用计数大于0 但也应该被销毁的对象。          特定情形会导致循环引用。          一个循环引用发生在当你有至少两个对象互相引用时, 也就是说所有的引用都消失时, 这 些引用仍然存在, 这说明只靠引用计数是不够的。     Python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。     当一个对象的引用计数变为0,解释器会暂停,释放掉这个对象和仅有这个对象可访问(可到达)的其它对象。     作为引用计数的补充, 垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。     在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环。 核心技巧:使用局部变量替换模块变量
    类似 os.linesep 这样的名字需要解释器做两次查询:
        (1)查找os 以确认它是一个模块,
        (2)在这个模块中查找 linesep 变量。因为模块也是全局变量, 我们多消耗了系统资源。
    如果你在一个函数中类似这样频繁使用一个属性,我们建议你为该属性取一个本地变量别名。
    变量查找速度将会快很多--在查找全局变量之前, 总是先查找本地变量。
    这也是一个让你的程序跑的更快的技巧: 将经常用到的模块属性替换为一个本地引用。代码跑得更快,而也不用老是敲那么长的变量名了。 3.6 相关模块和开发工具     Python 代码风格指南(PEP8), Python 快速参考和Python 常见问答都是开发者很重要的“工具”。     另外, 还有一些模块会帮助你成为一个优秀的Python 程序员。
?? Debugger: pdb
?? Logger: logging
?? Profilers: profile, hotshot, cProfile
关键词:

相关文章