第四章深入理解类和对象

1.鸭子类型和多态

具有相同方法可以做相同任务就是鸭子类型

 1 class Cat(object):
 2     def say(self):
 3         print("cat")
 4 
 5 
 6 class Dog(object):
 7     def say(self):
 8         print("dog")
 9 
10 
11 class Duck(object):
12     def say(self):
13         print("duck")
14 
15 
16 animal_list = [Cat, Dog, Duck]
17 for animal in animal_list:
18     animal().say()      # cat dog duck,具有多态性

2.抽象基类(abstruct模块)

(1)概念:

  • 抽象基类无法实例化
  • 规定继承类必须具有抽象基类指定的方法

(2)使用:

  • 检查某个类是否有某种方法
  • 判定某个对象的类型:使用isintance不建议使用type
  • sf
 1 # 检查某个类是否有某种方法
 2 class Company(object):
 3     def __init__(self, employee_list):
 4         self.employee = employee_list
 5 
 6     def __len__(self):
 7         return len(self.employee)
 8 
 9 
10 com = Company(["wzh1","wzh2"])
11 print(hasattr(com, "__len__"))  # True
 1 # 我们在某些情况之下希望判定某个对象的类型
 2 class A:
 3     pass
 4 
 5 
 6 class B:
 7     pass
 8 
 9 
10 b = B()
11 print(isinstance(b, A))  # False
12 print(isinstance(b, B))  # True
 1 # 如何去模拟一个抽象基类
 2 import abc
 3 
 4 
 5 class CacheBase(metaclass=abc.ABCMeta):
 6     @abc.abstractmethod
 7     def get(self, key):
 8         pass
 9 
10     @abc.abstractmethod
11     def set(self, key, value):
12         pass
13 
14 
15 class RedisCache(CacheBase):
16     def get(self, key):
17         print("get")
18 
19     def set(self, key, value):
20         print("set")
21 
22 
23 redis_cache = RedisCache()
24 redis_cache.set("name", "wzh")  # set
 1 # 如何去模拟一个抽象基类
 2 class CacheBase(object):
 3     def get(self, key):
 4         raise NotImplementedError   # 子类没有重写就报错
 5 
 6     def set(self, key, value):
 7         raise NotImplementedError   # 子类没有重写就报错
 8 
 9 
10 class RedisCache(CacheBase):
11     def get(self, key):
12         print("get")
13 
14     def set(self, key, value):
15         print("set")
16 
17 
18 redis_cache = RedisCache()
19 redis_cache.set("name", "wzh")  # set

3.使用isintance而不是type

  • is 和 == 不要乱用:
    • is:比较两个对象的地址(id)是否相同
    • ==:比较两个变量值是否相同
  • type和isinstance区别:
    • type不会追溯到基类去比较,isinstance会追溯到基类比较
 1 class A:
 2     pass
 3 
 4 
 5 class B(A):
 6     pass
 7 
 8 
 9 b = B()
10 print(isinstance(b, B))   # True
11 print(isinstance(b, A))   # True
12 
13 print(type(b) is B)     # True
14 print(type(b) is A)     # False

4.类变量和对象变量

  • 类变量:类中定义的变量
  • 对象变量:又称实例变量,__init__中定义的变量

注意:使用对象名去修改类变量,不会真实修改类中的类变量,只会开辟一个对象变量保存修改的值并且只有这个对象才会是有修改的值,其他创建对象都是类变量原来的值

 1 class A:
 2     aa = 1  # 类变量
 3 
 4     def __init__(self, x, y):
 5         self.x = x  # 实例变量
 6         self.y = y  # 实例变量
 7 
 8 
 9 a = A(2, 3)
10 
11 A.aa = 11
12 a.aa = 100  # 开辟一块空间定义a.aa变量,但类变量A.aa不会改变
13 print(a.x, a.y, a.aa)
14 print(A.aa)
15 
16 b = A(3, 5)
17 print(b.aa)

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

  • 属性重名:先找对象实例的属性再找类中的属性
  • 查找算法:C3算法

属性重名查找:

 1 class Person:
 2     name = "Person.name"
 3     age = 25
 4 
 5     def __init__(self):
 6         self.name = "self.name"
 7 
 8 
 9 person = Person()
10 print(person.name)  # self.name  先找实例属性再找类属性
11 print(person.age)   # 25        实例属性中没有就用类属性

继承查找:

 1 # 新式类:对于没有写父类的类都会去继承object类
 2 class D:
 3     pass
 4 
 5 
 6 class E:
 7     pass
 8 
 9 
