Python类和对象(高级编程一,二)
抽象基类
1 2 3 4 5 6 7 8 9 10 11 12 |
import abc class Person(metaclass=abc.ABCMeta): # 只能被继承,不能实例化,实例化会报错 @abc.abstractmethod # 被修饰的方法必须重写 def eat(self): pass @abc.abstractmethod def drink(self): pass |
TIP:为了解决Python2&3的兼容问题,需要引入six模块,该模块中有一个针对类的装饰器 @six.add_metaclass(MetaClass) 可以为两个版本的Python类方便地添加metaclass
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import abc import six @six.add_metaclass(abc.ABCMeta) class Person(object): @abc.abstractmethod def eat(self): pass @abc.abstractmethod def drink(self): pass |
对象比较(isinstance和type)
type()不会认为子类是一种父类类型
isinstance()会认为子类是一种父类类型
isinstance可以判断子类实例对象是属于父类的;而type会判断子类实例对象和父类类型不一样
type只接收一个参数,不但可以判断变量是否属于某个类型,而且可以得到参数变量未知的所属的类型;而isinstance只能判断是否属于某个已知类型,不能直接得到变量未知的所属的类型
1 2 3 4 5 6 7 8 9 10 11 |
# coding=UTF-8 >>> a = 4 >>> isinstance (a,int) True >>> isinstance (a,str) False >>> isinstance (a,(str,int,list))#与元组类型之一相同 True >>> isinstance(a,(str,list,float))#与元组类型都不相同 False |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# coding=UTF-8 class father(object): pass class son(father): pass >>>a=father() >>>b=son() >>>isinstance(a,father) True >>>type(a)==father True >>>isinstance(b,father)#isinstance得到子类实例是属于父类的 True >>>type(b)==father#type对于子类实例判断不属于父类 False |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# coding=UTF-8 class A(object): pass >>>a=A() #type判断变量是否属于某个类型 >>>type(a)==A True #type得到变量类型 >>>type(a) __main__.A #isinstance只能判断变量是否属于某个类型 >>>isinstance(a,A) True |
类属性和实例属性以及查找顺序
Python2.2之前的算法:金典类
Python2.2版本之后,引入了BFS(广度优先搜索)
在Python2.3之后,Python采用了C3算法
C3算法
可通过类调用mro()
获取查找顺序
自省机制
######dir()
dir() 函数可能是 Python 自省机制中最著名的部分了。它返回传递给它的任何对象的属性名称经过排序的列表。如果不指定对象,则 dir() 返回当前作用域中的名称。
type()
type() 函数有助于我们确定对象是字符串还是整数,或是其它类型的对象。它通过返回类型对象来做到这一点,可以将这个类型对象与 types 模块中定义的类型相比较
hasattr()
对象拥有属性,并且 dir() 函数会返回这些属性的列表。但是,有时我们只想测试一个或多个属性是否存在。如果对象具有我们正在考虑的属性,那么通常希望只检索该属性。这个任务可以由 hasattr() 和 getattr() 函数来完成.
isinstance()
可以使用 isinstance() 函数测试对象,以确定它是否是某个特定类型或定制类的实例
派生内置不可变类型并修改其实例化行为
1 2 3 4 5 |
class IntTuple(tuple): def __new__(cls, *args, **kwargs): f = (i for i in args if isinstance(i, int) and (i > 0)) return super().__new__(cls, f) |
创建大量实例节省内存
在python新式类中,可以定义一个变量slots,它的作用是阻止在实例化类时为实例分配dict,默认情况下每个类都会有一个dict,通过dict访问,这个dict维护了这个实例的所有属性。
由于每次实例化一个类都要分配一个新的dict,因此存在空间的浪费,因此有了slots。
slots是一个元组,包括了当前能访问到的属性。
当定义了slots后,slots中定义的变量变成了类的描述符,相当于java,c++中的成员变量声明,
类的实例只能拥有slots中定义的变量,不能再增加新的变量。注意:定义了slots后,就不再有dict
1 2 3 4 5 6 7 |
class Person(object): __slots__ = ('name', 'age') def __init__(self): self.name = "None" self.age = 10 |
TIP:使用slots要注意,slots定义的属性仅对当前类起作用,对继承的子类是不起作用的
Python中的with语句
1 2 3 |
with open('image.png','r') as f: f.read() |
contextlib简化上下文管理器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class OpenContext(object): def __init__(self, filename, mode): self.fp = open(filename, mode) def __enter__(self): return self.fp def __exit__(self, exc_type, exc_val, exc_tb): self.fp.close() if __name__ == '__main__': with OpenContext('abc.txt', 'w') as file: file.write("hello world") |
可以使用@contextmanager
修饰类
1 2 3 4 5 6 7 8 9 10 11 12 |
from contextlib import contextmanager @contextmanager class OpenContext(object): def __init__(self, filename, mode): fp = open(filename, mode) print("file open") try: yield fp finally: fp.close() |
创建可管理的对象属性
可使用property
管理属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Person: def __init__(self): self.__age = 10 def age(self): return self.__age def set_age(self, age): if not isinstance(age, int): raise TypeError("TypeError") self.__age = age def del_age(self): self.__age = None age = property(fget=age, fset=set_age, fdel=del_age) if __name__ == '__main__': p = Person() p.age = 33 print(p.age) |
让类支持比较操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from functools import total_ordering @total_ordering class Rect(object): def __init__(self, w, h): self.w = w self.h = h def area(self): return self.w * self.h def __lt__(self, other): # 重写小于方法,可以自动实现大于方法 return self.area() < other.area() def __eq__(self, other): # 等于方法 return self.area() == other.area() |
在环状数据结构中管理内存
使用weakref
修饰后引用计数不增加
1 2 3 4 5 |
import weakref a = A() a2 = weakref.ref(a) |
Python 垃圾回收机制
获取内存占用方法
1 2 3 4 5 6 7 8 9 10 11 12 |
import os import psutil # 显示当前 python 程序占用的内存大小 def show_memory_info(hint): pid = os.getpid() p = psutil.Process(pid) info = p.memory_full_info() memory = info.uss / 1024. / 1024 print('{} memory used: {} MB'.format(hint, memory)) |
循环引用解决
获取引用关系
1 2 3 4 5 6 7 8 9 10 |
import objgraph a = [1, 2, 3] b = [4, 5, 6] a.append(b) b.append(a) objgraph.show_refs([a]) |
objgraph.show_refs(d, filename=’sample-graph.png’)
dot转图片
清除没有引用的对象
1 2 3 4 |
import gc gc.collect() # 清理内存 |
Leave a Comment