前言:学习《简明 Python 教程》Swaroop, C. H. 著 沈洁元 译 www.byteofpython.info 摘录,方便以后使用查阅。
本译本作为原书的派生作品,依照创作公用约定(署名-非派生作品-非商业用途)发布。转载编辑传播请署上作者名字<沈洁元>,就可以免费复制、分发和展示本译本。未得到作者/译作者的允许,禁止把本译本用于商业目的,也不能再在本译本的基础上修改、派生新的作品。
如果对本书和译本有任何批评和建议,十分欢迎与译本作者联系:orion_val@163.com。
面向过程的 编程:根据操作数据的函数或语句块来设计程序。
面向对象的 编程:把数据和功能结合起来,用称为对象的东西包裹起来组织程序的方法。编写大型程序或是寻求一个更加合适的解决方案的时候,就得使用面向对象的编程技术。
类和对象是面向对象编程的两个主要方面。
**类:**创建一个新类型,可以包含变量(域)、函数(方法)等。
**对象:**是类的实例。
举例:一个int类型的变量,存储整数的变量是int类的实例(对象)。比如,(int类型)Integ=100,Integ就是一个int类的对象(实例)。
给C/C++/Java/C#程序员的注释
注意,即便是整数也被作为对象(属于int类)。这和C++、Java(1.5版之前)把整数纯粹作为类型是不同的。
对象可以使用普通的 属于 对象的变量存储数据。属于一个对象或类的变量被称为域。 对象也可以使用 属 于 类的函数来具有功能。这样的函数被称为类的方法。域和方法可以合称为类的属性。
域有两种类型——属于每个实例/类的对象或属于类本身。它们分别被称为实例变量和类变量。(后面继承讲到:类本身的域,叫共享域;每个实例/对象的域,叫私有域。)
类使用class关键字创建。类的域和方法被列在一个缩进块中。
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称,但是在调用这个方法的时候你不为这个参数赋值,Python会提供这个值。这个特别的变量指对象本身,按照惯例它的名称是self。
虽然可以给这个参数任何名称,但是 强烈建议 使用self这个名称——其他名称都是不赞成使用的。使用一个标准的名称有很多优点——你的程序读者可以迅速识别它,如果使用self的话,还有些IDE(集成开发环境)也可以帮助你。
Python中的self等价于C++中的self指针。
你一定很奇怪Python如何给self赋值以及为何不需要给它赋值。举一个例子会使此变得清晰。假如你有一个类称为MyClass和这个类的一个实例MyObject。当你调用这个对象的方法MyObject.method(arg1, arg2)的时候,这会由Python自动转为MyClass.method(MyObject, arg1, arg2)——这就是self的原理了。
这也意味着如果有一个不需要参数的方法,还是得给这个方法定义一个self参数。
创建一个类:
例 创建一个类
#!/usr/bin/python
# Filename: simplestclass.py
class Person:
pass # An empty block
p = Person()
print p
#输出
$ python simplestclass.py
<__main__.Person instance at 0xf6fcb18c>
使用class语句后跟类名,创建了一个新的类。这后面跟着一个缩进的语句块形成类体。在这个例子中,使用了一个空白块,它由pass语句表示。
接下来,使用类名后跟一对圆括号来创建一个对象/实例。为了验证,简单地打印了这个变量的类型。它告诉我们已经在__main__模块中有了一个Person类的实例。
可以注意到存储对象的计算机内存地址也打印了出来。
类/对象可以拥有像函数一样的方法,这些方法与函数的区别只是一个额外的self变量。
#例 使用对象的方法
#!/usr/bin/python
# Filename: method.py
class Person:
def sayHi(self): #类的方法,参数必须有self,没有其他输入参数
print 'Hello, how are you?'
p = Person()
p.sayHi()
# This short example can also be written as Person().sayHi()
#输出
$ python method.py
Hello, how are you?
self的用法:注意sayHi方法没有任何参数,但仍然在函数定义时有self。
在Python的类中有很多方法的名字有特殊的重要意义。__init__方法是其一。
** __init__方法在类的一个对象被建立时,马上运行** 。 这个方法可以用来对对象做一些希望的 初始化 。注意,这个名称的开始和结尾都是双下划线。
#例 使用__init__方法
#!/usr/bin/python
# Filename: class_init.py
class Person:
def __init__(self, name):
self.name = name
def sayHi(self):
print 'Hello, my name is', self.name
p = Person('Swaroop')
p.sayHi()
# This short example can also be written as Person('Swaroop').sayHi()
#输出
$ python class_init.py
Hello, my name is Swaroop
把__init__方法定义为取一个参数name(以及普通的参数self)。在这个__init__里,只是创建一个新的域,也称为name。注意它们是两个不同的变量,尽管它们有相同的名字。点号能够区分它们。
最重要的是,没有专门调用__init__方法,只是在创建一个类的新实例的时候,把参数包括在圆括号内跟在类名后面,从而传递给__init__方法。这是这种方法的重要之处。
现在,我们能够在我们的方法中使用self.name域。这在sayHi方法中得到了验证。
类与对象的数据部分:它们只是与类和对象的名称空间 绑定 的普通变量,即这些名称只在这些类与对象的前提下有效。ps:理解即是类或对象的变量。
有两种类型的 域 ——类的变量和对象的变量,它们根据是类还是对象 拥有 这个变量而区分。
类的变量: 由一个类的所有对象(实例)共享使用。只有一个类变量的拷贝,所以当某个对象对类的变量做了改动的时候,这个改动会反映到所有其他的实例上。 – 共享
对象的变量:由类的每个对象/实例拥有。因此每个对象有自己对这个域的一份拷贝,即它们不是共享的,在同一个类的不同实例中,虽然对象的变量有相同的名称,但是是互不相关的。 --私有独立
#例 使用类与对象的变量
#!/usr/bin/python
# Filename: objvar.py
class Person:
'''Represents a person.''' #文档字符串
population = 0 #类的变量/域
def __init__(self, name):
'''Initializes the person's data.'''
self.name = name #对象的变量/域
print '(Initializing %s)' % self.name
# When this person is created, he/she
# adds to the population
Person.population += 1
def __del__(self):
'''I am dying.'''
print '%s says bye.' % self.name
Person.population -= 1
if Person.population == 0:
print 'I am the last one.'
else:
print 'There are still %d people left.' % Person.population
def sayHi(self):
'''Greeting by the person.
Really, that's all it does.'''
print 'Hi, my name is %s.' % self.name
def howMany(self):
'''Prints the current population.'''
if Person.population == 1:
print 'I am the only person here.'
else:
print 'We have %d persons here.' % Person.population
swaroop = Person('Swaroop')
swaroop.sayHi()
swaroop.howMany()
kalam = Person('Abdul Kalam')
kalam.sayHi()
kalam.howMany()
swaroop.sayHi()
swaroop.howMany()
#输出
$ python objvar.py
(Initializing Swaroop)
Hi, my name is Swaroop.
I am the only person here.
(Initializing Abdul Kalam)
Hi, my name is Abdul Kalam.
We have 2 persons here.
Hi, my name is Swaroop.
We have 2 persons here.
Abdul Kalam says bye.
There are still 1 people left.
Swaroop says bye.
I am the last one
说明类与对象的变量的本质:这里,population属于Person类,因此是一个类的变量。name变量属于对象(它使用self赋值)因此是对象的变量。
__init__方法用一个名字来初始化Person实例。在这个方法中,让population增加1,这是因为增加了一个人。同样可以发现,self.name的值根据每个对象指定,这表明了它作为对象的变量的本质。
记住,只能使用self变量来参考同一个对象的变量和方法。这被称为 属性参考 。
docstring对于类和方法同样有用:可以在运行时使用Person.__doc__和Person.sayHi.__doc__来分别访问类与方法的文档字符串。
就如同__init__方法一样,还有一个特殊的方法__del__,它在对象消逝的时候被调用。对象消逝即对象不再被使用,它所占用的内存将返回给系统作它用。在这个方法里面,只是简单地把Person.population减1。
当对象不再被使用时,__del__方法运行,但是很难保证这个方法究竟在 什么时候 运行。如果想要指明它的运行,就得使用del语句,就如同我们在以前的例子中使用的那样。
给C++/Java/C#程序员的注释
Python中所有的类成员(包括数据成员)都是 公共的 ,所有的方法都是 有效的 。只有一个例外:如果你使用的数据成员名称以 双下划线前缀 比如 privatevar,Python的名称管理体系会有效地把它作为私有变量。这样就有一个惯例,如果某个变量只想在类或对象中使用,就应该以单下划线前缀。而其他的名称都将作为公共的,可以被其他类/对象使用。记住这只是一个惯例,并不是Python所要求的(与双下划线前缀不同)。同样,注意__del 方法与 destructor 的概念类似。
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过 继承 机制。继承完全可以理解成类之间的 类型和子类型 关系。
举例:
问题:
假设想要写一个程序来记录学校之中的教师和学生情况。他们有一些共同属性,比如姓名、年龄和地址。他们也有专有的属性,比如教师的薪水、课程和假期,学生的成绩和学费。
分析:
可以为教师和学生建立两个独立的类来处理它们,但是这样做的话,如果要增加一个新的共有属性,就意味着要在这两个独立的类中都增加这个属性。这很快就会显得不实用。
一个比较好的方法是创建一个共同的类称为SchoolMember然后让教师和学生的类 继承 这个共同的类。即它们都是这个类型(类)的子类型,然后我们再为这些子类型添加专有的属性。
使用这种方法有很多优点。如果我们增加/改变了SchoolMember中的任何功能,它会自动地反映到子类型之中。例如,要为教师和学生都增加一个新的身份证域,那么只需简单地把它加到SchoolMember类中。然而,在一个子类型之中做的改动不会影响到别的子类型。另外一个优点是可以把教师和学生对象都作为SchoolMember对象来使用,这在某些场合特别有用,比如统计学校成员的人数。一个子类型在任何需要父类型的场合可以被替换成父类型,即对象可以被视作是父类的实例,这种现象被称为多态现象。
另外,我们会发现在 重用 父类的代码的时候,无需在不同的类中重复它。而如果使用独立的类的话,我们就不得不这么做了。
在上述的场合中,SchoolMember类被称为 基本类 或 超类 。而Teacher和Student类被称为 导出类 或 子类 。
使用继承:
#例 使用继承
#!/usr/bin/python
# Filename: inherit.py
class SchoolMember:
'''Represents any school member.'''
def __init__(self, name, age):
self.name = name
self.age = age
print '(Initialized SchoolMember: %s)' % self.name
def tell(self):
'''Tell my details.'''
print 'Name:"%s" Age:"%s"' % (self.name,self.age),
class Teacher(SchoolMember):
'''Represents a teacher.'''
def __init__(self, name, age, salary):
SchoolMember.__init__(self, name, age)
self.salary = salary
print '(Initialized Teacher: %s)' % self.name
def tell(self):
SchoolMember.tell(self)
print 'Salary: "%d"' % self.salary
class Student(SchoolMember):
'''Represents a student.'''
def __init__(self, name, age, marks):
SchoolMember.__init__(self, name, age)
self.marks = marks
print '(Initialized Student: %s)' % self.name
def tell(self):
SchoolMember.tell(self)
print 'Marks: "%d"' % self.marks
t = Teacher('Mrs. Shrividya', 40, 30000)
s = Student('Swaroop', 22, 75)
print # prints a blank line
members = [t, s]
for member in members:
member.tell() # works for both Teachers and Students
#输出
$ python inherit.py
(Initialized SchoolMember: Mrs. Shrividya)
(Initialized Teacher: Mrs. Shrividya)
(Initialized SchoolMember: Swaroop)
(Initialized Student: Swaroop)
Name:"Mrs. Shrividya" Age:"40" Salary: "30000"
Name:"Swaroop" Age:"22" Marks: "75"
为了使用继承,把基本类的名称作为一个元组跟在定义类时的类名称之后(子类名称后括号内–基类的名称)。然后,注意到基本类
的__init__方法专门使用self变量调用,这样就可以初始化对象的基本类部分。这一点十分重要——Python不会自动调用基本类的constructor,得亲自专门调用它。
还观察到在方法调用之前加上类名称前缀,然后把self变量及其他参数传递给它。
注意,在使用SchoolMember类的tell方法的时候,把Teacher和Student的实例仅仅作为SchoolMember的实例。
另外,在这个例子中,调用了子类型的tell方法,而不是SchoolMember类的tell方法。可以这样来理解,**Python总是首先查找对应类型的方法,在这个例子中就是如此。如果它不能在导出类中找到对应的方法,它才开始到基本类中逐个查找。**基本类是在类定义的时候,在元组之中指明的。
一个术语的注释—— 如果在继承元组中列了一个以上的类,那么它就被称作 多重继承 。
小结:本章,已经研究了类和对象的多个内容以及与它们相关的多个术语。通过本章,可以了解面向对象的编程的优点和缺陷。Python是一个高度面向对象的语言。
输入:使用raw_input语句
输出:使用print语句,也可以使用多种多样的str(字符串)类。例如,能够使用rjust方法来得到一个按一定宽度右对齐的字符串。利用help(str)获得更多详情。
另一个常用的输入/输出类型是处理文件。创建、读和写文件的能力是许多程序所必需的,本章探索如何实现这些功能。
通过创建一个file类的对象来打开一个文件,分别使用file类 的read、readline或write方法来恰当地读写文件。
对文件的读写能力依赖于在打开文件时指定的模式。最后,当完成对文件的操作的时候,调用close方法来告诉Python完成了对文件的使用。
例 使用文件
#!/usr/bin/python
# Filename: using_file.py
poem = '''\
Programming is fun
When the work is done
if you wanna make your work also fun:
use Python!
'''
f = file('poem.txt', 'w') # open for 'w'riting
f.write(poem) # write text to file
f.close() # close the file
f = file('poem.txt')
# if no mode is specified, 'r'ead mode is assumed by default
while True:
line = f.readline()
if len(line) == 0: # Zero length indicates EOF
break
print line,
# Notice comma to avoid automatic newline added by Python
f.close() # close the file
#输出
$ python using_file.py
Programming is fun
When the work is done
if you wanna make your work also fun:
use Python!
首先,通过指明希望打开的文件和模式来创建一个file类的实例。模式可以为读模式(‘r’)、写模式(‘w’)或追加模式(‘a’)。事实上还有多得多的模式可以使用,可以使用**help(file)**来了解它们的详情。
首先用写模式打开文件,然后使用file类的write方法来写文件,最后用close关闭这个文件。
接下来,再一次打开同一个文件来读文件。如果没有指定模式,读模式会作为默认的模式。在一个循环中,使用readline方法读文件的每一行。这个方法返回包括行末换行符的一个完整行。所以,当一个 空的 字符串被返回的时候,即表示文件末已经到达了,于是停止循环。
注意,因为从文件读到的内容已经以换行符结尾,所以在print语句上使用逗号来消除自动换行。
Python提供一个标准的模块,称为pickle。使用它可以在一个文件中储存任何Python对象,之后又可以把它完整无缺地取出来。这被称为 持久地 储存对象。
有另一个模块称为cPickle,它的功能和pickle模块完全相同,只不过它是用C语言编写的,因此要快得多(比pickle快1000倍)。可以使用它们中的任一个,而在这里将使用cPickle模块。记住,把这两个模块都简称为pickle模块。
例 储存与取储存
#!/usr/bin/python
# Filename: pickling.py
import cPickle as p
#import pickle as p
shoplistfile = 'shoplist.data'
# the name of the file where we will store the object
shoplist = ['apple', 'mango', 'carrot']
# Write to the file
f = file(shoplistfile, 'w')
p.dump(shoplist, f) # dump the object to a file
f.close()
del shoplist # remove the shoplist
# Read back from the storage
f = file(shoplistfile)
storedlist = p.load(f)
print storedlist
#输出
$ python pickling.py
['apple', 'mango', 'carrot']
首先,使用import…as语法。这是一种便利方法,以便于可以使用更短的模块名称。在这个例子中,它还让能够通过简单地改变一行就切换到另一个模块(cPickle或者pickle)!在程序的其余部分的时候,简单地把这个模块称为p。
为了在文件里储存一个对象,首先以写模式打开一个file对象,然后调用储存器模块的dump函数,把对象储存到打开的文件中。这个过程称为 储存 。接下来,使用pickle模块的load函数的返回来取回对象。这个过程称为 取储存 。
本章学习了多种类型的输入/输出,及文件处理和使用储存器模块。
程序中出现某些 异常的 状况的时候,异常就发生了。例如,当想要读某个文件的时候,而那个文件不存在。或者在程序运行的时候,不小心把它删除了。上述这些情况可以使用异常来处理。
一个简单的print语句。假如把print误拼为Print,注意大写,这样Python会 引发 一个语法错误。
>>> Print 'Hello World'
File "" , line 1
Print 'Hello World'
^
SyntaxError: invalid syntax
>>> print 'Hello World'
Hello World
可以观察到有一个SyntaxError被引发,并且检测到的错误位置也被打印了出来。这是这个错误的错误处理器 所做的工作。
读取用户的一段输入。按Ctrl-d,看一下会发生什么。
>>> s = raw_input('Enter something --> ')
Enter something --> Traceback (most recent call last):
File "" , line 1, in ?
EOFError
Python引发了一个称为EOFError的错误,这个错误基本上意味着它发现一个不期望的 文件尾 (由Ctrl -d表示)
接下来,将学习如何处理这样的错误。
处理异常:
可以使用try…except语句来处理异常。把通常的语句放在try-块中,而把错误处理语句放在except-块中。
例 处理异常
#!/usr/bin/python
# Filename: try_except.py
import sys
try:
s = raw_input('Enter something --> ')
except EOFError:
print '\nWhy did you do an EOF on me?'
sys.exit() # exit the program
except:
print '\nSome error/exception occurred.'
# here, we are not exiting the program
print 'Done'
#输出
$ python try_except.py
Enter something -->
Why did you do an EOF on me?
$ python try_except.py
Enter something --> Python is exceptional!
Done
把所有可能引发错误的语句放在try块中,然后在except从句/块中处理所有的错误和异常。 except从句可以专门处理单一的错误或异常,或者一组包括在圆括号内的错误/异常。如果没有给出错误或异常的名称,它会处理 所有的 错误和异常。对于每个try从句,至少都有一个相关联的except从句。
如果某个错误或异常没有被处理,默认的Python处理器就会被调用。它会终止程序的运行,并且打印一个消息,已经看到了这样的处理。
还可以让try…catch块关联上一个else从句。当没有异常发生的时候,else从句将被执行。
可以使用raise语句 引发 异常。还得指明错误/异常的名称和伴随异常 触发的 异常对象。可以引发的错误或异常应该分别是一个Error或Exception类的直接或间接导出类。
例 如何引发异常
#!/usr/bin/python
# Filename: raising.py
class ShortInputException(Exception):
'''A user-defined exception class.'''
def __init__(self, length, atleast):
Exception.__init__(self)
self.length = length
self.atleast = atleast
try:
s = raw_input('Enter something --> ')
if len(s) < 3:
raise ShortInputException(len(s), 3)
# Other work can continue as usual here
except EOFError:
print '\nWhy did you do an EOF on me?'
except ShortInputException, x:
print 'ShortInputException: The input was of length %d, \
was expecting at least %d' % (x.length,x.atleast)
else:
print 'No exception was raised.'
输出
$ python raising.py
Enter something -->
Why did you do an EOF on me?
$ python raising.py
Enter something --> ab
ShortInputException: The input was of length 2, was expecting at least 3
$ python raising.py
Enter something --> abc
No exception was raised.
**创建自己的异常类型,其实可以使用任何预定义的异常/错误。**这个新的异常类型是ShortInputException类。它有两个域——length是给定输入的长度,atleast则是程序期望的最小长度。
在except从句中,提供了错误类和用来表示错误/异常对象的变量。这与函数调用中的形参和实参概念类似。在这个特别的except从句中,使用异常对象的length和atleast域来为用户打印一个恰当的消息。
假如在读一个文件的时候,希望在无论异常发生与否的情况下都关闭文件,该怎么做呢?这可以使用finally块来完成。
注意,在一个try块下,可以同时使用except从句和finally块。如果要同时使用它们的话,需要把一个嵌入另外一个。
例 使用finally
#!/usr/bin/python
# Filename: finally.py
import time
try:
f = file('poem.txt')
while True: # our usual file-reading idiom
line = f.readline()
if len(line) == 0:
break
time.sleep(2)
print line,
finally:
f.close()
print 'Cleaning up...closed the file'
输出
$ python finally.py
Programming is fun
When the work is done
Cleaning up...closed the file
Traceback (most recent call last):
File "finally.py", line 12, in ?
time.sleep(2)
KeyboardInterrupt
进行通常的读文件工作,但是有意在每打印一行之前用time.sleep方法暂停2秒钟。这样做的原因是让程序运行得慢一些(Python由于其本质通常运行得很快)。在程序运行的时候,按Ctrl-c中断/取消程序。可以观察到KeyboardInterrupt异常被触发,程序退出。但是在程序退出之前,finally从句仍然被执行,把文件关闭。
本章学习了try…except和try…finally语句的用法。还学习了如何创建自己的异常类型和如何引发异常。
Python标准库是随Python附带安装的,它包含大量极其有用的模块。熟悉Python标准库是十分重要的,因为如果熟悉这些库中的模块,那么大多数问题都可以简单快捷地使用它们来解决。
可以在Python附带安装的文档的“库参考”一节中了解Python标准库中所有模块的完整内容。
sys模块包含系统对应的功能。
sys.argv列表,它包含命令行参数。
#例 使用sys.argv
#!/usr/bin/python
# Filename: cat.py
import sys
def readfile(filename):
'''Print a file to the standard output.'''
f = file(filename)
while True:
line = f.readline()
if len(line) == 0:
break
print line, # notice comma
f.close()
# Script starts from here
if len(sys.argv) < 2:
print 'No action specified.'
sys.exit()
if sys.argv[1].startswith('--'):
option = sys.argv[1][2:]
# fetch sys.argv[1] but without the first two characters
if option == 'version':
print 'Version 1.2'
elif option == 'help':
print '''\
This program prints files to the standard output.
Any number of files can be specified.
Options include:
--version : Prints the version number
--help : Display this help'''
else:
print 'Unknown option.'
sys.exit()
else:
for filename in sys.argv[1:]:
readfile(filename)
输出
$ python cat.py
No action specified.
$ python cat.py --help
This program prints files to the standard output.
Any number of files can be specified.
Options include:
--version : Prints the version number
--help : Display this help
$ python cat.py --version
Version 1.2
$ python cat.py --nonsense
Unknown option.
$ python cat.py poem.txt
Programming is fun
When the work is done
if you wanna make your work also fun:
use Python!
这个程序用来模范Linux/Unix用户熟悉的cat命令。只需要指明某些文本文件的名字,这个程序会把它们打印输出。
在Python程序运行的时候,即不是在交互模式下,在sys.argv列表中总是至少有一个项目。它就是当前运行的程序名称,作为sys.argv[0](由于Python从0开始计数)。其他的命令行参数在这个项目之后。
为了使这个程序对用户更加友好,提供了一些用户可以指定的选项来了解更多程序的内容。使用第一个参数来检验程序是否被指定了选项。如果使用了–version选项,程序的版本号将被打印出来。类似地,如果指定了–help选项,提供一些关于程序的解释。使用sys.exit函数退出
正在运行的程序。和以往一样,可以看一下help(sys.exit)来了解更多详情。如果没有指定任何选项,而是为程序提供文件名的话,它就简单地打印出每个文件地每一行,按照命令行中的顺序一个文件接着一个文件地打印。
顺便说一下,名称cat是 concatenate 的缩写,它基本上表明了程序的功能——它可以在输出打印一个文件或者把两个或两个以上文件连接/级连在一起打印。
更多sys的内容:
sys.version字符串提供安装的Python的版本信息。sys.version_info元组则提供一个更简单的方法来使程序具备Python版本要求功能。
[swaroop@localhost code]$ python
>>> import sys
>>> sys.version
'2.3.4 (#1, Oct 26 2004, 16:42:40) \n[GCC 3.4.2 20041017 (Red Hat 3.4.2-6.fc3)]'
>>> sys.version_info
(2, 3, 4, 'final', 0)
sys.stdin、sys.stdout和sys.stderr它们分别对应你的程序的标准输入、标准输出和标准错误流。
模块包含普遍的操作系统功能。如果希望程序能够与平台无关的话,这个模块是尤为重要的。
即它允许一个程序在编写后不需要任何改动,也不会发生任何问题,就可以在Linux和Windows下运行。一个例子就是使用os.sep可以取代操作系统特定的路径分割符。
在os模块中:
>>> os.path.split('/home/swaroop/byte/code/poem.txt')
('/home/swaroop/byte/code', 'poem.txt')
可以利用Python标准文档去探索更多有关这些函数和变量的详细知识。也可以使用help(sys)等等。
本章学习Python标准库中的sys模块和os模块的一部分功能。利用Python标准文档去学习这两个模块以及其他模块的更多内容。
在类中有一些特殊的方法具有特殊的意义,比如__init__和__del__方法。
一般说来,特殊的方法都被用来模仿某个行为。例如,如果想要为你的类使用x[key]这样的索引操作(就像列表和元组一样),那么只需要实现__getitem__()方法就可以了。想一下,Python就是对list类这样做的!
表15.1 一些特殊的方法(如果想要知道所有的特殊方法,可以在《Python参考手册》中找到一个庞大的列表。)
名称 说明
init(self,…) 这个方法在新建对象恰好要被返回使用之前被调用。
del(self) 恰好在对象要被删除之前调用。
str(self) 在我们对对象使用print语句或是使用str()的时候调用。
lt(self,other) 当使用 小于 运算符(<)的时候调用。类似地,对于所有的运算符(+,>等等)都有特殊的方法。
getitem(self,key) 使用x[key]索引操作符的时候调用。
len(self) 对序列对象使用内建的len()函数的时候调用。
每一个语句块是通过它的缩进层次与其它块区分开来的。然而这在大多数情况下是正确的,但是并非100%的准确。如果语句块只包含一句语句,那么可以在条件语句或循环语句的同一行指明它。
>>> flag = True
>>> if flag: print 'Yes'
...
Yes
单个语句被直接使用而不是作为一个独立的块使用。虽然这样做可以使程序变得 小一些 ,但是除了检验错误之外强烈建议不要使用这种缩略方法。不使用它的一个主要的理由是一旦使用了恰当的缩进,就可以很方便地添加一个额外的语句。
另外,注意在使用交互模式的Python解释器的时候,它会通过恰当地改变提示符来帮助输入语句。在上面这个例子中,当输入了关键字if之后,Python解释器把提示符改变为…以表示语句还没有结束。在这种情况下,按回车键用来确认语句已经完整了。然后,Python完成整个语句的执行,并且返回原来的提示符并且等待下一句输入。
**通过列表综合,可以从一个已有的列表导出一个新的列表。**例如,有一个数的列表,而想要得到一个对应的列表,使其中所有大于2的数都是原来的2倍。对于这种应用,列表综合是最理想的方法。
#例 使用列表综合
#!/usr/bin/python
# Filename: list_comprehension.py
listone = [2, 3, 4]
listtwo = [2*i for i in listone if i > 2]
print listtwo
#输出
$ python list_comprehension.py
[6, 8]
为满足条件(if i > 2)的数指定了一个操作(2*i),从而导出一个新的列表。注意原来的列表并没有发生变化。在很多时候,都是使用循环来处理列表中的每一个元素,而使用列表综合可以用一种更加精确、简洁、清楚的方法完成相同的工作。
当要使函数接收元组或字典形式的参数的时候,有一种特殊的方法,它分别使用*和前缀。这种方法在函数需要获取可变数量的参数的时候特别有用。
>>> def powersum(power, *args):
... '''Return the sum of each argument raised to
specified power.'''
... total = 0
... for i in args:
... total += pow(i, power)
... return total
...
>>> powersum(2, 3, 4)
25
>>> powersum(2, 10)
100
由于在args变量前有*前缀,所有多余的函数参数都会作为一个元组存储在args中。如果使用的是** 前缀,多余的参数则会被认为是一个字典的键/值对。
lambda语句被用来创建新的函数对象,并且在运行时返回它们。
#例 使用lambda形式
#!/usr/bin/python
# Filename: lambda.py
def make_repeater(n):
return lambda s: s*n
twice = make_repeater(2)
print twice('word')
print twice(5)
#输出
$ python lambda.py
wordword
10
使用了make_repeater函数在运行时创建新的函数对象,并且返回它。**lambda语句用来创建函数对象。**本质上,lambda需要一个参数,后面仅跟单个表达式作为函数体,而表达式的值被这个新建的函数返回。注意,即便是print语句也不能用在lambda形式中,只能使用表达式。
exec语句用来执行储存在字符串或文件中的Python语句。
例如,可以在运行时生成一个包含Python代码的字符串,然后使用exec语句执行这些语句。下面是一个简单的例子。
>>> exec 'print "Hello World"'
Hello World
eval语句用来计算存储在字符串中的有效Python表达式。
>>> eval('2*3')
6
assert语句用来声明某个条件是真的。
例如,如果非常确信某个你使用的列表中至少有一个元素,而想要检验这一点,并且在它非真的时候引发一个错误,那么assert语句是应用在这种情形下的理想语句。当assert语句失败的时候,会引发一个AssertionError。
>>> mylist = ['item']
>>> assert len(mylist) >= 1
>>> mylist.pop()
'item'
>>> assert len(mylist) >= 1
Traceback (most recent call last):
File "" , line 1, in ?
AssertionError
repr函数用来取得对象的规范字符串表示。反引号(也称转换符)可以完成相同的功能。 注意,在大多数时候有eval(repr(object)) == object。
>>> i = []
>>> i.append('item')
>>> `i`
"['item']"
>>> repr(i)
"['item']"
基本上,repr函数和反引号用来获取对象的可打印的表示形式。可以通过定义类的__repr__方法来控制对象在被repr函数调用的时候返回的内容。
使用Python的GUI库——需要使用这些库来用Python语言创建自己的图形程序。使用GUI库和它们的Python绑定,可以创建自己的IrfanView、Kuickshow软件或者任何别的类似的东西。绑定能够使用Python语言编写程序,而使用的库本身是用C、C++或者别的语言编写的。
有许多可供选择的使用Python的GUI:
Qt工具包的Python绑定。Qt工具包是构建KDE的基石。Qt,特别是配合Qt Designer和出色的Qt文档之后,它极其易用并且功能非常强大。可以在Linux下免费使用它,但是如果在Windows下使用它需要付费。使用PyQt,可以在Linux/Unix上开发免费的(GPL约定的)软件,而开发具产权的软件则需要付费。
PyQt资源:
《使用Python语言的GUI编程:Qt版》 http://www.opendocs.org/pyqt/
官方主页:https://riverbankcomputing.com/pyqt/index.php
GTK+工具包的Python绑定。GTK+工具包是构建GNOME的基石。GTK+在使用上有很多怪癖的地方,不过一旦习惯了,可以非常快速地开发GUI应用程序。Glade图形界面设计器是必不可少的,而文档还有待改善。GTK+在Linux上工作得很好,而它的Windows接口还不完整。可以使用GTK+开发免费和具有产权的软件。
官方主页:http://www.pygtk.org/
wxWidgets工具包的Python绑定。wxPython有与它相关的学习方法。它的可移植性极佳,可以在Linux、Windows、Mac甚至嵌入式平台上运行。有很多wxPython的IDE,其中包括GUI设计器以及如SPE(Santi’s Python Editor)和wxGlade那样的GUI开发器:
SPE(Santi’s Python Editor):http://spe.pycs.net/
wxGlade:https://wxglade.sourceforge.net/
可以使用wxPython开发免费和具有产权的软件,请查阅官方主页:https://www.wxpython.org/
现存最老的GUI工具包之一。如果使用过IDLE,它就是一个TkInter程序。在PythonWare.org(http://www.pythonware.com/library/tkinter/introduction/index.htm)上的TkInter文档是十分透彻的。TkInter具备可移植性,可以在Linux/Unix和Windows下工作。重要的是,TkInter是标准Python发行版的一部分。
其他:
获取更多选择,请参阅Python.org上的GUI编程wiki页http://www.python.org/cgi-bin/moinmoin/GuiProgramming
并没有单一的标准Python GUI工具。建议你根据情况在上述工具中选择一个。首要考虑的因素是否愿意为GUI工具付费。其次考虑的是想让程序运行在Linux下、Windows下还是两者都要。第三个考虑因素根据Linux下的KDE用户还是GNOME用户而定。
http://docs.python.org/
一个丰富的库,在大多数时候,可以在这个库中找到你所需的东西。这被称为Python的“功能齐全”理念。强烈建议在开始开发大型Python程序之前浏览一下Python标准文档。
https://www.python.org/
——Python编程语言的官方主页。可以在上面找到Python语言和解释器的最新版本。另外还有各种邮件列表活跃地讨论Python的各方面内容。
讨论Python语言的世界性新闻组。可以把疑惑和询问贴在这个新闻组上。可以使用Google群(http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&group=comp.lang.python)在线访问这个新闻组,或加入作为新闻组镜像的邮件列表(https://mail.python.org/mailman/listinfo/python-list)。
http://aspn.activestate.com/ASPN/Python/Cookbook/
一个极有价值的秘诀和技巧集合,它帮助解决某些使用Python的问题。这是每个Python用户必读的一本书。
http://gnosis.cx/publish/tech_index_cp.html
David Mertz编著的一系列优秀的Python相关文章。
http://www.diveintopython.org/
给有经验的Python程序员的一本很优秀的书。如果已经完整地阅读了本书,那么强烈建议接下来阅读《深入理解Python》。它覆盖了包括XML处理、单元测试和功能性编程在内的广泛的主题。
http://www.jython.org/
用Java语言实现的Python解释器。这意味着可以用Python语言编写程序而同时使用Java库!Jython是一个稳定成熟的软件。如果也是一个Java程序员,强烈建议尝试一下Jython。
https://www.hugedomains.com/domain_profile.cfm?d=caddr.com
用C#语言实现的Python解释器,可以运行在.NET、Mono和DotGNU平台上。这意味着可以用Python语言编写程序而使用.NET库以及其他由这三种平台提供的库!IronPython还只是一个前期alpha测试软件,现在还只适合用来进行试验。Jim Hugunin,IronPython的开发者,已经
加入了微软公司,将在将来全力开发一个完整版本的IronPython。Lython是Python语言的Lisp前段。它类似于普通的Lisp语言,会被直接编译为Python字节码,这意味着它能与我们普通的Python代码协同工作。
另外还有很多很多的Python资源。其中比较有趣的有Daily Python-URL!,它使保持与Python的最新进展同步。另外还有Vaults of Parnassus、ONLamp.com PythonDevCenter、dirtSimple.org、Python Notes等等。
Daily Python-URL! :http://www.pythonware.com/daily/
Vaults of Parnassus:http://www.vex.net/parnassus/
ONLamp.com Python DevCenter:https://www.oreilly.com/radar/
dirtSimple.org:https://dirtsimple.org/
Python Notes:http://pythonnotes.blogspot.com/
等等。