python学习

来源:互联网 发布:无尽之剑3宝石数据修改 编辑:程序博客网 时间:2024/05/01 08:23

python 学习

1.python解释器

  cPython JPython IPython PyPy Jython IronPython

2.第一个python程序

python print 'hello world'print 'hello','pyhton','world' /*逗号分隔,显示为空号分隔*/print 100print 100+300shell 方式vim hello.py#!/usr/bin/env python  /**如果不加这行,那么需要python环境*/print 'hello','pyhton','world'运行方式python  hello.py./hello.py

3.基本语法

3.1 输入输出

>>> name = raw_input()ssss>>> print namessss>>> name = raw_input('please enter your name: ')print 'hello,', name

数据类型

面向对象高级特性

>>> def set_age(self, age): # 定义一个函数作为实例方法...     self.age = age...>>> from types import MethodType>>> s.set_age = MethodType(set_age, s, Student) # 给实例绑定一个方法>>> s.set_age(25) # 调用实例方法>>> s.age # 测试结果25但是,给一个实例绑定的方法,对另一个实例是不起作用的:    >>> s2 = Student() # 创建新的实例    >>> s2.set_age(25) # 尝试调用方法Traceback (most recent call last):File "<stdin>", line 1, in <module>为了给所有实例都绑定方法,可以给class绑定方法:>>> def set_score(self, score):...     self.score = score...    >>> Student.set_score = MethodType(set_score, None, Student)给class绑定方法后,所有实例均可调用:>>> s.set_score(100)>>> s.score100>>> s2.set_score(99)>>> s2.score99

使用slots

但是,如果我们想要限制class的属性怎么办?比如,只允许对Student实例添加name和age属性。

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的slots变量,来限制该class能添加的属性:>>> class Student(object):
slots = (‘name’, ‘age’) # 用tuple定义允许绑定的属性名称

s = Student() # 创建新的实例>>> s.name = 'Michael' # 绑定属性'name'>>> s.age = 25 # 绑定属性'age'>>> s.score = 99 # 绑定属性'score'Traceback (most recent call last):File "<stdin>", line 1, in <module>AttributeError: 'Student' object has no attribute 'score'除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__

使用@property
在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:
s = Student()
s.score = 9999
这显然不合逻辑。为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score()方法里,就可以检查参数:
class Student(object):

def get_score(self):    return self._scoredef set_score(self, value):    if not isinstance(value, int):        raise ValueError('score must be an integer!')    if value < 0 or value > 100:        raise ValueError('score must between 0 ~ 100!')    self._score = value

现在,对任意的Student实例进行操作,就不能随心所欲地设置score了:
s = Student()
s.set_score(60) # ok!
s.get_score()
60
s.set_score(9999)
Traceback (most recent call last):
ValueError: score must between 0 ~ 100!
但是,上面的调用方法又略显复杂,没有直接用属性这么直接简单。

有没有既能检查参数,又可以用类似属性这样简单的方式来访问类的变量呢?对于追求完美的Python程序员来说,这是必须要做到的!

还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。Python内置的@property装饰器就是负责把一个方法变成属性调用的:

class Student(object):

@propertydef score(self):    return self._score@score.setterdef score(self, value):    if not isinstance(value, int):        raise ValueError('score must be an integer!')    if value < 0 or value > 100:        raise ValueError('score must between 0 ~ 100!')    self._score = value

@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:

    >>> s = Student()    >>> s.score = 60 # OK,实际转化为s.set_score(60)    >>> s.score # OK,实际转化为s.get_score()    60    >>> s.score = 9999    Traceback (most recent call last):      ...    ValueError: score must between 0 ~ 100!

注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。

还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:

class Student(object):

@propertydef birth(self):    return self._birth@birth.setterdef birth(self, value):    self._birth = value@propertydef age(self):    return 2014 - self._birth

上面的birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。
@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。

多重继承
class Dog(Mammal, RunnableMixin, CarnivorousMixin):
pass
Mixin

在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为Mixin。

为了更好地看出继承关系,我们把Runnable和Flyable改为RunnableMixin和FlyableMixin。类似的,你还可以定义出肉食动物CarnivorousMixin和植食动物HerbivoresMixin,让某个动物同时拥有好几个Mixin:

class Dog(Mammal, RunnableMixin, CarnivorousMixin):
pass
Mixin的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个Mixin的功能,而不是设计多层次的复杂的继承关系。

Python自带的很多库也使用了Mixin。举个例子,Python自带了TCPServer和UDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixin和ThreadingMixin提供。通过组合,我们就可以创造出合适的服务来。

比如,编写一个多进程模式的TCP服务,定义如下:

class MyTCPServer(TCPServer, ForkingMixin):
pass
编写一个多线程模式的UDP服务,定义如下:

class MyUDPServer(UDPServer, ThreadingMixin):
pass
如果你打算搞一个更先进的协程模型,可以编写一个CoroutineMixin:

