面向对象
抽象基类(了解)
-
说明:
- 抽象基类就是为了统一接口而存在的
- 抽象类不能进行实例化(创建对象)
- 继承自抽象类的子类必须实现抽象类中的抽象方法
-
示例:
from abc import ABC, abstractmethod # 抽象基类 class Animal(ABC): # 定义抽象方法:规定接口 @abstractmethod def run(self): pass # 抽象基类无法实例化 # a = Animal() class Cat(Animal): # 子类中必须实现抽象基类的抽象方法,才能实例化 def run(self): print('猫喜欢走猫步') c = Cat()
特殊函数
-
示例1
d = {'name': 'xiaoming', 'age': 20} # 返回对象的字符串表示形式 r = repr(d) print(r, type(r)) # 执行有效的python代码字符串 d2 = eval(r) print(d2, type(d2)) a = 10 b = 20 c = eval('a + b') print(c)
-
示例2:
class Person: def __init__(self, name, age): self.name = name self.age = age # print打印对象,str方法转换时都会触发 def __str__(self): print('__str__') return '姓名:{} 年龄:{}'.format(self.name, self.age) # 返回对象的字符串表示形式,使用repr函数处理时会自动触发 def __repr__(self): return "Person('{}', {})".format(self.name, self.age) p = Person('王大花', 18) # print(p) # s = str(p) r = repr(p) print(r) p2 = eval(r) print(p2, type(p2))
内置方法
-
构造和析构
__init__、__del____
-
干预属性操作
__setattr__、__getattr__、__delattr__
-
支持字典操作
__setitem__、__getitem__、__delitem__
-
对象支持函数调用
__call__
-
打印输出或str转换
__str__
-
对象的字符串表示,调用repr方法时触发
__repr__
运算符重载
-
算术运算符
- 示例:
class Number: def __init__(self, num): self.num = num # 对象出现在'+'的左边时会自动触发 def __add__(self, other): print('__add__') return self.num + other # 对象出现在'+'的右边时会自动触发 def __radd__(self, other): print('__radd__') return self.num + other # +=运算时自动触发,若没有实现会调用__add__ def __iadd__(self, other): print('__iadd__') # 返回新的Number对象 # return Number(self.num + other) # 返回处理后的原始对象 self.num += other return self n = Number(10) print(id(n)) # ret = n + 20 # ret = 20 + n # print(ret) n += 50 # n = n + 50 print(id(n))
- 自行测试
加法:add、radd、iadd 减法:sub、rsub、isub 乘法:mul、rmul、imul 除法:truediv、rtruediv、itruediv 求余:mod、rmod、imod
-
关系运算符
class Number: def __init__(self, num): self.num = num # 大于 > def __gt__(self, other): print('__gt__') return self.num > other # 小于 < def __lt__(self, other): print('__lt__') return self.num < other # 等于 ==, 判断是否相等,当不实现__ne__时,!=运算也会触发 def __eq__(self, other): print('__eq__') return self.num == other # 大于等于 >= def __ge__(self, other): print('__ge__') return self.num >= other # 小于等于 <= def __le__(self, other): print('__le__') return self.num <= other # 不等于 != def __ne__(self, other): print('__ne__') return self.num != other n = Number(20) print(n > 10) print(n < 10) print(n == 10) print(n != 10)
内存管理
-
引用计数
- python中所有的数据都是通过类来实现的,对象的管理是通过引用计数实现的
- 当创建一个对象赋值给一个变量时,引用计数为1,当多一个变量指向该对象时,计数值加1;当少一个变量指向对象时,计数值减1。计数值减到0时会调用
__del__
方法释放存储空间 - 不可变变量引用计数是没有意义的
- 示例:
import sys # 不可变变量的引用计数没有意义 a = 10 print(sys.getrefcount(a)) lt = [1, 2, 3] lt2 = lt # 本身此时引用计数为1,但是该方法也引用了一次 print(sys.getrefcount(lt)) del lt2 print(sys.getrefcount(lt)) class Person: def __del__(self): print('对象即将释放') p = Person() print(sys.getrefcount(p)) del p print('over')
-
函数传参
- 对不可变变量来说,传递的是值,函数中不可能改变传递的参数
- 对于可变变量及自定义的类创建的对象,传递的是引用,函数中可以操作原对象
- 示例:
def test(a): a += 1 num = 100 # 对于不可变数据传递的是值 test(num) print(num) def test2(lt): lt[0] = 10 lt = [1, 2, 3] test2(lt) print(lt)
-
深浅拷贝
import copy lt = [1, 2, [3, 4]] # 赋值会增加一个引用,访问的都是同一数据 lt2 = lt # 浅拷贝:只拷贝对象本身,里面的元素只会增加一个引用 # lt2 = lt.copy() # 专门的拷贝函数,也是浅拷贝,等价于上面的拷贝 lt2 = copy.copy(lt) # 深拷贝:拷贝对象本身,对象中的元素也进行拷贝 # lt2 = copy.deepcopy(lt) lt[0] = 100 lt2 = 30 print(lt) print(lt2) print(id(lt)) print(id(lt2)) # 判断是否是同一对象的多个引用 print(lt is lt2)
数据持久化存储
-
说明:持久化存储方案,普通文件、数据库、序列化
-
示例:
import pickle class Person: def __init__(self, name, age): self.name = name self.age = age def __str__(self): return 'name:{} age:{}'.format(self.name, self.age) xiaoming = Person('xiaoming', 20) # print(xiaoming) # 序列化:会将对象转换为bytes # s = pickle.dumps(xiaoming) # print(s) # 反序列化:从bytes中解析出对象 # xm = pickle.loads(s) # print(xm, type(xm)) # 直接保存到文件 # fp = open('data.txt', 'wb') # pickle.dump(xiaoming, fp) # fp.close() # 从文件中读取对象 fp = open('data.txt', 'rb') xm = pickle.load(fp) print(xm, type(xm))