10 class C(E):
11     pass
12 
13 
14 class B(D):
15     pass
16 
17 
18 class A(B, C):
19     pass
20 
21 
22 print(A.__mro__)  # C3算法:A->B->D->C->E (DFS:处理非菱形继承)
23 
24 
25 class W:
26     pass
27 
28 
29 class W1(W):
30     pass
31 
32 
33 class W2(W):
34     pass
35 
36 
37 class W4(W1, W2):
38     pass
39 
40 
41 print(W4.__mro__)  # C3算法:W4->W1->W2->W (BFS:处理菱形继承)

6.静态方法、类方法、对象方法以及参数

  • 静态方法:
    • 格式:在方法上面添加 @staticmethod
    • 参数:静态方法可以有参数也可以无参数
    • 应用场景:一般用于和类对象以及实例对象无关的代码。
    • 使用方式: 类名.类方法名(或者对象名.类方法名)。
  • 类方法:
    • 在方法上面添加@classmethod
    • 方法的参数为 cls 也可以是其他名称,但是一般默认为cls
    • cls 指向 类对象
    • 应用场景:当一个方法中只涉及到静态属性的时候可以使用类方法(类方法用来修改类属性)。
    • 使用可以是 对象名.类方法名。或者是 类名.类方法名
  • 实例方法:又叫对象方法,指类中定义的普通方法
 1 class Date:
 2     # 构造函数
 3     def __init__(self, year, month, day):
 4         self.year = year
 5         self.month = month
 6         self.day = day
 7 
 8     def tomorrow(self):
 9         self.day += 1
10 
11     @staticmethod
12     def parse_from_string(date_str):
13         year, month, day = tuple(date_str.split("-"))
14         return Date(int(year), int(month), int(day))
15 
16     @staticmethod
17     def valid_str(date_str):
18         year, month, day = tuple(date_str.split("-"))
19         if int(year) > 0 and (int(month) > 0 and int(month) <= 12) and (int(day) > 0 and int(day) <= 31):
20             return True
21         else:
22             return False
23 
24     @classmethod
25     def from_string(cls, date_str):
26         year, month, day = tuple(date_str.split("-"))
27         return cls(int(year), int(month), int(day))
28 
29     def __str__(self):
30         return "{year}/{month}/{day}".format(year=self.year, month=self.month, day=self.day)
31 
32 
33 if __name__ == "__main__":
34     new_day = Date(2018, 12, 31)
35     new_day.tomorrow()
36     print(new_day)
37 
38     # 2018-12-31
39     date_str = "2018-12-31"
40     year, month, day = tuple(date_str.split("-"))
41     new_day = Date(int(year), int(month), int(day))
42     print(new_day)
43 
44     # 用staticmethod完成初始化
45     new_day = Date.parse_from_string(date_str)
46     print(new_day)
47 
48     # 用classmethod完成初始化
49     new_day = Date.from_string(date_str)
50     print(new_day)
51 
52     print(Date.valid_str("2018-12-32"))

7.数据封装和私有属性

  • 私有属性:以双下划线开头__xxx
  • 私有属性也是可以访问的:_classname__attrname即可访问
 1 class User:
 2     def __init__(self, name):
 3         self.__name = name  # __birthday为私有属性
 4 
 5     @staticmethod
 6     def get_age():
 7         # 返回年龄
 8         return 25
 9 
10 
11 if __name__ == "__main__":
12     user = User("wzh")
13     print(user._User__name)     # wzh
14     print(user.get_age())       # 25

8.python对象的自省机制

  • 概念:自省是通过一定机制查询到对象的内部结构
  • 使用:
    • __dict__:显示部分属性和值,不能显示对象的父类属性,但是可以添加属性和显示文档内容
    • dir():dir比__dict__更强大,获得所有属性但是没有值
 1 class Person:
 2     """
 3  4     """
 5     name = "user"
 6 
 7 
 8 class Student(Person):
 9     def __init__(self, school_name):
10         self.school_name = school_name
11 
12 
13 if __name__ == "__main__":
14     user = Student("慕课网")
15 
16     # 通过__dict__查询属性
17     print(user.__dict__)    # {'school_name': '慕课网'}不能显示父类属性
18     user.__dict__["school_addr"] = "北京市"    # 添加属性
19     print(user.school_addr)  # 北京市
20     print(Person.__dict__)   # 可以显示文档内容
21     print(user.name)
22     a = [1, 2]
23     print(dir(a))

9.super函数

  • 目的:主要是把父类继承来的属性赋值
  • super执行的顺序:使用C3算法调用
 1 class A:
 2     def __init__(self):
 3         print("A")
 4 
 5 
 6 class B(A):
 7     def __init__(self):
 8         print("B")
 9         super().__init__()
