第1章 深入类和对象

1、鸭子类型 和 多态

1.1 鸭子类型

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

动态语言调用实例方法时不检查类型,只要方法存在,参数正确,就可以调用。这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
def extend(self, iterable): iterable 可迭代的对象,可以用for循环,列表、元组、集合都是可迭代对象,都可以用于extend函数

a = [1, 2]
b = [3, 4]
c = (5, 6)
d = {7, 8}

a.extend(b)   
print(a)

a的返回值:[1, 2, 3, 4]

a = [1, 2]
c = (5, 6)
a.extend(c)
print(a)

a的返回值:[1, 2, 5, 6]

a = [1, 2]
a.extend(d)
print(a)

a的返回值:[1, 2, 7, 8]

1.2 多态

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

class Cat(object):
    def say(self):
        print("I'm cat")


class Dog(object):
    def say(self):
        print("I'm dog")


class Duct(object):
    def say(self):
        print("I'm duct")

animal_list = [Cat, Dog, Duct]
for aninal in animal_list:
    aninal().say()

返回值:
在这里插入图片描述

2、抽象类型

2.1 判断某个对象类型

class Demo(object):

    def __init__(self, names):
        self.names = names

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

    def test(self):
        pass

d = Demo(['mysql','python'])

print(len(d))
# 返回值:2

#判断d对象是否包含有test函数
print(hasattr(d,'test'))
#返回值:True

#判断 1是不是整形
print(isinstance(1,int))
#返回值:True

#因为Demo实现了 __len__ 方法,所以 d 是不是Sized 类型
from collections.abc import Sized,Iterable

print(isinstance(d,Sized))
#返回值:True

2.2 强制子类实现某些方法,否则,raise抛出异常

2.2.1 用 raise 抛出异常

利用 raise 抛出异常

class CacheBase(object):
    def get(self, key):
        raise ValueError

   def set(self, key, value):
        raise NotImplementedError

class RedisBase(CacheBase):
    pass

r = RedisBase()
r.set('juran','python')

上面代码返回下面异常信息:
在这里插入图片描述

2.2.2 继承abc异常类装饰器@abstractmethod

改变2.2.1使得CacheBase类继承abc异常类装饰器@abstractmethod,这样强制子类重写,否则就报错。

import abc
class CacheBase(metacclass=abc.ABCMeta):
    @abc.abstractmethod
    def get(self, key):
        pass

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

class RedisBase(CacheBase):
    pass

r = RedisBase()
r.set('juran','python')

由于RedisBase 类没有重写set、get方法,所以,返回以下报错信息:
class CacheBase(metacclass=abc.ABCMeta):
TypeError: init_subclass() takes no keyword arguments

2.2.3 继承abc异常类装饰器,子类中重写父类方法,则不会报错

