Python类和对象(高级编程一,二)

299 阅读5分钟

抽象基类

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

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只能判断是否属于某个已知类型,不能直接得到变量未知的所属的类型

# 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
# 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
# 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() 函数测试对象,以确定它是否是某个特定类型或定制类的实例


派生内置不可变类型并修改其实例化行为

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

class Person(object):
    __slots__ = ('name', 'age')

    def __init__(self):
        self.name = "None"
        self.age = 10

TIP:使用__slots__要注意,__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的


Python中的with语句

with open('image.png','r') as f:
  f.read()
contextlib简化上下文管理器
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修饰类

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管理属性

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)

让类支持比较操作

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修饰后引用计数不增加

import weakref

a = A()
a2 = weakref.ref(a)

Python 垃圾回收机制

获取内存占用方法
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))
循环引用解决

获取引用关系

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转图片

清除没有引用的对象

import gc

gc.collect() # 清理内存