7.15. 类的高级特性

7.15.1. super函数的执行顺序

#!/usr/bin/env python
#-*- coding:utf8 -*-
class A:
    def __init__(self):
        print('A')

class B(A):
    def __init__(self):
        print('B')
        super(B, self).__init__()


class C(A):
    def __init__(self):
        print('C')
        super().__init__()


class D(B,C):
    def __init__(self):
        print('D')
        super(D, self).__init__()

if __name__ == '__main__':
    print(D.__mro__)          #(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
    d = D()

7.15.2. super()函数的使用

#!/usr/bin/env python
#-*- coding:utf8 -*-
# auther; 18793
# Date:2019/5/10 17:53
# filename: 类的继承2.py
class Employee:
    def __init__(self,salary):
        self.salary = salary

    def work(self):
        print("普通员工正在写代码,工资是:",self.salary)

class Customer:
    def __init__(self,favorite,address):
        self.favorite = favorite
        self.address = address
    def info(self):
        print("我是一个顾客,我的爱好是:{},地址是:{}".format(self.favorite,self.address))


class Manager(Employee,Customer):
    #重写父类的构造方法
    def __init__(self,salary,favorite,address):
        print("--------Manager的构造方法------------")
        #通过super()函数调用父类的构造方法
        super(Manager, self).__init__(salary)
        #同上面的效果一样
        # super().__init__(salary)

        Customer.__init__(self,favorite, address)

if __name__ == '__main__':
    m = Manager(25000,"IT产品","深圳")
    m.work()
    m.info()

7.15.3. 对象的 自省 功能

#!/usr/bin/env python
#-*- coding:utf8 -*-
class Person(object):
    '''
    人类
    '''
    name = "hujianli"


class Student(Person):
    def __init__(self,school_name):
        self.school = school_name


if __name__ == '__main__':
    user = Student("仙剑")
    print(user.__dict__)        #查看类属性,自省
    print(Person.__doc__)
    print(Person.__dict__)
    user.__dict__["school_addr"] = "北京"
    print(user)
    print(user.__dict__)
    print(dir(user))

7.15.4. 类中实例属性的查找顺序

#!/usr/bin/env python
#-*- coding:utf8 -*-
class D:
    pass

class E:
    pass

class C(E):
    pass

class B(D):
    pass

class A(B,C):
    pass

#顺序:A,B,D,C,E
#__mro__,类的属性查找顺序
print(A.__mro__)

#(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)

7.15.5. isinstance()的用法

#!/usr/bin/env python
#-*- coding:utf8 -*-
'''
语法:

isinstance(object, classinfo)
object 是变量,classinfo 是类型即 (tuple,dict,int,float,list,bool等) 和 class类
'''
print(isinstance(1,int))
print(isinstance(1.0,float))
print(isinstance("aa",str))
print(isinstance(1,list))


print()
print()
'''
type()与isinstance()的区别:

共同点:两者都可以判断对象类型
不同点:对于一个 class 类的子类对象类型判断,type就不行了,而 isinstance 可以。
'''

class A(object):
    pass

class B(A):
    pass


b = B()
print(isinstance(b,B))
print(isinstance(b,A))
print(" type ".center(100,"*"))
print(type(b) is B)           #True
#b指向了B()对象,虽然A是B的父类,但是A是另外一个对象,它们的id是不相等的
print(type(b) is A)           #False

7.15.6. 抽象基类

代码示例 1

#!/usr/bin/env python
#-*- coding:utf8 -*-
#判断类是否有某种属性


#抽象基类的作用类似于JAVA中的接口。在接口中定义各种方法,然后继承接口的各种类进行具体方法的实现。
# 抽象基类就是定义各种方法而不做具体实现的类,任何继承自抽象基类的类必须实现这些方法,否则无法实例化
#抽象基类(abc模块)

class Company(object):
    def __init__(self, employee_list):
        self.employee = employee_list

    def __len__(self):
        return len(self.employee)

com = Company(["11", "22", "33"])

#hasattr判断类有没有某种属性,方法也是类的属性
print(hasattr(com,"__len__"))   #True

#虽然用hasattr可以判断,但正确的方式是定义一个抽象基类

#我们在某些情况下希望判定某个对象的类型,可以用抽象基类
from collections.abc import Sized
print(isinstance(com,Sized))    #True
print(len(com))

代码示例 2

#!/usr/bin/env python
#-*- coding:utf8 -*-
#模拟一个抽象基类