import abc
class CacheBase(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def get(self, key):
        pass

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

class RedisBase(CacheBase):
    #重写父类中的方法
    def get(self, key):
        pass
    def set(self, key, value):
        pass
r = RedisBase()
r.get('python')
r.set('juran','luoji')

运行上面代码,不会再报错

3-isinstance和type的区别

3.1 isinstance和type的区别

i = 1
s = ‘a’
print(type(s))
返回值:<class ‘str’>
print(type(i))
返回值:<class ‘int’>
print(isinstance(i,int))
返回值:True
print(isinstance(s,str))
返回值:True
print(isinstance(s,int))
返回值:False

class A:
    pass

class B(A):
    pass

b = B()

  • isinstance() 考虑继承关系
    print(isinstance(b,B))
    返回True
    print(isinstance(b,A))
    返回True

  • type() 不考虑继承关系
    print(type(b) is B)
    返回True
    print(type(b) is A)
    返回False

3.2 类变量和对象变量

class A:
    #类属性
    aa = 1

   #实例方法
    def __init__(self, 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类不能访问__init__方法中的x报错:
AttributeError: type object ‘A’ has no attribute ‘x’

A.aa = 11
a.aa = 22
print(a.aa)
print(A.aa)

返回值:22 11

b = A(1, 2)
print(b.aa)

返回值:11 #这里返回的是 A.aa = 11 设定的值

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

4.1 类属性和实例属性

class A(object):
    name = 'juran'

    def __init__(self):
        self.name = 'jr'

a = A()
print(a.name)  #实例属性
print(A.name)  #类属性

返回值:
jr
juran

4.2 MRO算法:

4.2.1 深度优先

在这里插入图片描述
Python2.2之前的算法:金典类
DFS(deep first search):A->B->D->C->E

4.2.2 广度优先

在这里插入图片描述
Python2.2版本之后,引入了BFS(广度优先搜索)
BFS:A->B->C->D

4.2.3 C3算法

在Python2.3之后,Python采用了C3算法 mro
在这里插入图片描述

class D():
    pass

class C(D):
    pass

class B(D):
    pass

class A(B, C):
    pass
print(A.__mro__)

返回值:A -> B -> C -> D
(<class ‘main.A’>, <class ‘main.B’>, <class ‘main.C’>, <class ‘main.D’>, <class ‘object’>)

在这里插入图片描述

class D():
    pass

class B(D):
    pass

class E():
    pass

class C(E):
    pass

class A(B, C):
    pass
print(A.__mro__)

返回值:A -> B -> D ->C -> E
(<class ‘main.A’>, <class ‘main.B’>, <class ‘main.D’>, <class ‘main.C’>, <class ‘main.E’>, <class ‘object’>)

4.3 Python对象的自省机制

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

class Person:
    name = 'campo'
    age = 20

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

user = Student('逻辑教育')

#__dict__ 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的
print('Student----',Student.__dict__)
#Student类属性:{'__module__': '__main__', '__init__': <function Student.__init__ at 0x00000200E35FC828>, '__doc__': None}

print('user----',user.__dict__)
#Student类对象user属性:{'school_name': '逻辑教育'}

# dir()函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表
print('dir()----',dir())
# dir()函数不带参数时:['Person', 'Student', '__annotations__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'user']

print('dir(user)----',dir(user))
# dir()函数带参数时:['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name', 'school_name']

print('isinstance----:',isinstance(user, Person))
#返回值:True


# hasattr()函数用于判断对象是否包含对应的属性
print('hasattr----:',hasattr(user, 'name'))
#返回值:True

print('type----:',type(user) is Student)
#返回值:True

print('type----:',type(user))
#返回值:<class '__main__.Student'>

print('isinstance-user:Stucent----',isinstance(user,Student))
#返回值:

print('isinstance-user:Person----',isinstance(user,Person))
#返回值:True

5 super

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

5.1 super().init()调用父类的构造函数

class A(object):
    def __init__(self):
        print('我是A类的init方法')


class B(A):
    def __init__(self):
        print("我是B类的init方法")
        #这里通过super()函数调用A的 __init__ 方法
        super().__init__()

def main():
    b = B()

if __name__ == '__main__':
    main()

返回值:
我是B类的init方法
我是B类的init方法

5.2 通过调用父类中属性 super().init(name, age, weight) 简化了子类

这个程序里面
super().init(name, age, weight)
可以替代:
People.init(self, name, age, weight)
这两条语句效果等价

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

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


class Student(People):
    def __init__(self, name, age, weight, grade):
        # self.name = name
        # self.age = age
        # self.weight = weight
        # 这里用super()调用父类中的函数来代替上面的三条语句
        # People.__init__(self, name, age, weight)
        super().__init__(name, age, weight)
        self.grade = grade


s = Student('lg', 18, 60, 3)
s.speak()

上面程序返回值:
lg 说:我18岁了,我在读3年级

5.3 mro 决定super 的执行顺序到底是什么样的

super 调用父类的方法,是按照 mro c3 算法调用的

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 D(B, C):
    def __init__(self):
        print('D')
        super().__init__()

d = D()
print(D.__mro__)

上面程序按照__mro__算法来调用的,决定继承关系

返回值:
D
B
C
A
(<class ‘main.D’>, <class ‘main.B’>, <class ‘main.C’>, <class ‘main.A’>, <class ‘object’>)

发布了31 篇原创文章 · 获赞 0 · 访问量 350

猜你喜欢

转载自blog.csdn.net/weixin_38027481/article/details/103737763