决心在一个这个寒假更加深入学习推荐系统之后,本来打算看数据挖掘导论或者是数据挖掘:概念与技术。不过在询问过一位学长之后,他推荐我看一看更加基础的书:集体智慧编程。该书所有的代码都是由python完成,在阅读了前4章之后,深刻觉得需要系统学习一下python。而且当时学长也说了,要学机器学习,python是必学的,而且python也不难。所以更加坚定了学习python的决心。故搜索到这本python最基础的书:简明python教程,作者:Swaroop C. H。译者:沈洁元。说完缘由之后让我正式进入简明python教程的学习吧。
简介中,说python是一个脚本语言。
我认为最关键的有两点可以帮助我们理解什么是脚本语言。
python的特色有点多,但是我认为其中重要的有:
解释性
这一点需要一些解释。
一个用编译性语言比如C或C++写的程序可以从源文件(即C或C++语言)转换到一个你的计算机使用的语言(二进制代码,即0和1)。这个过程通过编译器和不同的标记、选项完成。当你运行你的程序的时候,连接/转载器软件把你的程序从硬盘复制到内存中并且运行。
而Python语言写的程序不需要编译成二进制代码。你可以直接从源代码 运行 程序。在计算机内部,Python解释器把源代码转换成称为字节码的中间形式,然后再把它翻译成计算机使用的机器语言并运行。事实上,由于你不再需要担心如何编译程序,如何确保连接转载正确的库等等,所有这一切使得使用Python更加简单。由于你只需要把你的Python程序拷贝到另外一台计算机上,它就可以工作了,这也使得你的Python程序更加易于移植。
上文拷贝自原书,显然C/C++的
运作模式我们还是知道的,但是python的的方式我还是第一次接触,简单说了,python的脚本语言被解释器处理成了字节码,字节码被处理成了机器语言,并运行。
可扩展性
如果你需要你的一段关键代码运行得更快或者希望某些算法不公开,你可以把你的部分程序用C或C++编写,然后在你的Python程序中使用它们。
很显然这表明python可以调用C/C++的代码。
作者表明linux下都默认装了python
首先进入python模式,可以再命令行或者shell打印python,也可以直接使用idle。
>>> print 'hello world'
hello world
>>>
非常重要了
在Python中有4种类型的数——整数、长整数、浮点数和复数。
使用单引号(')
你可以用单引号指示字符串,就如同'Quote me on this'这样。所有的空白,即空格和制表符都照原样保留。
使用双引号(")
在双引号中的字符串与单引号中的字符串的使用完全相同,例如"What's your name?"。
使用三引号('''或""")
利用三引号,你可以指示一个多行的字符串。你可以在三引号中自由的使用单引号和双引号。例如:
'''This is a multi-line string. This is the first line.
This is the second line.
"What's your name?," I asked.
He said "Bond, James Bond."
'''
转义符
这个和平常的使用差不多
要表示:What's your name?。
可以使用:'What\'s your name?'
你可以用转义符\\来指示反斜杠本身
最大的不同在于:
在一个字符串中,行末的单独一个反斜杠表示字符串在下一行继续,而不是开始一个新的行。例如:
"This is the first sentence.\
This is the second sentence."
等价于"This is the first sentence. This is the second sentence."
自然字符串
如果你想要指示某些不需要如转义符那样的特别处理的字符串,那么你需要指定一个自然字符串。自然字符串通过给字符串加上前缀r或R来指定。例如r"Newlines are indicated by \n"。
加r和不加r的区别在于,加了r之后,就\n被认为是一个字符,而不是换行符
Unicode字符串
Unicode是书写国际文本的标准方法。如果你想要用你的母语如北印度语或阿拉伯语写文本,那么你需要有一个支持Unicode的编辑器。类似地,Python允许你处理Unicode文本——你只需要在字符串前加上前缀u或U。例如,u"This is a Unicode string."。
记住,在你处理文本文件的时候使用Unicode字符串,特别是当你知道这个文件含有用非英语的语言写的文本。
最后一句再读一遍哈
字符串是不可变的
给C/C++程序员的注释
使用变量时只需要给它们赋一个值。不需要声明或定义数据类型。
比如:
i = 5
print i
i = i + 1
print i
你没使用int指明数据类型吧
虽然python里面有分号,但是一般不用。因为不用的时候看起来更方便。
>>> i = 5 print i
SyntaxError: invalid syntax
>>> i = 5 ; print i
5
>>>
分号可以用来表示逻辑行的结束,当时当我们使用
i=5
print 5
这样的形式的时候将不需要考虑这个问题。
事实上行首的空白是重要的。它称为缩进。
居然在这个地方把操作数看懂了
表5.1 运算符与它们的用法
运算符 | 名称 | 说明 | 例子 |
---|---|---|---|
+ | 加 | 两个对象相加 | 3 + 5得到8。'a' + 'b'得到'ab'。 |
- | 减 | 得到负数或是一个数减去另一个数 | -5.2得到一个负数。50 - 24得到26。 |
* | 乘 | 两个数相乘或是返回一个被重复若干次的字符串 | 2 * 3得到6。'la' * 3得到'lalala'。 |
** | 幂 | 返回x的y次幂 |
3 ** 4得到81(即3 * 3 * 3 * 3) |
/ | 除 | x除以y | 4/3得到1(整数的除法得到整数结果)。4.0/3或4/3.0得到1.3333333333333333 |
// | 取整除 | 返回商的整数部分 | 4 // 3.0得到1.0 |
% | 取模 | 返回除法的余数 | 8%3得到2。-25.5%2.25得到1.5 |
<< | 左移 | 把一个数的比特向左移一定数目(每个数在内存中都表示为比特或二进制数字,即0和1) | 2 << 2得到8。——2按比特表示为10 |
>> | 右移 | 把一个数的比特向右移一定数目 | 11 >> 1得到5。——11按比特表示为1011,向右移动1比特后得到101,即十进制的5。 |
& | 按位与 | 数的按位与 | 5 & 3得到1。 |
| | 按位或 | 数的按位或 | 5 | 3得到7。 |
^ | 按位异或 | 数的按位异或 | 5 ^ 3得到6 |
~ | 按位翻转 | x的按位翻转是-(x+1) | ~5得到6。 |
< | 小于 | 返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。注意,这些变量名的大写。 | 5 < 3返回0(即False)而3 < 5返回1(即True)。比较可以被任意连接:3 < 5 < 7返回True。 |
> | 大于 | 返回x是否大于y | 5 > 3返回True。如果两个操作数都是数字,它们首先被转换为一个共同的类型。否则,它总是返回False。 |
<= | 小于等于 | 返回x是否小于等于y | x = 3; y = 6; x <= y返回True。 |
>= | 大于等于 | 返回x是否大于等于y | x = 4; y = 3; x >= y返回True。 |
== | 等于 | 比较对象是否相等 | x = 2; y = 2; x == y返回True。x = 'str'; y = 'stR'; x == y返回False。x = 'str'; y = 'str'; x == y返回True。 |
!= | 不等于 | 比较两个对象是否不相等 | x = 2; y = 3; x != y返回True。 |
not | 布尔“非” | 如果x为True,返回False。如果x为False,它返回True。 | x = True; not y返回False。 |
and | 布尔“与” | 如果x为False,x and y返回False,否则它返回y的计算值。 | x = False; y = True; x and y,由于x是False,返回False。在这里,Python不会计算y,因为它知道这个表达式的值肯定是False(因为x是False)。这个现象称为短路计算。 |
or | 布尔“或” | 如果x是True,它返回True,否则它返回y的计算值。 | x = True; y = False; x or y返回True。短路计算在这里也适用。 |
老生常谈的问题,直接看表吧,由上到下,由低到高。
运算符 | 描述 |
---|---|
lambda | Lambda表达式 |
or | 布尔“或” |
and | 布尔“与” |
not x | 布尔“非” |
in,not in | 成员测试 |
is,is not | 同一性测试 |
<,<=,>,>=,!=,== | 比较 |
| | 按位或 |
^ | 按位异或 |
& | 按位与 |
<<,>> | 移位 |
+,- | 加法与减法 |
*,/,% | 乘法、除法与取余 |
+x,-x | 正负号 |
~x | 按位翻转 |
** | 指数 |
x.attribute | 属性参考 |
x[index] | 下标 |
x[index:index] | 寻址段 |
f(arguments...) | 函数调用 |
(experession,...) | 绑定或元组显示 |
[expression,...] | 列表显示 |
{key:datum,...} | 字典显示 |
'expression,...' | 字符串转换 |
结合规律
运算符通常由左向右结合,即具有相同优先级的运算符按照从左向右的顺序计算。例如,2 + 3 + 4被计算成(2 + 3) + 4。
一些如赋值运算符那样的运算符是由右向左结合的,即a = b = c被处理为a = (b = c)。
在我来看,唯一新鲜的就是有一个elif的关键字,它是if和else的结合。
给C/C++程序员的注释
在Python中没有switch语句。你可以使用if..elif..else语句来完成同样的工作(在某些场合,使用字典会更加快捷。)
重点是多了一个else句:
while flag:
else:
print 'The while loop is over.'
当while循环条件变为False的时候,else块才被执行——这甚至也可能是在条件第一次被检验的时候。如果while循环有一个else从句,它将始终被执行,除非你的while循环将永远循环下去不会结束!
这个不同之处多一些,请看例子:
for i in range(1, 5):
print i
else:
print 'The for loop is over'
输出:
>>>
1
2
3
4
over!
>>>
其中:for..in是另外一个循环语句,它在一序列的对象上 递归 即逐一使用队列中的每个项目
在C/C++中,如果你想要写for (int i = 0; i < 5; i++),那么用Python,你写成for i in range(0,5)。
break语句是用来 终止 循环语句的,即哪怕循环条件没有称为False或序列还没有被完全递归,也停止执行循环语句。
最后一句重点哈。回答:执行是不执行?
重点是如何将局部变量改为全局变量。
def func(x):
print 'x is', x
x = 2
print 'Changed local x to', x
x = 50
func(x)
print 'x is still', x
输出:
x is 50
Changed local x to 2
x is still 50
def func(): global x print 'x is', x x = 2 print 'Changed local x to', xx = 50func()print 'Value of x is', x
输出:x is 50
Changed global x to 2
Value of x is 2
代码:
def say(message, times = 1):
print message * times
say('Hello')
say('World', 5)
Hello
WorldWorldWorldWorldWorld
很有趣的是,这里学习到了print的一个用法,原来还可以这么玩。
注意:只有在形参表末尾的那些参数可以有默认参数值。例如,def func(a, b=5)是有效的,但是def func(a=5, b)是 无效 的。
对函数参数的赋值,不一定依据位置,还可以依据其形参的变量名。
def func(a, b=5, c=10):
print 'a is', a, 'and b is', b, 'and c is', c
func(3, 7)
func(25, c=24)
func(c=50, a=100)
输出:
a is 3 and b is 7 and c is 10
a is 25 and b is 5 and c is 24
a is 100 and b is 5 and c is 50
在第三次使用func(c=50, a=100)的时候,我们使用关键参数来完全指定参数值。注意,尽管函数定义中,a在c之前定义,我们仍然可以在a之前指定参数c的值。
注意,没有返回值的return语句等价于return None。None是Python中表示没有任何东西的特殊类型。例如,如果一个变量的值为None,可以表示它没有值。
def somefuntion():
pass
print somefuntion()
输出:
>>>
None
>>>
这其实是告诉我们一种方式:给函数写说明的方式。
def printMax(x, y):
'''Prints the maximum of two numbers.
The two values must be integers.'''
x = int(x) # convert to integers, if possible
y = int(y)
if x > y:
print x, 'is maximum'
else:
print y, 'is maximum'
printMax(3, 5)
print printMax.__doc__
其中__是双下划线。两下哈
5 is maximum
Prints the maximum of two numbers.
The two values must be integers.
你也可以调用help(printMax)来查看这个函数的说明,如下所示:
>>> help(printMax)
Help on function printMax in module __main__:
printMax(x, y)
Prints the maximum of two numbers.
The two values must be integers.
需要注意要写这个东西的话:
在函数的第一个逻辑行写这个说明,文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始是详细的描述。 强烈建议 你在你的函数中使用文档字符串时遵循这个惯例。
模块基本上就是一个包含了所有你定义的函数和变量的文件。为了在其他程序中重用模块,模块的文件名必须以.py为扩展名。
import sys
print 'The command line arguments are:'
for i in sys.argv:
print i
print '\n\nThe PYTHONPATH is', sys.path, '\n'
输出:
$ python using_sys.py we are arguments
The command line arguments are:
using_sys.py
we
are
arguments
The PYTHONPATH is ['/home/swaroop/byte/code', '/usr/lib/python23.zip',
'/usr/lib/python2.3', '/usr/lib/python2.3/plat-linux2',
'/usr/lib/python2.3/lib-tk', '/usr/lib/python2.3/lib-dynload',
'/usr/lib/python2.3/site-packages', '/usr/lib/python2.3/site-packages/gtk-2.0']
我对这段代码唯一觉得奇怪的地方就是为什么sys.argv就是我输入的argv呢?难道就是因为我import了sys,所以把我输入的文件名和参数一起给了sys.argv,只能这样解释了
输入一个模块相对来说是一个比较费时的事情,所以Python做了一些技巧,以便使输入模块更加快一些。一种方法是创建 字节编译的文件 ,这些文件以.pyc作为扩展名。字节编译的文件与Python变换程序的中间状态有关。当你在下次从别的程序输入这个模块的时候,.pyc文件是十分有用的——它会快得多,因为一部分输入模块所需的处理已经完成了。另外,这些字节编译的文件也是与平台无关的。所以,现在你知道了那些.pyc文件事实上是什么了。
如果你想要直接输入argv变量到你的程序中(避免在每次使用它时打sys.),那么你可以使用from sys import argv语句。如果你想要输入所有sys模块使用的名字,那么你可以使用from sys import *语句。这对于所有模块都适用。一般说来,应该避免使用from..import而使用import语句,因为这样可以使你的程序更加易读,也可以避免名称的冲突。
那这个知识点不讲也罢,注意最后一句话,不建议用from语句。
关键是import一个模块会导致这个模块的代码被运行,这个模块是自身运行还是被别的模块import后运行的呢?我们可以通过if __name__ == '__main__'这样一个语句来判断,并且做相应的操作。代码:
# Filename: using_name.py
if __name__ == '__main__':
print 'This program is being run by itself'
else:
print 'I am being imported from another module'
输出:
$ python using_name.py
This program is being run by itself
$ python
>>> import using_name
I am being imported from another module
>>>
这个其实本身没有多大的意义。
因为只是把函数和变量封装的另一个py文件里,如果要用到别的py文件,请使用import关键字,当然你也可以使用from ... import ... 只引进你需要的方法和变量。
经过测试发现只用import关键字的话,那么文件必须放在相同目录下。
>>> import testA
>>> dir(testA)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'sayhi', 'version']
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'testA']
>>> a = 5
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'a', 'testA']
>>> del a
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'testA']
>>>
你可以使用内建的dir函数来列出模块定义的标识符。标识符有函数、类和变量。
当你为dir()提供一个模块名的时候它返回模块定义的名称列表。如果不提供参数,它返回当前模块中定义的名称列表。
如上就是做了就些测试,比如我们可以添加了a之后,看看dir(),也可以将del删除掉。
我们还可以观察在那份testA中,sayhi是一个函数,但是version是一个名字,但是我们无法使用dir()函数看出它到底是一个变量还是一个函数。
数据结构基本上就是——它们是可以处理一些 数据 的 结构 。或者说,它们是用来存储一组相关数据的。
在Python中有三种内建的数据结构——列表、元组和字典
那么多废话还不如看了一个例子
注意list是一个[]括号。
代码:
shoplist = ['apple', 'mango', 'carrot', 'banana']
print 'I have', len(shoplist),'items to purchase.'
print 'These items are:', # Notice the comma at end of the line
for item in shoplist:
print item,
print '\nI also have to buy rice.'
shoplist.append('rice')
print 'My shopping list is now', shoplist
print 'I will sort my list now'
shoplist.sort()
print 'Sorted shopping list is', shoplist
print 'The first item I will buy is', shoplist[0]
olditem = shoplist[0]
del shoplist[0]
print 'I bought the', olditem
print 'My shopping list is now', shoplist
输出:
I have 4 items to purchase.
These items are: apple mango carrot banana
I also have to buy rice.
My shopping list is now ['apple', 'mango', 'carrot', 'banana', 'rice']
I will sort my list now
Sorted shopping list is ['apple', 'banana', 'carrot', 'mango', 'rice']
The first item I will buy is apple
I bought the apple
My shopping list is now ['banana', 'carrot', 'mango', 'rice'] ‘
其中顺便讲了一下
shoplist 作为一个list的类的对象,那么他才可以调用append、sort、方法。
这个玩意很有意思,倒不是其含义有意思,倒是其在例子中是一个用法很有意思。就是在元组中再加一个元组就会形成二维数组的感觉。
代码:
zoo = ('wolf', 'elephant', 'penguin')
print 'Number of animals in the zoo is', len(zoo)
new_zoo = ('monkey', 'dolphin', zoo)
print 'Number of animals in the new zoo is', len(new_zoo)
print 'All animals in new zoo are', new_zoo
print 'Animals brought from old zoo are', new_zoo[2]
print 'Last animal brought from old zoo is', new_zoo[2][2]
输出:
Number of animals in the zoo is 3
Number of animals in the new zoo is 3
All animals in new zoo are ('monkey', 'dolphin', ('wolf', 'elephant', 'penguin'))
Animals brought from old zoo are ('wolf', 'elephant', 'penguin')
Last animal brought from old zoo is penguin
打印时也使用了元组,不过我对这个并不陌生。
代码:
age = 22
name = 'Swaroop'
print '%s is %d years old' % (name, age)
print 'Why is %s playing with that python?' % name
输出:
Swaroop is 22 years old
Why is Swaroop playing with that python?
看一个例子吧,例子中还有一些常用的函数。
代码:
ab = { 'Swaroop' : '[email protected]',
'Larry' : '[email protected]',
'Matsumoto' : '[email protected]',
'Spammer' : '[email protected]'
}
print "Swaroop's address is %s" % ab['Swaroop']
# Adding a key/value pair
ab['Guido'] = '[email protected]'
# Deleting a key/value pair
del ab['Spammer']
print '\nThere are %d contacts in the address-book\n' % len(ab)
for name, address in ab.items():
print 'Contact %s at %s' % (name, address)
if 'Guido' in ab: # OR ab.has_key('Guido')
print "\nGuido's address is %s" % ab['Guido']
输出:
Swaroop's address is [email protected]
There are 4 contacts in the address-book
Contact Swaroop at [email protected]
Contact Matsumoto at [email protected]
Contact Larry at [email protected]
Contact Guido at [email protected]
Guido's address is [email protected]
真是不看不知道,一看没什么大不了
看例子吧,肯定能懂,但是要看仔细哦,很容易被阴到的
代码:
shoplist = ['apple', 'mango', 'carrot', 'banana']
# Indexing or 'Subscription' operation
print 'Item 0 is', shoplist[0]
print 'Item 1 is', shoplist[1]
print 'Item 2 is', shoplist[2]
print 'Item 3 is', shoplist[3]
print 'Item -1 is', shoplist[-1]
print 'Item -2 is', shoplist[-2]
# Slicing on a list
print 'Item 1 to 3 is', shoplist[1:3]
print 'Item 2 to end is', shoplist[2:]
print 'Item 1 to -1 is', shoplist[1:-1]
print 'Item start to end is', shoplist[:]
# Slicing on a string
name = 'swaroop'
print 'characters 1 to 3 is', name[1:3]
print 'characters 2 to end is', name[2:]
print 'characters 1 to -1 is', name[1:-1]
print 'characters start to end is', name[:]
输出:
Item 0 is apple
Item 1 is mango
Item 2 is carrot
Item 3 is banana
Item -1 is banana
Item -2 is carrot
Item 1 to 3 is ['mango', 'carrot']
Item 2 to end is ['carrot', 'banana']
Item 1 to -1 is ['mango', 'carrot']
Item start to end is ['apple', 'mango', 'carrot', 'banana']
characters 1 to 3 is wa
characters 2 to end is aroop
characters 1 to -1 is waroo
characters start to end is swaroop
shoplist[1:3]返回从位置1开始,包括位置2,但是停止在位置3的一个序列切片,因此返回一个含有两个项目的切片。类似地,shoplist[:]返回整个序列的拷贝。
很显然翻译的这个参考这个词,太不合适了。
这是因为这里主要讲的是序列的赋值和引用问题
当使用赋值操作的时候只是引用,两个序列指向同一片内存地址
也就是说列表的赋值语句不创建拷贝内存。你得使用切片操作符来建立序列的内存的拷贝。
代码:
print 'Simple Assignment'
shoplist = ['apple', 'mango', 'carrot', 'banana']
mylist = shoplist # mylist is just another name pointing to the same object!
del shoplist[0]
print 'shoplist is', shoplist
print 'mylist is', mylist
# notice that both shoplist and mylist both print the same list without
# the 'apple' confirming that they point to the same object
print 'Copy by making a full slice'
mylist = shoplist[:] # make a copy by doing a full slice
del mylist[0] # remove first item
print 'shoplist is', shoplist
print 'mylist is', mylist
# notice that now the two lists are different
输出:
$ python reference.py
Simple Assignment
shoplist is ['mango', 'carrot', 'banana']
mylist is ['mango', 'carrot', 'banana']
Copy by making a full slice
shoplist is ['mango', 'carrot', 'banana']
mylist is ['carrot', 'banana']
你在程序中使用的字符串都是str类的对象。这个类的一些有用的方法会在下面这个例子中说明。如果要了解这些方法的完整列表,请参见help(str)。
代码:
# Filename: str_methods.py
name = 'Swaroop' # This is a string object
if name.startswith('Swa'):
print 'Yes, the string starts with "Swa"'
if 'a' in name:
print 'Yes, it contains the string "a"'
if name.find('war') != -1:
print 'Yes, it contains the string "war"'
delimiter = '_*_'
mylist = ['Brazil', 'Russia', 'India', 'China']
print delimiter.join(mylist)
输出:
$ python str_methods.py
Yes, the string starts with "Swa"
Yes, it contains the string "a"
Yes, it contains the string "war"
Brazil_*_Russia_*_India_*_China
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称
假如你有一个类称为MyClass和这个类的一个实例MyObject。当你调用这个对象的方法MyObject.method(arg1, arg2)的时候,这会由Python自动转为MyClass.method(MyObject, arg1, arg2)——这就是self的原理了。
这也意味着如果你有一个不需要参数的方法,你还是得给这个方法定义一个self参数。
代码:
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()
del kalam
swaroop.sayHi()
swaroop.howMany()
输出:
>>>
(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.
Abdul Kalam says bye.
There are still 1 people left.
Hi, my name is Swaroop.
I am the only person here.
>>>
其中Person.population += 1 是类的变量
__init__在开始时调用
__del__在对象被删除时调用
给C++/Java/C#程序员的注释
Python中所有的类成员(包括数据成员)都是 公共的 ,所有的方法都是 有效的 。
只有一个例外:如果你使用的数据成员名称以 双下划线前缀 比如__privatevar,Python的名称管理体系会有效地把它作为私有变量。
这样就有一个惯例,如果某个变量只想在类或对象中使用,就应该以单下划线前缀。而其他的名称都将作为公共的,可以被其他类/对象使用。记住这只是一个惯例,并不是Python所要求的(与双下划线前缀不同)。
同样,注意__del__方法与 destructor 的概念类似。
概念已经很熟悉了
看一下例子吧,另外还支持多重继承。
代码:
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
输出:
(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"
一个术语的注释——如果在继承元组中列了一个以上的类,那么它就被称作 多重继承 。
这里只是讲了讲最基本的操作,实际上,读读写写呗。最关键还是要学会使用help(file)来查找自己不知道的事。
代码:
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!
Python提供一个标准的模块,称为pickle。使用它你可以在一个文件中储存任何Python对象,之后你又可以把它完整无缺地取出来。这被称为 持久地 储存对象。
还有另一个模块称为cPickle,它的功能和pickle模块完全相同,只不过它是用C语言编写的,因此要快得多(比pickle快1000倍)。你可以使用它们中的任一个,而我们在这里将使用cPickle模块。记住,我们把这两个模块都简称为pickle模块。
代码:
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
输出:
['apple', 'mango', 'carrot']
首先,请注意我们使用了import..as语法。这是一种便利方法,以便于我们可以使用更短的模块名称。在这个例子中,它还让我们能够通过简单地改变一行就切换到另一个模块(cPickle或者pickle)!在程序的其余部分的时候,我们简单地把这个模块称为p。
我们使用pickle模块的load函数的返回来取回对象。这个过程称为 取储存 。
处理异常
我们可以使用try..except语句来处理异常。我们把通常的语句放在try-块中,而把我们的错误处理语句放在except-块中。
代码:
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'
输出:
Enter something -->
Why did you do an EOF on me?
$ python try_except.py
Enter something --> Python is exceptional!
Done
我在windows下弄不出那个EOFError的错误,应该在linux平台下的ctrl+D
我们把所有可能引发错误的语句放在try块中,然后在except从句/块中处理所有的错误和异常。except从句可以专门处理单一的错误或异常,或者一组包括在圆括号内的错误/异常。如果没有给出错误或异常的名称,它会处理 所有的 错误和异常。对于每个try从句,至少都有一个相关联的except从句。
你还可以让try..catch块关联上一个else从句。当没有异常发生的时候,else从句将被执行。
引发异常
你可以使用raise语句 引发 异常。你还得指明错误/异常的名称和伴随异常 触发的 异常对象。你可以引发的错误或异常应该分别是一个Error或Exception类的直接或间接导出类。
代码:
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.'
输出:
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.
假如你在读一个文件的时候,希望在无论异常发生与否的情况下都关闭文件,该怎么做呢?这可以使用finally块来完成
代码:
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'
中途用Ctrl-c来中断程序。
讲了sys模块 和os模块
恐怕暂时对我的程序没什么作用。
比如:os模块
这个模块包含普遍的操作系统功能。如果你希望你的程序能够与平台无关的话,这个模块是尤为重要的。即它允许一个程序在编写后不需要任何改动,也不会发生任何问题,就可以在Linux和Windows下运行。
这些都是类似于构造方法和析构方法一样的回调方法。
表15.1 一些特殊的方法
名称 | 说明 |
---|---|
__init__(self,...) | 这个方法在新建对象恰好要被返回使用之前被调用。 |
__del__(self) | 恰好在对象要被删除之前调用。 |
__str__(self) | 在我们对对象使用print 语句或是使用str() 的时候调用。 |
__lt__(self,other) | 当使用 小于 运算符(<)的时候调用。类似地,对于所有的运算符(+,>等等)都有特殊的方法。 |
__getitem__(self,key) | 使用x[key] 索引操作符的时候调用。 |
__len__(self) | 对序列对象使用内建的len() 函数的时候调用。 |
刚开始这个东西让我很痛苦呀
通过列表综合,可以从一个已有的列表导出一个新的列表。例如,你有一个数的列表,而你想要得到一个对应的列表,使其中所有大于2的数都是原来的2倍。对于这种应用,列表综合是最理想的方法。
代码:
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语句被用来创建新的函数对象,并且在运行时返回它们。
代码:
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(2)返回了一个函数,这个函数的名字叫twice,很显然再给twice传值进去,是make_repeater里面的s部分。
exec语句用来执行储存在字符串或文件中的Python语句。例如,我们可以在运行时生成一个包含Python代码的字符串,然后使用exec语句执行这些语句。下面是一个简单的例子。
代码:
>>> exec 'print "Hello World"'
Hello World
eval语句用来计算存储在字符串中的有效Python表达式。下面是一个简单的例子。
>>> eval('2*3')
6
assert语句用来声明某个条件是真的。例如,如果你非常确信某个你使用的列表中至少有一个元素,而你想要检验这一点,并且在它非真的时候引发一个错误,那么assert语句是应用在这种情形下的理想语句。当assert语句失败的时候,会引发一个AssertionError。
为什么直接用if?
代码:
>>> 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函数调用的时候返回的内容。