#写一个抽象基类,它的子类必须要重写抽象基类里面的方法
import abc
#定义一个抽象基类
class CacheBase(metaclass=abc.ABCMeta):
    @abc.abstractclassmethod
    def get(self,key):
        pass

    @abc.abstractclassmethod
    def set(self,key,value):
        pass

#子类,必须有抽象基类里面的方法,get和set
#假入不写set方法会报错

class RedisCache(CacheBase):
    def get(self,key):
        pass

    def set(self,key,value):
        pass

redis_cache = RedisCache()

抽象类与接口

#!/usr/bin/env python
# -*- coding:utf8 -*-
# @auther:   18793
# @Date:    2020/6/19 14:09
# @filename: sample.py
# @Email:    1879324764@qq.com
# @Software: PyCharm
import abc


class All_file(metaclass=abc.ABCMeta):
    all_type = "file"

    @abc.abstractmethod  # 定义抽象方法,无需实现功能
    def read(self):
        """ 子类必须定义读功能"""
        pass

    @abc.abstractmethod
    def write(self):
        """ 子类必须定义写功能"""
        pass


# class Txt(All_file):
#     pass
#
# t1 = Txt()

class Txt(All_file):  # 子类继承抽象类,必须定义read和write方法
    def read(self):
        print("读文本数据...............")

    def write(self):
        print("写文本数据...............")


class Sata(All_file):  # 子类继承抽象类,必须定义read和write方法
    def read(self):
        print("硬盘数据的读方式..........")

    def write(self):
        print("硬盘数据的写方式..........")


class Process(All_file):  # 子类继承抽象类,必须定义read和write方法
    def read(self):
        print("进程数据的读方式..........")

    def write(self):
        print("进程数据的写方式..........")


wenben = Txt()
yingpan = Sata()
jingcheng = Process()

wenben.read()
yingpan.write()
jingcheng.read()

print(wenben.all_type)
print(yingpan.all_type)
print(jingcheng.all_type)

抽象类本质上还是类,它指的是一组类的相似性, 包括数据属性(如all_type)和函数属性(如read、write), 而接口只强调函数属性的相似性。

抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计。

7.15.7. 元类

#!/usr/bin/env python
#-*- coding:utf8 -*-
# 把User类创建的过程委托给元类去做,这样代码的分离性比较好

class MetaClass(type):
    def __new__(cls, *args, **kwargs):
        return super().__new__(cls,*args, **kwargs)

class User(metaclass=MetaClass):
    def __init__(self,name):
        self.name = name

    def __str__(self):
        return "test"

if __name__ == '__main__':
    #python中类的实例化过程,会首先寻找metaclass,通过metaclass去创建User类
    my_obj = User(name="derek")
    print(my_obj)    #test

7.15.8. 通过type来创建类

#!/usr/bin/env python
#-*- coding:utf8 -*-

print("一个简单type创建类的例子".center(100,"*"))
#type(object_or_name, bases, dict)
#type里面有三个参数,第一个类名,第二个基类名,第三个是属性
User = type("User",(),{"name":"derek"})

my_obj = User()
print(my_obj.name)    #derek

print(" 使用type创建类和方法 ".center(100,"*"))

#不但可以定义属性,还可以定义方法
def say(self):     #必须加self
    return "i am derek"

User = type("User",(),{"name":"derek","say":say})

my_obj = User()
print(my_obj.name)     #derek
print(my_obj.say())    #i am derek

print(" 让type创建的类继承一个基类 ".center(100,"*"))
def say(self):     #必须加self
    return "i am derek"

class BaseClass:
    def answer(self):
        return "i am baseclass"

#type里面有三个参数,第一个类名,第二个基类名,第三个是属性
User = type("User",(BaseClass,),{"name":"derek","say":say})

if __name__ == '__main__':

    my_obj = User()
    print(my_obj.name)          #d erek
    print(my_obj.say())         # i am derek
    print(my_obj.answer())      # i am baseclass

7.15.9. 通过传入的字符串动态的创建不同的类

#!/usr/bin/env python
#-*- coding:utf8 -*-
def create_class(name):
    if name == 'user':
        class User:
            def __str__(self):
                return "user"
        return User

    elif name == "company":
        class Company:
            def __str__(self):
                return "company"
        return Company

if __name__ == '__main__':
    Myclass = create_class("user")
    my_obj = Myclass()
    print(my_obj)    #user
    print(type(my_obj))     #<class '__main__.create_class.<locals>.User'>