1.给类对象绑定的函数,只对这个对象生效, 而对类绑定的对象, 所有的对象都可以调用. 栗子:
def set_score(self, score): self.score = score s.set_age = MethodType(set_score, s) #对象绑定 Student.set_score = MethodType(set_score, Student) #绑定类
动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现
2.使用__slots__ 限制实例属性. 在定义class的时候,定义一个特殊的__slots__变量, 限制该class实例能添加的属性
class Student(object): __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
要注意,__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
3.使用@property可以将python定义的函数"当做"属性访问, 从而提供更加友好的访问方式, 但有时候setter/getter也是需要的.
内置装饰器负责把一个方法变成属性调用, 它既能检查参数,又可以用类似属性这样简单的方式来访问变量.
4.多重继承
class Animal(object): pass # 大类: class Mammal(Animal): pass class Bird(Animal): pass # 各种动物: class Dog(Mammal): pass class Bat(Mammal): pass class Parrot(Bird): pass class Ostrich(Bird): pass
IO编程
#!/usr/bin/env python # encoding: utf-8 f = open('./testdir/test.txt', 'r') #'r'表示读 f.read() #一次读取文件的全部内容 f.close() #关闭文件 #文件读写出错都可能产生IOError,一旦出错,f.close就不能调用 #为保证无论是否出错都能正确关闭文件,我们用try...finally实现 try: f = open('./testdir/Forever.mp3', 'rb') print(f.read()) finally: if f: f.close() #每次这样写太繁琐,引入with语句自动帮我们调用方法: with open('./testdir/test.txt', 'r') as f: print(f.read()) # read(size)防止一次性读取文件过多,内存负荷,可以反复调用 # 调用readline()可以每次读取一行内容 # 调用readlines()一次读取所有的内容并按行返回list #如果文件很小,read()一次性读取最方便;如果不能确定文件大小, #反复调用read(size)比较保险; #如果是配置文件,调用readlines()最方便 for line in f.readlines(): print(line.strip) #把末尾的' '删掉 ##file-like Object不要求从特定类继承,只要写个read()方法就行 # StringIO就是在内存中创建的file-like Object,常用作临时缓冲 #读取二进制文件,如图片视频音频等,用'rb' #要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数 # 栗子:读取GBK编码的文件 f = open('./testdir/Forever.mp3', 'rb') f.read() f = open('./testdir/test.txt', 'r', encoding = 'gbk') f.read() #某些不规范文件,会遇到UnicodeDecodeError,因为在文本文件中可能 #夹杂了一些非编码的字符. 这是open()函数还接收一个errors参数, #表示如果遇到编码错误后如何处理. 最简单处理是直接忽略 f = open('./testdir/Forever.mp3', 'r', encoding = 'gbk', errors = 'ignore') #写文件 'w'文本文件, 'wb'二进制文件 f = open('./testdir/test.txt', 'w') f.write('gogleem') f.close() #保险的with语句,防止忘记写close with open('./testdir/test.txt', 'w') as f: f.write('Frente!') #要写入特定编码的文本文件,请给open()函数传入encoding参数, # 字符串自动转换成指定编码 #使用with语句操作文件IO是个好习惯 # w是覆盖, a是续写
StringIO和BytesIO
StringIO:内存中读写str, 要把str写入StringIO,我们需要先创建一个StringIO,然后像写文件一样写入即可
from io import StringIO f = StringIO() f.wrie('hello') f.wrie(' ') f.wrie('world!') print(f.getvalue()) #getvalue()方法用于获得写入后的str
要读取StringIO可以用一个str初始化StringIO, 然后像读文件一样读取
from io import StringIO f = StringIO(' Hello! Goodbye! ') while True: s = f.readline() if s =='': #不太明白这里判断这个的意思 break #但是没有这个,会影响下面的打印 print(s.strip()) #strip()函数能够去掉字符串前后的空格
BytesIO
操作二进制数据,实现了在内存中读写bytes,我们创建 一个BytesIO, 然后写入一些bytes
from io import BytesIO f = BytesIO() f.write('中文'.encode('utf-8')) print(f.getvalue()) #from io import StringIO f = BytesIO(b'xe4xb8xadxe6x96x87') f.read() #和stringIO类似,可以用一个bytes初始化BytesIO,然后像读文件一样读取 #读文件和读二进制与读文件的区别是,from import的不同,打开的不同 #读文件使用open, 读StringIo用StringIO,而读BytesIO用的是BytesIO打开 #其他的读写操作是一样的,接口一致
操作文件和目录
Python内置的os模块可以直接调用操作系统提供的接口函数.
linux下的shell指令,前面加上os就可以在python中使用了. 栗子: os.uname()
import os #import shutil a = os.path.abspath('.') #当前文件的绝对路径 b = os.path.abspath('./animal/animal.py') print(a, ' ', b) c = os.path.join('/yu/you', 'imhp.txt') #将路径和文件名连接,完整的目录表示出来 print(c) os.mkdir('/home/feixiao/demo/Py_Rabbic/a') #创建一个目录 os.rmdir('/home/feixiao/demo/Py_Rabbic/a') #注意,linux和mac下路径分隔符是/,win下是 d = os.path.split('/home/feixiao/demo/Py_Rabbic/testdir/test2.txt') #把路径拆分为目录和文件名 print(d) print(d[0]) print(d[1]) #拆分路径名不要求文件一定存在 open('out.md', 'w') os.rename('out.md', 'out.txt') #重命名文件 os.remove('out.txt') #移除文件 #os模块中不存在复制文件 #求一个shutil模块copyfile()函数拷贝文件的栗子~~~><~~~ #os模块封装了操作系统的目录和文件操作,这些函数有的在os模块中,有的在os.path
序列化
序列化在这里不介绍了,上一篇文章有用CPP实现的专门的一篇
import pickle #序列化头文件 d = dict(name = 'Jared', age = 43, score = 100) c = pickle.dumps(d) #序列化字典d中的内容,打印出来 print(c) #python的好处就是可以把任何东西赋值成一个变量 f = open('./testdir/test.txt', 'wb') pickle.dump(d, f) #把d的内容序列化后写入f文件中 f.close() f = open('./testdir/test.txt', 'rb') d = pickle.load(f) #读文件中序列化记录的文件, 反序列化读出 f.close() print(d)
JSON
#在不同编程语言间传递对象 #把对象序列化为标准格式,如XML,ini,但更好的方法是序列化为JSON #因为JSON表示出来是一个字符串,可被所有语言读取,也可以方便存储到磁盘或网络传输 #JSON比XML快,可以直接在Web页面中读取 # import json d = dict(name = 'Jared', age = 43, score = 100) c = json.dumps(d) #dumps()方法返回一个str, 内容就是标准的JSON.它可以把JSON写入一个file-like-Object #要把JSON反序列化为Python对象,用loads()或者对应的load()方法 #前者把JSON字符反序列化,后者从file-like-object中读取字符串并反序列化 print(c) json_str = '{"age":43, "score":100, "name":"Jared"}' #哈,这里很有意思的引号,开始我用的全是单引号,报错了,分析是age的前引号被当字符串后引号配对了 #所以,就把引号中的引号换了 c = json.loads(json_str) print(c) #JSON编码是utf-8,所以Py的str可以与之自由交换
序列化类
import json class Student(object): def __init__(self, name, age, score): self.name= name self.age = age self.score = score #python类的序列化函数与CPP不同,序列化函数不在类中 #而C++中嵌入式序列化ar & a是在类中的 def student2dict(std): return{#这个序列化函数,把要打印的数据放到一个dict的字符串中 'name':std.name, 'age':std.age, 'score':std.score } s = Student('Jared', 43, 100) print(json.dumps(s, default = student2dict)) #把任意class的实例变为dict: print(json.dumps(s, default = lambda obj:obj.__dict__)) #这依然需要序列化函数,把类序列化到dict中 #通常class的实例都有一个__dict__属性,它就是一个dict,用来存储实例变量. #也有少数例外,比如定义了__slots__的class. #同,要把JSON反序列化为一个Student对象实例,loads()方法首先转换出一个dict对象, #然后,传入 object_hook函数负责把dict转换为Student实例: #类的反序列化 #def dict2student(d): # return Student(d['name'], d['age'], s['score']) #json_str = '{"age":43, "score":100, "name":"Jared"}' #print(json.loads(json_str, object_hook = dict2student)) #我自己写的这段不知道为啥就是会报错/V def dict2student(d): return Student(d['name'],d['age'],d['score']) json_str = '{"age": 20, "score": 88, "name": "Bob"}' print(json.loads(json_str, object_hook=dict2student)) #打印出反序列化的Student实例对象 #Python语言特定的序列化模块是pickle,但要使序列化更通用,更符合Web标准,用json # json模块的dumps()和losds()函数是定义的非常好的接口典范 #使用时,只需传入一个必须的参数 #当默认机制不满足要求,传入更多参数, #既做到了接口简单易用,又做到了充分的扩展性和灵活性