10 
11 
12 class C(A):
13     def __init__(self):
14         print("C")
15         super().__init__()
16 
17 
18 class D(B, C):
19     def __init__(self):
20         print("D")
21         super().__init__()
22 
23 
24 if __name__ == "__main__":
25     print(D.__mro__)  # C3算法:D->B->C->A
26     d = D()     # D B C A

10.django rest framework中对多继承使用的经验

使用mixin模式:

  • Mixin类功能单一
  • 不和基类关联,可以和任意基类组合,基类可以不和mixin关联就能初始化成功
  • 在mixin中不要使用super这种用法
  • 使用__bases__将需要继承的类组合在一起
 1 def mixin(pyClass, pyMixinClass, key=0):
 2     if key:
 3         pyClass.__bases__ = (pyMixinClass,) + pyClass.__bases__
 4     elif pyMixinClass not in pyClass.__bases__:
 5         pyClass.__bases__ += (pyMixinClass,)
 6     else:
 7         pass
 8 
 9 
10 class test1:
11     def test(self):
12         print('In the test1 class!')
13 
14 
15 class testMixin:
16     def test(self):
17         print('In the testMixin class!')
18 
19 
20 class test2(test1, testMixin):
21     def test(self):
22         print('In the test2 class!')
23 
24 
25 class test0(test1):
26     pass
27 
28 
29 if __name__ == '__main__':
30     print(test0.__mro__)  # 继承了test1,object
31     test_0 = test0()
32     test_0.test()  # 调用test1的方法
33     mixin(test0, testMixin, 1)  # 优先继承testMixin类
34     test__0 = test0()
35     test__0.test()  # 由于优先继承了testMixin类,所以调用testMixin类的方法
36     print(test0.__mro__)
37 
38     print(test2.__mro__)
39     mixin(test2, testMixin)     # test2中已经继承了testMixin
40     print(test2.__mro__)
1 (<class '__main__.test0'>, <class '__main__.test1'>, <class 'object'>)
2 In the test1 class!
3 In the testMixin class!
4 (<class '__main__.test0'>, <class '__main__.testMixin'>, <class '__main__.test1'>, <class 'object'>)
5 (<class '__main__.test2'>, <class '__main__.test1'>, <class '__main__.testMixin'>, <class 'object'>)
6 (<class '__main__.test2'>, <class '__main__.test1'>, <class '__main__.testMixin'>, <class 'object'>)

11.python中的with语句

  • 普通的try...finally语句的调用流程:
    • 如果无异常:try->else->finally
      • finally中有return,则调用finally中的return
      • finally中无return
        • try中有return,则调用try中return
        • try中无return,则调用else中的return
    • 如果有异常:try->except->finally
      • finally中有return,则调用finally中的return
      • finally中无return,则调用except中的return
 1 # try except finally
 2 def exe_try():
 3     try:
 4         print("code started")
 5         # raise KeyError
 6         return 1
 7     except KeyError as e:
 8         print("key error")
 9         return 2
10     else:
11         print("other error")
12         return 3
13     finally:
14         print("finally")
15         return 4
16 
17 
18 if __name__ == "__main__":
19     result = exe_try()   
20     print(result)  # 4
  • 上下文管理器协议:with
    • 两个魔法函数:__enter__、__exit__
      • __enter__:进入时执行,用于获取资源
      • __exit__:结束时执行,用于释放资源
 1 # 上下文管理器协议
 2 class Sample:
 3     def __enter__(self):
 4         print("enter")
 5         # 获取资源
 6         return self
 7 
 8     def __exit__(self, exc_type, exc_val, exc_tb):
 9         # 释放资源
10         print("exit")
11 
12     @staticmethod
13     def do_something():
14         print("doing something")
15 
16 
17 with Sample() as sample:
18     sample.do_something()   # enter, doing something, exit
  • contextlib简化上下文管理器
    • 将__enter__、__exit__以及中间处理函数都整合到一个函数中
    • yield:中间处理函数
    • 使用装饰器:@contextlib.contextmanager
 1 import contextlib
 2 
 3 
 4 @contextlib.contextmanager
 5 def file_open(file_name):
 6     print("file open")
 7     yield {}
 8     print("file end")
 9 
10 
11 with file_open("bobby.txt") as f_opened:
12     print("file processing")  # file open, file processing, file end

 

posted @ 2019-12-20 21:28  All_just_for_fun  阅读(178)  评论(0编辑  收藏  举报