day27 - 面向对象 组合、多态、内置方法、鸭子类型、反射
一:组合
继承:is - a
组合:has - a
把另外一个类的对象 赋值给当前对象的属性,表达的是什么 有 什么
的关系
class Teacher:
def __init__(self, name, age, gender, level):
self.name = name
self.age = age
self.gender = gender
self.level = level
def tell(self):
print(f'姓名:{self.name},年龄:{self.age},性别:{self.gender},等级:{self.level}')
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def tell(self):
print(f'姓名:{self.name},年龄:{self.age},性别:{self.gender}')
class Course:
def __init__(self, name, price, period):
self.name = name
self.price = price
self.period = period
def tell(self):
print(f'课程名:{self.name},价格:{self.price},周期:{self.period}')
teacher_obj1 = Teacher('egon', 78, 'male', 5)
student_obj1 = Student('xxq', 18, 'male')
python = Course("python全栈", 29999, "6months")
linux = Course("linux课程", 19999, "3months")
teacher_obj1.courses = [python, linux]
student_obj1.course = python
# tea,stu # 超级对象
# stu1.course.tell()
for course_obj in teacher_obj1.courses:
course_obj.tell()
# 课程名:python全栈,价格:29999,周期:6months
# 课程名:linux课程,价格:19999,周期:3months
继承 + 组合 组合技
# 组合:把另外一个类的对象赋值给当前对象的属性
# 组合表达的是一种有的关系
# class People(object):
class People:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Teacher(People):
def __init__(self, name, age, gender, level):
# super(Teacher, self).__init__(name, age, gender)
super().__init__(name, age, gender)
self.level = level
def tell(self):
print(f'姓名:{self.name},年龄:{self.age},性别:{self.gender},等级:{self.level}')
class Student(People):
def __init__(self, name, age, gender):
# super(Student, self).__init__(name, age, gender)
super().__init__(name, age, gender)
def tell(self):
print(f'姓名:{self.name},年龄:{self.age},性别:{self.gender}')
# class Course(People):
class Course:
def __init__(self, name, price, period):
# super(Course, self).__init__(name)
self.name = name
self.price = price
self.period = period
def tell(self):
print(f'课程名:{self.name},价格:{self.price},周期:{self.period}')
teacher_obj1 = Teacher('egon', 78, 'female', 10)
student_obj1 = Student('xxq', 18, 'male')
python = Course("python全栈", 29999, "6months")
linux = Course("linux课程", 19999, "3months")
teacher_obj1.courses = [python, linux]
student_obj1.course = python
# 这时候teacher_obj1和student_obj1就是超级对象
for course_obj in teacher_obj1.courses:
course_obj.tell()
student_obj1.tell()
teacher_obj1.tell()
# 课程名:python全栈,价格:29999,周期:6months
# 课程名:linux课程,价格:19999,周期:3months
# 姓名:xxq,年龄:18,性别:male
# 姓名:egon,年龄:78,性别:female,等级:10
二:多态
什么是多态:同一种事物有多重形态
多态性指的是:可以在不考虑对象的具体类型情况下 直接使用对象
class Animal:
def roar(self):
pass
class Pepple(Animal):
def roar(self):
print('嘤嘤嘤~')
class Dog(Animal):
def roar(self):
print('汪汪汪~')
class Cat(Animal):
def roar(self):
print('喵喵喵~')
people_obj = Pepple()
dog_obj1 = Dog()
cat_obj1 = Cat()
people_obj.roar()
# 嘤嘤嘤~
dog_obj1.roar()
# 汪汪汪~
cat_obj1.roar()
# 喵喵喵~
三:鸭子类型
在Python中,只要你长得像鸭子,并且也是嘎嘎叫的,那你就是一只鸭子
# 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()
四:面向对象 高级
内置方法 __len_
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}))
__str__
会在打印对象的时候触发,然后将返回值(必须是字符串类型)当做本次打印的结果输出
class People:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
print('运行了')
return 'hahahah'
obj = People('xxq', 18)
print(obj)
# 运行了
# hahahah
obj1 = int(10)
print(obj1)
# 10
print(obj.__str__())
# 运行了
# hahahah
print(obj) # <'辣白菜同学':18>
# 运行了
# hahahah
__del__
会在对象执行结束,系统要回收资源的时候触发
class People:
def __init__(self, name, age):
self.name = name
self.age = age
print('运行了__init__')
def __str__(self):
print('运行了__str__')
return 'hahahah'
obj = People('xxq', 18)
print(obj)
# 运行了__init__
# 运行了__str__
# hahahah
obj1 = int(10)
print(obj1)
# 10
print(obj.__str__())
# 运行了__str__
# hahahah
print(obj)
# 运行了__str__
# hahahah
五:一切皆对象
isinstance(obj,cls)
判断对象obj是否是类cls的对象
issunclass(sub,super)
判断sub类是否是super类的子类或者子子类
六:反射
1.什么是反射?
指的是在程序运行过程中可以“动态(不见棺材不落泪)”获取对象的信息(数据属性、函数属性)
# 静态:在定义阶段就确定类型
# 动态:在调用阶段才去确定类型
2.如何实现反射?
① 先通过多dir:查看某一个对象下 可以.出哪些属性来
dir(对象)
可以看出该对象可以.
出哪些属性
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__', 'age', 'name', 'say']
② 可以通过字符串反射到真正的属性上,得到属性值
print(obj.__dict__['name']) # xxq
print(obj.__dict__[dir(obj)[-2]]) # xxq
3.通过字符串来操作属性
3.1.hasattr()
print(hasattr(obj, 'name')) # True
print(hasattr(obj, 'x')) # False
3.2.getattr()
print(getattr(obj, 'name')) # xxq
print(getattr(obj, 'x')) # AttributeError: 'People' object has no attribute 'x'
3.3.setattr()
print(getattr(obj, 'name', 'EGON')) # 修改名字为EGON
print(obj.name) # EGON
3.4.delattr()
delattr(obj, 'name')
print(obj.__dict__) # {'age': 18}
获取对象和类
res1 = getattr(obj, 'say') # obj.say
res2 = getattr(People, 'say') # People.say
print(res1) # <bound method People.say of <__main__.People object at 0x0167B0B8>>
print(res2) # <function People.say at 0x016783D0>
查看是否有这个方法
obj = 10
if hasattr(obj, 'x'):
print(getattr(obj, 'x'))
else:
print('找不到') # 找不到
print(getattr(obj, 'x', None)) # None
print(getattr(People, 'say', None)) # <function People.say at 0x01AC83D0>
if hasattr(obj, 'x'):
setattr(obj, 'x', 1111111) # 10.x = 1111111
else:
print('找不到') # 找不到
基于反射可以十分灵活地操作对象的属性,比如将用户交互的结果反射到具体的功能执行
class Ftp:
def upload(self):
print('正在上传')
def download(self):
print('正在下载')
def interactive(self):
method = input('>>>: ').strip() # method = 'upload'
if hasattr(self, method):
getattr(self, method)()
else:
print('该指令不存在!')
obj = Ftp()
obj.interactive()
七:了解知识点(abc模块)
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() # 动物基本的发声...吼吼吼