(一)多态
(1)什么是多态
-
多态指的是一类事物有多种形态
-
比如动物---猪狗牛羊
(2)示例
- 比如动物有多种形态:猫、狗、猪
import abc
# 同一类事物:动物
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def talk(self):
pass
# 动物的形态之一:人
class People(Animal):
def talk(self):
print('你真帅')
# 动物的形态之二:狗
class Dog(Animal):
def talk(self):
print('汪汪汪')
# 动物的形态之三:猪
class Pig(Animal):
def talk(self):
print('哼唧哼唧')
- 文件有多种形态:文本文件,可执行文件
import abc
# 同一类事物:文件
class File(metaclass=abc.ABCMeta):
@abc.abstractmethod
def click(self):
pass
# 文件的形态之一:文本文件
class Text(File):
def click(self):
print('open file')
# 文件的形态之二:可执行文件
class ExeFile(File):
def click(self):
print('execute file')
(二)多态性
(1)什么是多态动态绑定(多态性)
- 多态动态绑定是在继承的背景下使用的,有时也称为多态性
- 多态性是指在不考虑实例类型的情况下使用实例
- 在面向对象方法中一般是这样表述多态性:
- 向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func)
- 不同的对象在接收时会产生不同的行为(即方法)。
- 也就是说,每个对象可以用自己的方式去响应共同的消息。
- 所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
- 比如:老师.下课铃响了(),学生.下课铃响了()
- 老师执行的是下班操作
- 学生执行的是放学操作
- 虽然二者消息一样,但是执行的效果不同
(2)多态性的分类
- 多态性分为静态多态性和动态多态性
(1)静态多态性
- 如任何类型都可以用运算符 + 进行运算
(2)动态多态性
import abc
# 同一类事物:动物
class Animal(metaclass=abc.ABCMeta):
@abc.abstractmethod
def talk(self):
pass
# 动物形态之一:猫
class Cat(Animal):
def talk(self):
print(f"喵喵叫")
# 动物形态之二:狗
class Dog(Animal):
def talk(self):
print(f"汪汪叫")
# 动物形态之三:猪
class Pig(Animal):
def talk(self):
print(f"哼哼哼")
cat=Cat()
dog=Dog()
pig=Pig()
# cat、dog、pig都是动物,只要是动物就肯定有talk的方法
# 不考虑三者具体是什么类型,可以直接使用
cat.talk()# 喵喵叫
dog.talk()# 汪汪叫
pig.talk()# 哼哼哼
# 更进一步可以定义一个接口来使用
def func(obj):
obj.talk()
func(cat)#喵喵叫
func(dog)#汪汪叫
func(pig)#哼哼哼
(3)为什么要用多态性(多态性的好处)
- 增加了程序的灵活性
- 以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(obj)
- 增加了程序额可扩展性
- 通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(obj)去调用
(三)鸭子类型duck_typing
(1)什么是鸭子类型duck_typing
- 鸭子类型是一种编程风格,决定一个对象是否有正确的接口
- 关注点在于它的方法或属性
- 而不是它的类型(
如果它看起来像鸭子,像鸭子一样嘎嘎叫,那么它一定是鸭子。
)。
- 通过强调接口而不是特定类型,设计良好的代码通过多态提高了灵活性。
- 鸭子类型无需使用
type()
或isinstance()
进行检查(注意,鸭子类型可以用抽象基类来补充) - 相反,它通常使用
hasattr()
来检查,或是 EAFP 编程。
- 鸭子类型无需使用
- 但其实我们完全可以不依赖于继承,只需要制造出外观和行为相同对象,同样可以实现不考虑对象类型而使用对象,这正是Python崇尚的“鸭子类型”(duck typing):
- “如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子”。
- 比起继承的方式,鸭子类型在某种程度上实现了程序的松耦合度
(2)鸭子类型
# 鸭子类型是一种编程风格,决定一个对象是否有正确的接口
# 如果它看起来像鸭子,像鸭子一样嘎嘎叫,那么它一定是鸭子。
# 二者都像鸭子,因而就可以当鸭子一样去用
class NormalDuck():
def eat(self):
print(f"正常鸭子可以吃饭")
def walk(self):
print(f"正常鸭子可以走路")
class RockDuck():
def eat(self):
print(f"肉鸭子可以吃饭")
def walk(self):
print(f"肉鸭子可以走路")
class Chicken()
def eat(self):
print(f"鸡可以吃饭")
def walk(self):
print(f"鸡可以走路")
(四)反射
(1)什么是反射
-
通过字符串的形式操作对象的属性
- 反射是一种程序可以访问、检测和修改其本身状态或行为的能力。
- 在 Python 中,反射主要指通过字符串的形式操作对象的属性。
(2)Python中的反射
-
通过字符串的的形式操作对象相关的属性。
-
python中一切皆是对象(都可以使用反射)
(五)反射的方法
(1)反射方法介绍
- getattr(object, name[, default])
- 获取对象的属性值,如果属性不存在,可提供默认值。
- hasattr(object, name)
- 判断对象是否具有指定属性
- setattr(object, name, value)
- 设置对象的属性值
- delattr(object, name)
- 删除对象的属性
(2)引入
class Student():
def __init__(self,name,age):
self.name=name
self.age=age
def run(self):
print(f"{self.name}正在跑步")
# 实例化类得到对象
s=Student(name='syh',age=23)
# 直接操作对象得到属性
print(s.name)#syh
# 查看对象的属性
print(s.__dict__)
#{'name': 'syh', 'age': 23}
# 根据字典取值:拿到对应的值
print(s.__dict__['name'])#syh
# 查看对象的方法
print(s.__dir__())
# ['name', 'age', '__module__', '__init__', 'run', '__dict__', '__weakref__', '__doc__', '__new__', '__repr__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__reduce_ex__', '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
# 查看对象中的所有方法
print(dir(s))
#['__class__', '__delattr__', '
(3)getattr方法:获取对象的属性值
- 语法 : getattr(object, name[, default])
- 获取对象的属性值,如果对象不存在时,可以知道默认值
class Student():
def __init__(self,name,age):
self.name=name
self.age=age
def run(self):
print(f"{self.name}正在跑步")
s1=Student(name='syh',age=23)
# getattr方法:如果存在这个方法或属性,就返回属性值或者方法的内存地址,如果不存在就会报错
res_name=getattr(s1,'name')
print(res_name)#syh
res_age=getattr(s1,'age')
print(res_age)#23
# res_sex=getattr(s1,'sex')
# Traceback (most recent call last):
# File "D:\old boy\python\python28基础\day31\反射.py", line 38, in <module>
# res_sex=getattr(s1,'sex')
# AttributeError: 'Student' object has no attribute 'sex'
# getattr方法:获取的对象不存在时,可以知道不存在的时候返回的默认值
res_sex=getattr(s1,'sex','female')
print(res_sex)#female
(4)hasattr方法:判断对象是否具有指定的属性
- 语法:hasattr(object, name)
- 判断对象是否具有指定属性
# hasattr判断对象是否存在某属性或者方法
class Student():
def __init__(self,name,age):
self.name=name
self.age=age
def run(self):
print(f"{self.name}正在跑步")
s1=Student(name='syh',age=23)
print(hasattr(s1,'name'))#True
print(hasattr(s1,'sex'))#False
print(hasattr(s1,'run'))#True
(5)setattr方法:设置对象的属性值
- setattr(object, name, value)
- 设置对象的属性值
# setattr()方法:设置对象的属性值
class Student():
def __init__(self,name,age):
self.name=name
self.age=age
def run(self):
print(f"{self.name}正在跑步")
s1=Student(name='syh',age=23)
# 先判断s1对象是否具有该属性
print(hasattr(s1,'sex'))#False
# 如果不存在,setattr添加
setattr(s1,'sex','female')
# 如果存在,就获取属性值
print(hasattr(s1,'sex'))#True
(6)delattr方法:删除对象的属性
- delattr(object, name)
- 删除对象的属性
class Student():
def __init__(self,name,age):
self.name=name
self.age=age
def run(self):
print(f"{self.name}正在跑步")
s1=Student(name='syh',age=23)
# 先判断对象是否具有该属性
print(hasattr(s1,'name'))#True
# 如果存在就直接delattr删除该属性
delattr(s1,'name')
print(hasattr(s1,'name'))#False
(拓展)
(1)类也是对象
- 在Python中一切皆对象,所以我们也可以将类作为反射方法的第一个参数,反射其属性
class Student():
def __init__(self,name,age):
self.name=name
self.age=age
def run(self):
print(f"{self.name}正在跑步")
# 判断类是否具有该属性
res_name=hasattr(Student,'name')
print(res_name)# False
res_age=hasattr(Student,'age')
print(res_age)# False
res_run=hasattr(Student,'run')
print(res_run)# True
# 获取类中的属性值
print(getattr(Student,'run'))
# <function Student.run at 0x0000017219C62950>
# 设置类的属性
setattr(Student,'name','su')
print(hasattr(Student,'name'))#True
# 删除类中的属性
delattr(Student,'name')
print(hasattr(Student,'name'))#False
(2)反射当前模块成员
# 当前模块
#<module '__main__' from 'D:\\old boy\\python\\python28基础\\day31\\反射.py'>
thismodule=sys.modules[__name__]
import sys
thismodule=sys.modules[__name__]
#<module '__main__' from 'D:\\old boy\\python\\python28基础\\day31\\反射.py'>
def s1():
pass
def s2():
pass
res_s1=hasattr(thismodule,'s1')
print(res_s1)#True
print(getattr(thismodule,'s1'))
#<function s1 at 0x00000207BBA52290>
(7)反射的好处
# 反射的好处
# 反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,意味着可以在程序运行过程中动态地绑定接口的实现。
# 这种灵活性使得程序更容易扩展和维护
(1)实现可插拔机制
- 反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,意味着可以在程序运行过程中动态地绑定接口的实现。
- 这种灵活性使得程序更容易扩展和维护。
class PluginInterface:
def execute(self):
pass
class PluginA(PluginInterface):
def execute(self):
print("插件A被启动")
class PluginB(PluginInterface):
def execute(self):
print("插件B被启动")
def run_plugin(plugin):
plugin.execute()
# 使用反射调用插件
plugin_name = input("请输入插件名字(PluginA or PluginB) :>>>> ")
# 从全局名称空间中获取到 插件名字对应的类
plugin_class = globals().get(plugin_name)
# 判断一下当前类是否存在 并且 判断当前类是否 有 PluginInterface 接口
if plugin_class and issubclass(plugin_class, PluginInterface):
# 如果都成立会触发相应的方法
run_plugin(plugin_class())
else:
# 不存在则抛出异常
print("Invalid plugin name")
(2)动态导入模块(基于反射当前模块成员)
- 动态导入模块是指在程序运行时根据字符串的形式导入模块。
- 通过反射,可以动态导入模块的成员,实现更灵活的代码组织和管理。
import importlib
module_name = input("请输入模块名 :>>>> ")
method_name = input("请输入方法名 :>>>> ")
try:
# 动态导入模块
module = importlib.import_module(module_name)
# 反射是否存在当前方法
method = getattr(module, method_name)
# 如果存在则执行当前方法
method()
except ImportError:
print("Module not found")
except AttributeError:
print("Method not found")
标签:__,name,self,多态,print,age,def
From: https://www.cnblogs.com/suyihang/p/17947914