一:Python多继承的正确打开方式:mixins机制
Mixins核心:在多继承背景下,尽可能地提升多继承的可读性
ps:让多继承满足人的思维习惯 ==> 什么 是 什么
二:例子
class Vehicle: # 交通工具
def fly(self):
print("I am flying")
class CivilAircraft(Vehicle): # 民航飞机
pass
class Helicopter(Vehicle): # 直升飞机
pass
class Car(Vehicle): # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
pass
class Vehicle: # 交通工具
pass
class Flyable: # 新建一个类Flyable,只当做可飞行交通工具的父类
def fly(self):
print("I am flying")
class CivilAircraft(Vehicle, Flyable): # 民航飞机
pass
class Helicopter(Vehicle, Flyable): # 直升飞机
pass
class Car(Vehicle):
pass
Python语言可没有接口功能,但是它可以多重继承。那Python是不是就该用多重继承来实现呢?是,也不是。说是,因为从语法上看,的确是通过多重继承实现的。说不是,因为它的继承依然遵守”is-a”关系,从含义上看依然遵循单继承的原则。
class Vehicle: # 交通工具
pass
class FlyableMixin: # 加一个Mixin结尾,可以当做一个假父类混入区中
def fly(self):
print("I am flying")
class CivilAircraft(Vehicle, FlyableMixin): # 民航飞机
pass
class Helicopter(Vehicle, FlyableMixin): # 直升飞机
pass
class Car(Vehicle): # 汽车并不会飞,但按照上述继承关系,汽车也能飞了
pass
这里可以看到,CivilAircraft和Helicopter都继承了Vehicle,还有FlyableMixin,但是FlyableMixin,表示混入(mix-in),它告诉别人,这个类是作为功能添加到子类中,而不是作为父类,它的作用同Java中的接口。
使用Mixin类实现多重继承要非常小心
1.首先它必须表示某一种功能,而不是某个物品,如同Java中的Runnable,Callable等
2.其次它必须责任单一,如果有多个功能,那就写多个Mixin类
3.然后,它不依赖于子类的实现
4.最后,子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。
在子类派生的新方法super()
一:方式1
指名道姓调用某一个类下的函数 ==> 不依赖于继承关系
class OldboyPeople:
school = 'OldBoy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def f1(self):
print(f'{self.name} say hello')
class Student(OldboyPeople):
def choose_course(self):
print('学生%s 正在选课' % self.name)
class Teacher(OldboyPeople):
# 老师的空对象,'egon',18,'male',3000,10
def __init__(self, name, age, sex, salary, level):
# 方式1:# 指名道姓地跟父类OldboyPeople去要__init__
# OldboyPeople.__init__(self, name, age, sex)
self.salary = salary
self.level = level
def score(self):
print('老师 %s 正在给学生打分' % self.name)
print(Teacher.mro()) # [<class '__main__.Teacher'>, <class '__main__.OldboyPeople'>, <class 'object'>]
二:方式2
super()调用父类提供给自己的方法 ==> 严格依赖继承关系
class OldboyPeople:
school = 'OldBoy'
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def f1(self):
print(f'{self.name} say hello')
class Student(OldboyPeople):
def choose_course(self):
print('学生%s 正在选课' % self.name)
class Teacher(OldboyPeople):
# 老师的空对象,'egon',18,'male',3000,10
def __init__(self, name, age, sex, salary, level):
# 方式2:# 调用super()会得到一个特殊的对象,该对象会参照当前类的mro,去当前类的父类里找属性
super().__init__(name, age, sex) # 调用的是方法,自动传入对象
self.salary = salary
self.level = level
def score(self):
print('老师 %s 正在给学生打分' % self.name)
print(Teacher.mro()) # [<class '__main__.Teacher'>, <class '__main__.OldboyPeople'>, <class 'object'>]
class A:
def test(self):
super().test()
class B:
def test(self):
print('from B')
class C(A, B):
pass
print(A.mro()) # [<class '__main__.A'>, <class 'object'>]
print(B.mro()) # [<class '__main__.B'>, <class 'object'>]
print(C.mro()) # 在代码层面A并不是B的子类,但从MRO列表来看,属性查找时,就是按照顺序C->A->B->object,B就相当于A的“父类”
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,<class ‘object'>]
obj = C()
obj.test() # 属性查找的发起者是类C的对象obj,所以中途发生的属性查找都是参照C.mro()
# from B
class A:
def test(self):
print('from A')
super().test1()
class B:
def test1(self):
print('from B')
class C(A, B):
def test1(self):
print('from C')
print(C.mro()) # 在代码层面A并不是B的子类,但从MRO列表来看,属性查找时,就是按照顺序C->A->B->object,B就相当于A的“父类”
# [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,<class ‘object'>]
obj = C()
obj.test() # 属性查找的发起者是类C的对象obj,所以中途发生的属性查找都是参照C.mro()
三:使用须知
super()和之前的方法不能混用,只能用其中一种
多态
一:什么是多态
同一事物有多种形态
二:为何要有多态 ==> 多态会带来什么样的特性,多态性
多态性指的是:可以在不考虑对象的具体类型情况下 直接使用对象
class Animal:
def say(self):
print('动物基本的发声...', end='')
class People(Animal):
def say(self):
super().say()
print('卧槽')
class Dog(Animal):
def say(self):
super().say()
print('汪汪汪')
class Pig(Animal):
def say(self):
super().say()
print('吼吼吼')
obj1 = People()
obj2 = Dog()
obj3 = Pig()
# obj1.say() # 动物基本的发声...卧槽
# obj2.say() # 动物基本的发声...汪汪汪
# obj3.say() # 动物基本的发声...吼吼吼
# 定义统一的接口,接收传入的动物对象
def animal_say(animal):
animal.say()
animal_say(obj1)
animal_say(obj2)
animal_say(obj3)
Python中len的精妙之处
# len('hello')
# len([1, 2, 3])
# len({'name': 'xxq', 'age': 18})
# print('hello'.__len__())
# print([1, 2, 3].__len__())
# print({'name': 'xxq', 'age': 18}.__len__())
def my_len(val):
return val.__len__()
print(my_len('hello'))
print(my_len([1, 2, 3]))
print(my_len({'name': 'xxq', 'age': 18}))
三:鸭子类型
# Python推崇的是鸭子类型
class Cpu:
def read(self):
print('cpu read')
def write(self):
print('cpu write')
class Mem:
def read(self):
print('Mem read')
def write(self):
print('Mem write')
class Txt:
def read(self):
print('Txt read')
def write(self):
print('Txt write')
obj1 = Cpu()
obj2 = Mem()
obj3 = Txt()
obj1.read()
obj2.read()
obj3.read()
四:了解知识点
import abc
# 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化
class Animal(metaclass=abc.ABCMeta): # 统一所有子类的方法
@abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法
def say(self):
print('动物基本的发声...', end='')
class People(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准
pass
class Dog(Animal):
pass
class Pig(Animal):
pass
obj1 = People()
obj2 = Dog()
obj3 = Pig()
obj1.say() # 动物基本的发声...卧槽
obj2.say() # 动物基本的发声...汪汪汪
obj3.say() # 动物基本的发声...吼吼吼
# 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化
# TypeError: Can't instantiate abstract class People with abstract methods say
class Animal(metaclass=abc.ABCMeta): # 统一所有子类的方法
@abc.abstractmethod
def say(self):
print('动物基本的发声...', end='')
class People(Animal):
def say(self):
super().say()
print('卧槽')
class Dog(Animal):
def say(self):
super().say()
print('汪汪汪')
class Pig(Animal):
def say(self):
super().say()
print('吼吼吼')
obj1 = People()
obj2 = Dog()
obj3 = Pig()
obj1.say() # 动物基本的发声...卧槽
obj2.say() # 动物基本的发声...汪汪汪
obj3.say() # 动物基本的发声...吼吼吼
绑定
一:绑定方法:特殊之处在于 将调用者本身当做第一个参数 自动传入
1.绑定给对象的方法:调用者是 对象,自动传入的是 对象
class Mysql:
def __init__(self, ip, port):
self.ip = ip
self.port = port
def func(self):
print(f'{self.ip} {self.port}')
obj = Mysql('127.0.0.1', 3306)
obj.func() # 127.0.0.1 3306
2.绑定给类的方法:调用者是 类,自动传入的是 类
新的方法:
setting.py
IP = '127.0.0.1'
PORT = 3306
import settings
class Mysql:
def __init__(self, ip, port):
self.nid = self.create_id()
self.ip = ip
self.port = port
def func(self):
print(f'{self.ip} {self.port}')
@classmethod # 绑定给类的方法
def form_conf(cls):
print(cls)
return cls(settings.IP, settings.PORT)
@staticmethod # 将下述函数 装饰成一个静态方法
def create_id():
import uuid
return uuid.uuid4()
@classmethod
def f1(cls):
pass
def f2(self):
pass
obj2 = Mysql.form_conf() # <class '__main__.Mysql'>
print(obj2.__dict__) # {'nid': UUID('fb7015fb-8e6c-4c1e-9a24-241a7c3aff10'), 'ip': '127.0.0.1', 'port': 3306}
二:非绑定方法
没有绑定给任何人:调用者可以是类、对象,没有自动传参的效果
class Mysql:
def __init__(self, ip, port):
self.ip = ip
self.port = port
@staticmethod # 将下述函数 装饰成一个静态方法
def create_id():
import uuid
return uuid.uuid4()
obj1 = Mysql('1.1.1.1', 2208)
# print(Mysql.create_id) # <function Mysql.create_id at 0x037083D0>
# print(obj1.create_id) # <function Mysql.create_id at 0x037083D0>
Mysql.create_id()
obj1.create_id()
内置方法
# print(abs(-1)) # 返回绝对值 # 1
#
# print(all([1, 2, 3, ''])) # 返回可迭代对象,有一个为0,None,空就是假的 # False
# print(all([1, 2, 3, ])) # 返回可迭代对象 # True
#
# print(any([])) # False
#
# print(bin(111)) # 0b1101111
# print(oct(111)) # 0o157
# print(hex(111)) # 0x6f
#
# print(bool('')) # False
# def func():
# pass
# class Foo:
# pass
# print(callable(Foo)) # True
# print(chr(65)) # A
# print(ord('A')) # 65
# # ======= 掌握 =======
# class Foo:
# pass
# obj = Foo()
# obj.xxx = 111
# print(dir(Foo)) # 可以查看可以.出来哪些属性 #['__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__']
# print(dir(obj)) # 可以查看可以.出来哪些属性 #['__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__', 'xxx']
# print(divmod(1000,4)) #总数据量,每一页的数据量
# 返回值:总页数,剩余数据 # (250, 0)
# # ======= 掌握 =======
# for i, v in enumerate(['a', 'b', 'c']):
# print(i, v)
#
# # 0 a
# # 1 b
# # 2 c
# # ======= 掌握 =======
# res = eval('1+2') # eval就是执行字符串中的表达式
# print(res)
# # ======= 掌握 =======
# 不可变集合
# s = frozenset({1, 2, 3})
# print(s) # frozenset({1, 2, 3})
# hash(不可变类型)
# # ======= 掌握 =======
# isinstance判断一个对象是不是一个类的实例
# class Foo:
# pass
#
# obj = Foo()
# print(isinstance(obj, Foo)) # True
# print(isinstance([], list)) # True # 推荐
# print(type([]) is list) # True # 不推荐
# # 10 ** 2 % 3
# print(pow(10, 2, 3)) # 1
# # 了解
# print('aaa'.__repr__()) # 'aaa'
# # round 四舍五入
# print(round(1.545)) # 2
# print(round(1.445)) # 1
# # 切片
# s = slice(1, 4, 2) # 不常用
# l1 = [1, 2, 3, 4]
# l2 = [3, 2, 5, 9, 6, 7]
#
# print(l1[1:4:2]) # [2, 4]
# print(l2[1:4:2]) # [2, 9]
# print(l1[s]) # [2, 4]
# print(l2[s]) #[2, 4]
# # ======= 掌握 =======
# # zip拉链函数 一个对一个,没有对应的就报错
# v1 = 'hello'
# v2 = [111, 222, 333, 444, 555]
# res = zip(v1, v2)
# print(list(res)) # [('h', 111), ('e', 222), ('l', 333), ('l', 444), ('o', 555)]
# # ======= 掌握 =======
# __import__()
import time
# import 'time' # 报错
# 变量名 = __import__('time')
# x = __import__('time')
# x.sleep(3)
# # ======= 掌握 =======
# 下周:反射