class MyTCPServer(TCPServer, CoroutineMixin):
pass
这样一来,我们不需要复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类。

小结

由于Python允许使用多重继承,因此,Mixin就是一种常见的设计。

只允许单一继承的语言(如Java)不能使用Mixin的设计。

文件读写

要以读文件的模式打开一个文件对象,使用Python内置的open()函数,传入文件名和标示符:

 f = open('/Users/michael/test.txt', 'r')标示符'r'表示读,这样,我们就成功地打开了一个文件。

如果文件不存在,open()函数就会抛出一个IOError的错误,并且给出错误码和详细的信息告诉你文件不存在:

f=open(‘/Users/michael/notfound.txt’, ‘r’)
Traceback (most recent call last):
File “”, line 1, in
IOError: [Errno 2] No such file or directory: ‘/Users/michael/notfound.txt’
如果文件打开成功,接下来,调用read()方法可以一次读取文件的全部内容,
Python把内容读到内存,用一个str对象表示:

>>> f.read()'Hello, world!'

最后一步是调用close()方法关闭文件。文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的:

f.close()
由于文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用try … finally来实现:

try:
f = open(‘/path/to/file’, ‘r’)
print f.read()
finally:
if f:
f.close()
但是每次都这么写实在太繁琐,所以,Python引入了with语句来自动帮我们调用close()方法:

with open(‘/path/to/file’, ‘r’) as f:
print f.read()
这和前面的try … finally是一样的,但是代码更佳简洁,并且不必调用f.close()方法。

调用read()会一次性读取文件的全部内容,如果文件有10G,内存就爆了,所以,要保险起见,可以反复调用read(size)方法,每次最多读取size个字节的内容。另外,调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list。因此,要根据需要决定怎么调用。

如果文件很小,read()一次性读取最方便;如果不能确定文件大小,反复调用read(size)比较保险;如果是配置文件,调用readlines()最方便:

for line in f.readlines():
print(line.strip()) # 把末尾的’\n’删掉
file-like Object

像open()函数返回的这种有个read()方法的对象,在Python中统称为file-like Object。除了file外,还可以是内存的字节流,网络流,自定义流等等。file-like Object不要求从特定类继承,只要写个read()方法就行。

StringIO就是在内存中创建的file-like Object,常用作临时缓冲。

二进制文件

前面讲的默认都是读取文本文件,并且是ASCII编码的文本文件。要读取二进制文件,比如图片、视频等等,用’rb’模式打开文件即可:

f = open(‘/Users/michael/test.jpg’, ‘rb’)
f.read()
‘\xff\xd8\xff\xe1\x00\x18Exif\x00\x00…’ # 十六进制表示的字节
字符编码

要读取非ASCII编码的文本文件,就必须以二进制模式打开,再解码。比如GBK编码的文件:

f = open(‘/Users/michael/gbk.txt’, ‘rb’)
u = f.read().decode(‘gbk’)
u
u’\u6d4b\u8bd5’
print u
测试
如果每次都这么手动转换编码嫌麻烦(写程序怕麻烦是好事,不怕麻烦就会写出又长又难懂又没法维护的代码),Python还提供了一个codecs模块帮我们在读文件时自动转换编码,直接读出unicode:

import codecs
with codecs.open(‘/Users/michael/gbk.txt’, ‘r’, ‘gbk’) as f:
f.read() # u’\u6d4b\u8bd5’
写文件

写文件和读文件是一样的,唯一区别是调用open()函数时,传入标识符’w’或者’wb’表示写文本文件或写二进制文件:

f = open(‘/Users/michael/test.txt’, ‘w’)
f.write(‘Hello, world!’)
f.close()
你可以反复调用write()来写入文件,但是务必要调用f.close()来关闭文件。当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。所以,还是用with语句来得保险:

with open(‘/Users/michael/test.txt’, ‘w’) as f:
f.write(‘Hello, world!’)
要写入特定编码的文本文件,请效仿codecs的示例,写入unicode,由codecs自动转换成指定编码。

小结

在Python中,文件读写是通过open()函数打开的文件对象完成的。使用with语句操作文件IO是个好习惯。

>>> os.getenv('path')>>> os.path.abspath('.')'/opt/pythonStudy/examples/base'>>> os.path.join('opt/pythonStudy/examples/base','testdir')'opt/pythonStudy/examples/base/testdir'>>> os.mkdir('opt/pythonStudy/examples/base/testdir')Traceback (most recent call last):  File "<stdin>", line 1, in <module>    OSError: [Errno 2] No such file or directory: 'opt/pythonStudy/examples/base/testdir'>>> os.mkdir('/opt/pythonStudy/examples/base/testdir')>>> os.rmdir('opt/pythonStudy/examples/base/testdir')Traceback (most recent call last):  File "<stdin>", line 1, in <module>OSError: [Errno 2] No such file or directory:   'opt/pythonStudy/examples/base/testdir'>>> os.rmdir('/opt/pythonStudy/examples/base/testdir')
0 0