Python核心编程--学习笔记--3--Python基础

  本章介绍基本的Python语法、编程风格;并简要介绍标识符、变量和关键字,以及变量占用内存的分配和回收;最后给出一个较大的Python样例程序来体验这些特性。

 

1 语句和语法

1.1 注释

  可以在一行的任何位置,以 # 开头,直至行尾都是注释。

1.2 反斜线继续上一行

  一行过长的语句,可以用反斜线 \ 分解成几行。\ 必须是该行的最后一个字符(其后不能有空格等其他任何字符)。

  闭合符号:小括号()、中括号[]、花括号{}、三引号"""  """/'''  ''',其内的语句可以跨行书写,不需使用 \ 。

1.3 多个语句构成代码组

  缩进相同的一组语句构成一个代码块,称为代码组。例如:if、while等关键字开头的首行,之后的一行或多行就是一个代码组。首行及之后的代码组称为一个子句(clause)。

1.4 代码组由不同的缩进分隔

  代码的层次关系通过同样深度的空格或制表符缩进来体现,同一代码组的代码行必须严格左对齐。

  没有缩进的代码块是最高层次的,称为脚本的main部分。

1.5 同一行书写多个语句

  多个语句写在同一行的话,之间用分号(;)隔开,这些语句同属一个代码块(子句),中间不能开始新的代码块。

1.6 模块

  每个Python脚本文件都可以当成一个模块,模块以磁盘文件形式存在。如果一个模块太大,功能太多,应考虑拆分到多个模块中。

2 变量赋值

  Python通过等号=、增量赋值运算符+=(-=、*=等)来赋值。

  Python中,对象是通过引用传递的。在赋值时,不管这个对象是新创建的,还是一个已经存在的,都是将该对象的引用(并不是值)赋值给变量。(要有对象的概念,名字只是一个符号/指针,指向被赋值的对象)

  Python中的链式赋值(多重赋值),只是对象的同一个引用被赋给了多个变量。Python的赋值语句不会返回值(与C不同)

>>> x = y = z = 1
>>> x
1
>>> y
1
>>> z
1
>>> x = ( y = 13 )
  File "<stdin>", line 1
    x = ( y = 13 )
            ^
SyntaxError: invalid syntax

  增量赋值,同样适合与列表/字符串;++n、--n被解析为+(+n)、-(-n),n++、n--是语法错误。

+=    -=   *=   /=   %=   **=  #Python支持的增量赋值符
<<=   >>=   &=   ^=   |=
>>> aList = [123, 'xyz']
>>> aList += [45.6e7]  #列表加
>>> aList
[123, 'xyz', 456000000.0]

>>> n=3
>>> --n  #与C语言不同
3
>>> n
3
>>> n--  #语法错误
  File "<stdin>", line 1
    n--
      ^
SyntaxError: invalid syntax

  多元赋值,即同时给多个变量赋值: 

>>> x, y, z = 1, 2, 'a string'  #等号两边实质是元组,建议总是加上括号,即  (x, y, z) = (1, 2, 'string')
>>> x
1
>>> y
2
>>> z
'a string'
>>> x, y = 1, 2
>>> x
1
>>> y
2
>>> x, y = y, x  #不需要中间变量,即可交换两个变量值
>>> x
2
>>> y
1 

 3 标识符

  合法标识符:同C语言,字母或下划线_开头,后面可以是字母、数字或下划线;大小写敏感。

  关键字:关键字列表kwlist和iskeyword()函数都放入了keyword模块以便查阅。

and

as assert break
class continue def del
elif else except exec
finally for from global
if import in is
lambda not or pass
print raise return try
while with yield None
>>> import keyword
>>> keyword.iskeyword('and')
True

  内建:除了关键字之外,Python还有可以在任何一级代码使用的“内建”的名字集合,这些名字可以由解释器设置或使用,应该把它当作“系统保留字”,不做他用。Python不支持重载标识符,任何时刻都只有一个名字绑定。内建built-in是__builtins__模块的成员,在程序开始或在交互解释器中给出>>>提示之前,由解释器自动导入的。把它们看成适用在任何一级Python代码的全局变量

  类变量的专用下划线标识符:

