Python高级编程技巧第1讲 - 深入类和对象

一、深入类和对象

鸭子类型和多态

多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚"鸭子类型"

1.1 鸭子类型

a = [1,2]
b = [3,4]
c = (5,6)   # 元组 tuple
d = {7,8}   # 集合 set 无序的


# def extend(self,iterable):   iterable可迭代的对象   可以用for
a.extend(d)
print(a)   
结果:   [1, 2, 8, 7]  

其中,def extend(self,iterable): iterable可迭代的对象 可以用for

动态语言调用实例方法时不检查类型,只要方法存在,参数正确,就可以调用。这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

1.2 多态

所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态。

class Cat(object):
    def say(self):
        print("i am Cat")


class Dog(object):
    def say(self):
        print("i am Dog")


class Duck(object):
    def say(self):
        print("i am Duck")


animal_list = [Cat, Dog, Duck]
for animal in animal_list:
    animal().say()
    
结果:	i am Cat
		i am Dog
		i am Duck

二、抽象基类(abc模块)

应用场景1、判断某个对象的类型

class Demo(object):
    def __init__(self, names):
        self.names = names

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

    def test(self):
        pass

d = Demo(['je','qw'])
print(len(d))

# hasattr判断是否有这个方法
print(hasattr(d, 'test'))   #  True


from  collections.abc import Sized
print(isinstance(1, int))     # True
print(isinstance(d, Sized))   # True    检查d有没有__len__方法,因为Sized里面有__len__方法

Sized方法里面有__subclasshook__来实现判断 有没有__len__方法
在这里插入图片描述

应用场景2、需要强制某个子类必须实现某些方法

'''
我们需要强制某个子类必须实现某些方法
如果自己写web框架 要集成cache redis memcache等缓存

	@abc.abstractmethod  -- 装饰器
	metaclass=abc.ABCMeta 是 抽象基类,子类必须重写类方法
	有@abc.abstractmethod,如果 重写,则会报错
'''

import abc

class CacheBase(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def get(self, name):
        # raise ValueError
        pass

    @abc.abstractmethod
    def set(self, key,value):
        # raise NotADirectoryError
        pass


class RedisBase(CacheBase):
    # 重写父类中的方法
    def get(self, key):
        pass

    def set(self, key, value):
        pass

r = RedisBase()
# r.get('wee')
# print(r)

结论:

  • metaclass=abc.ABCMeta 是 抽象基类,子类必须重写类方法
  • 有@abc.abstractmethod,如果 重写,则会报错

三、isinstance 和 type的区别


if isinstance(i, int):
    print(1234)        # 可以打印


if type(i) is "int":
    print('qweqw')     # 打印不出来
class A:
    pass

class B(A):
    pass

b = B()
print(isinstance(b, B))
print(isinstance(b, A))     # True  考虑类的继承关系

print(type(b) is B)
print(type(b) is A)         # False  没有考虑类的继承关系
# == value
# 和 is  内存地址

四、类变量和对象变量

class A:
    # 类属性 类方法
    aa = 1

    # 实例方法
    def __init__(self, x, y):
        # x ,y 实例属性
        self.x = x
        self.y = y


a = A(1, 2)
print(a.x, a.y, a.aa)     # 1 2 1   可以向下查找

# print(A.x)              # 报错,不可向下查找

A.aa = 11      # 重新赋值
a.aa = 22
print(a.aa)    #  22
print(A.aa)    #  11

b = A(1, 2)
print(b.aa)    #  11     b.aa相当于A.aa

类属性和实例属性以及查找顺序

MRO算法

Python2.2之前的算法:金典类
DFS(deep first search):A->B->D->C->E

在这里插入图片描述

class D:
    pass


class B(D):
    pass

class E:
    pass


class C(E):
    pass


class A(B, C):
    pass

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

Python2.2版本之后,引入了BFS(广度优先搜索)
BFS:A->B->C->D

在这里插入图片描述

class D:
    pass

class B(D):
    pass

class C(D):
    pass

class A(B, C):
    pass

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

在Python2.3之后,Python采用了C3算法

Python新式类继承的C3算法:https://www.cnblogs.com/blackmatrix/p/5644023.html

五、Python对象的自省机制

自省是通过一定的机制查询到对象的内部结构
Python中比较常见的自省(introspection)机制(函数用法)有: dir(),type(), hasattr(), isinstance(),通过这些函数,我们能够在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。

六、super函数

在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现

class A:
    def __init__(self):
        print('A')

class B(A):
    def __init__(self):
        print('B')
        # python2的写法
        super(B, self).__init__()
        # python3的写法
        super().__init__()


b = B()

6.1 重写了B的构造函数 为什么还要去调用super

class People(object):
    def __init__(self, name, age, weight):
        self.name = name
        self.age = age
        self.weight = weight

    def speak(self):
        print("%s 说:我%d岁了"%(self.name, self.age))


class Student(People):
    def __init__(self,name, age, weight, grade):
        # self.name = name
        # self.age = age
        # self.weight = weight
        # super().__init__(name ,age, weight)
        People.__init__(self, name, age, weight)
        self.grade = grade

    def speak(self):
        print("%s 说:我%d岁了 我在读%d年级"%(self.name, self.age, self.grade))


s = Student('YYY', 20, 50, 6)
s.speak()

结果:  YYY 说:我20岁了 我在读6年级

super 执行顺序到底是什么样的?

class A:
    def __init__(self):
        print("A")

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

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

class E:
    pass

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

d = D()
print(D.__mro__)        # D B C A E

结论: super 并不是调用父类中的方法,而是按照 mro 算法来调用的

发布了46 篇原创文章 · 获赞 4 · 访问量 1292

猜你喜欢

转载自blog.csdn.net/Yauger/article/details/103711048
今日推荐