面向对象的高级编程&IO编程

时间:2021-09-01 21:05:33

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) #把末尾的'\n'删掉 ##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!\n 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'\xe4\xb8\xad\xe6\x96\x87')
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, '\n', 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()函数是定义的非常好的接口典范
#使用时,只需传入一个必须的参数
#当默认机制不满足要求,传入更多参数,
#既做到了接口简单易用,又做到了充分的扩展性和灵活性