_xxx      #不用'from module import *'导入,外部可以访问,但是应视其为 私有变量
__xxx__   #系统定义名字,特殊变量,可以直接访问,自己不要使用这种变量名
__xxx     #类中的私有变量名,外部无法访问(实质上,一般的编译器,都将其改名为 _所属类名__xxx)

 4 基本风格指南

  添加注释,写字串文档,采用合适缩进,尽量使用简短的变量名。  

import this  #可以看到Python之禅

4.1 模块结构和布局

  编写脚本文件pytest.py,并执行:

#/usr/bin/env python        #1.起始行(Unix) / 模块注释
# -*- coding: utf-8 -*-     #如果代码包含中文,需要添加该行(由于出现在该注释之前,上一行的中文注释会被报错)

"this is a test module"     #2.模块文档,可通过 模块名.__doc__ 直接访问

import sys    #3.导入所需的模块
import os

debug = True    #4.全局变量。尽量少使用全局变量,有利于代码维护,提高性能,节省内存

class FooClass(object):    #5.类定义,模块被导入时类就会被定义
    "Foo class"            #类文档,可通过 模块名.类名.__doc__ 来访问
    pass

def test():            #6.函数定义,模块被导入时类就会被定义,可通过 模块名.函数名() 来访问
    "test function"    #函数文档,可通过 模块名.函数名.__doc__ 来访问
    foo = FooClass()   #类对象
    if debug:
        print 'ran test()'

if __name__ == '__main__':    #7.主程序部分,通常只包含函数调用,无论是被导入还是作为脚本执行,都会执行这部分代码
    test()                    #如果模块直接执行,则__name__值为'__main__',该句执行;如果被导入,则__name__值为模块名
$ python pytest.py    #作为脚本直接执行
ran test()

>>> import pytest    #交互解释器中,导入模块,主程序部分的if条件不成立。模块名即去掉后缀的文件名
>>> pytest.__doc__  #模块文档
'this is a test module'
>>> pytest.FooClass.__doc__    #模块内的类文档
'Foo class'
>>> pytest.test()    #执行模块内函数
ran test()

  没有缩进的代码,在模块被导入时就会被执行(所以导入模块时,类、函数就会被定义),所以安全的写代码方式:除了真正要执行的代码,把其他功能代码都写在函数当中。

  绝大部分的模块,其创建的目的就是被导入,所以应该尽量只包括类、函数的定义。很多项目都只有一个主程序部分,由它导入模块、调用函数。

4.2 在主程序中书写测试代码

  测试代码应该在模块直接执行时被执行,模块被导入时不执行。(即用到上面例子的最后if语句)

  测试代码应随着测试条件、结果变更时及时更新,且每次代码更新后都应执行测试代码,以确认没有新问题。

5 内存管理

5.1 变量定义

  变量无需声明,第一次被赋值时自动声明。

>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>> x=4
>>> x
4

5.2 动态类型

  变量的类型和占用的内存,都是运行时确定的。赋值时,解释器根据语法和右操作数来决定新对象类型。对象创建后,将其引用赋给左边变量。

5.3 内存分配

  Python解释器负责内存管理,程序员无需关心。

5.4 引用计数

  Python内部记录着使用中的对象各有多少引用,对象的引用数目简称引用计数。当对象的引用计数为0时,它就被垃圾回收。

  增加引用计数:

x = 3.14    #对象被创建
y = x      #对象的别名被创建,即对象被赋值给一个新变量
foobar(x)   #对象作为参数传递给函数(新的本地引用)
myList = [123, x, 'xyz']    #对象成为容器对象的一个元素

  减少引用计数:

一个本地引用离开了其作用范围,比如上面的foobar()函数结束时。
del y   #对象的别名被显式的销毁
x = 123  #对象的一个别名被赋值给其它的对象 
myList.remove(x)  #对象被从一个窗口对象中移除
del myList  #窗口对象本身 离开作用范围 或 被销毁

  del语句:

del  obj1[, obj2[...]]     #可以一次删除多个对象的引用

  上面的 del y,会将y从现在的名字空间中删除,且y指向的对象引用计数减1。再执行del x后,该对象引用计数为0,对象从此“无法访问”。追踪或调试程序会增加对象的一个额外引用。

5.5 垃圾收集

  垃圾收集器是一段独立代码,用来寻找 引用计数为0的对象,也检查那些 引用计数不为0但应该被销毁的对象,然后释放其内存。

  当两个对象相互引用时,引用计数可能不会为0,因此垃圾收集器也包含循环垃圾收集器,来清理未引用的循环。

6 第一个Python程序

  介绍两个处理文本文件的脚本,分别实现写入/读取文件内容。

  makeTextFile.py,创建文件,输入每行文本:

#!/usr/bin/env python

'makeTextFile.py -- create text file'

import os
ls = os.linesep    #换行符,Unix为'\n',Windows为'\r\n',用os.linesep则不需关心平台。起个别名,减少名字查询,代码跑得快,名字也短

while True:
    fname = raw_input('Enter filename: ')
    if os.path.exists(fname):    #判断文件是否已存在,存在则返回True
        print "ERROR: '%s' already exists" % fname
    else:
        break

all = []
print "\nEnter lines ('.' by itself to quit).\n"

while True:
    entry = raw_input('> ')
    if entry == '.':    #输入'.'时结束输入
        break
    else:
        all.append(entry)    #将输入内容添加到列表中

fobj = open(fname, 'w')
fobj.writelines(['%s%s' % (x, ls) for x in all])    #列表解析。writelines接收包含行结束符的结果列表,并写入文件
fobj.close()
print 'DONE!'

  readTextFile.py,读取并显示文本内容:

#!/usr/bin/env Python

'readTextFile.py -- read and display text file'

fname = raw_input('Enter filename: ')
print

try:    #捕获异常语句,适用于没有合适函数处理异常的情况。这里没有使用上面的os.path.exsits()函数,因为打开文件错误可能不仅仅是文件名错误导致
    fobj = open(fname, 'r')
except IOError, e:    #如果打开文件错误,则捕获异常,并输出异常提示信息,然后跳过else
    print "*** file open error:", e
else:   #如果成功打开文件,则执行该子句
    for eachLine in fobj:
        print eachLine,  #创建文件时,我们人为加入了换行符,所以这里打印的时候要抑制print生成的换行符
    fobj.close()

 7 相关模块和开发工具

  工具:Python代码风格指南(PEP8),Python快速参考和Python常见问答。

  模块:

  • 调试模块pdb:允许设置(条件)断点,代码逐行执行,检查堆栈。还支持事后调试。
  • 日志模块logging:定义了一些函数和类帮程序实现灵活的日志系统。有五级日志级别:紧急,错误,警告,信息,调试。
  • 性能测试模块:profile,hotshot,cProfile。

 

练习题

3–11 字符串格式化 不再抑制readTextFile.py中print语句生成的 NEWLINE 字符,修改你的代码,在显示一行之前删除每行末尾的空白。这样,你就可以移除print语句末尾的逗号了。

提示:使用字符串对象的strip()方法 

 1 #!/usr/bin/env Python
 2 
 3 'readTextFile.py -- read and display text file'
 4 
 5 fname = raw_input('Enter filename: ')
 6 print
 7 
 8 try:
 9     fobj = open(fname, 'r')
10 except IOError, e:
11     print "*** file open error:", e
12 else:
13     for eachLine in fobj:
14         print eachLine.strip()    #将逗号改为 .strip() ,此时读入的字串后面的换行符作为空白被舍弃,但是仍然输出print的换行符
15     fobj.close() 
3-11 View Code 
posted @ 2013-11-25 23:20  阿杰的专栏  阅读(413)  评论(0编辑  收藏  举报