多态,抽象类,鸭子类型,classmethod和staticmethod,isinstance与issubclass和反射
多态
多态指的是同一种类型的事物,不同的形态
多态的目的:
多态也称之为多态性,目的是为了在不知道对象具体类型的情况下,统一对象调用方法的规范(例如名字)
多态的表现形式之一就是继承:
先抽象,再继承
父类:定制一套统一的规范 如方法名统一
子类:遵循父类的统一的规范 如子类遵循父类方法名的统一
ps:在python中不会强制限制 子类必须要遵循 父类的规范,所以出现了抽象类
class Father:
def func1(self):
pass
def speak(self);
pass
class Sub1(Father):
def func1(self):
pass
def speak(self):
pass
class Sub2(Father):
def func1(self):
pass
def speak(self):
pass
抽象类
什么是抽象类:
在python内置的abc模块中,有一个抽象类
抽象类的作用:
让子类必须遵守父类的编写规范
如何实现抽象类:
-父类需要继承abc模块中,metaclass = adb.ABCMeta
-在父类的方法中,需要装饰上 abc.abstractmethod
注意:在python中不推荐使用抽象类
注意: 子类必须按照父类的方法编写规范,缺一不可。父类中有几个抽象方法,子类就必须要定义几个
import abc
错误示范
# 父类
class Father(metaclass=abc.ABCMeta):
# 方法吃
@abc.abstractmethod
def eat(self):
pass
# 方法叫
@abc.abstractmethod
def speak(self):
pass
class Sub(Father):
def eat(self):
pass
def drink(self):
print(1)
sub_obj = Sub()
sub_obj.eat()
执行就会报错
父类中有几个抽象方法,子类就必须要定义几个
正确示范
# 父类
class Father(metaclass=abc.ABCMeta):
# 方法吃
@abc.abstractmethod
def eat(self):
pass
# 方法叫
@abc.abstractmethod
def speak(self):
pass
class Sub(Father):
def eat(self):
pass
def speak(self):
print(1)
def drink(self):
pass
鸭子类型
什么是鸭子类型:
不同的对象,只要长的像鸭子,动作行为像鸭子,那它就是鸭子
鸭子类型是多态的一种表现形式
为什么要有鸭子类型:
不同的对象,先抽象出相同的类型的方法,给他们定制一套统一的规范
所有的类,在定义时都按照统一的规范进行编写
多态的三种表现形式:
继承父类:
耦合度高,程序的可扩展性低
继承抽象类:
耦合度极高,程序的可扩展性极低
鸭子类型:
耦合度低,程序的可扩展性高
注意:在python中强列推荐使用鸭子类型
classmethod与staticmethd
classmethod与staticmethod都是python解释器内置的装饰器
classmethod:
是一个装饰器,给在类内部定义方法中修饰,将类内部的方法变为“类的绑定方法”
staticmethod:
静态方法
是一个装饰器,给在类内部定义方法中修饰,将类内部的方法变为非绑定方法
回顾:
对象的绑定方法:
由对象来调用,由谁来调用,会将谁作为第一个参数传入。
类的绑定方法:
由类来调用,由谁来调用,会将谁当作第一个参数传入
非绑定方法:
可以由对象或类来调用,谁来调用都是一个普通方法(普通函数),方法需要传入几个参数,就得传入几个
注意:__ class __: 是用来查看当前对象的类
import uuid 用来产生随机字符串的模块,由时间戳以及某种算法结合而成,会产生一串世界上独一无二的字符串
print(uuid.uuid4())
classmethod_Demo:
class DB:
__data = 'nothing can not be done!'
def __init__(self, user, pwd, role):
self.user = user
self.pwd = pwd
self.role = role
# cls指的是类
@classmethod
def check_db(cls, user, pwd, role):
obj = cls(user, pwd, role)
if obj.user == 'tank' and obj.pwd == '123' and obj.role =='admin':
print('通过检验!')
print(obj.__data)
DB.check_db('tank', '123', 'admin')
user_info = {
'user': None
}
class User:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
self.__uid = uuid.uuid4()
def register(self, user, pwd):
self.user = user
self.pwd = pwd
with open('user.txt', 'w', encoding='utf-8') as f:
f.write(
f'{self.name},{self.age},{self.sex},{self.user},{self.pwd}'
)
def login(self, user, pwd):
if self.user == user and self.pwd == pwd:
print('通过登录!')
user_info['user'] = user
else:
print('用户名或密码错误!')
user_obj = User('tank', 17, 'male')
user_obj.register('tank_jam', '123')
user_obj.login('tank_jam', '123')
通过登录!
isinstance与issubclass是python的内置模块
-isinstance:判断一个对象是否是另一个类的实例
-issubclass:判断一个类是否是类一个类的子类
如果是:True
如果不是:False
# isinstance:
class Foo:
pass
class Boo:
pass
foo_obj = Foo()
boo_obj = Boo()
print(isinstance(foo_obj, Foo)) # True
print(isinstance(boo_obj, Foo)) # False
# issubclass
class Father:
pass
class Sub(Father):
pass
class Foo:
pass
print(issubclass(Sub, Father)) # True
print(issubclass(Foo, Father)) # False
反射:
反射指的是通过“字符串”对对象的属性进行操作
-hasattr: 通过“字符串”判断对象的属性或方法是否存在 hasattr(self, str)
-getattr: 通过“字符串”获取对象的属性或方法 getattr(self, str, 默认值)
-setattr:通过“字符串”设置对象的属性或方法 seet(self, str, 属性值)
-delattr:通过“字符串”删除对象的属性或方法 delattr(self, str)
注意:反射的四个方法都是python内置的
class Foo:
def __init__(self, x, y):
self.x = x
self.y = y
foo_obj = Foo(10, 20)
print(hasattr(foo_obj, 'x'))
print(hasattr(foo_obj, 'z'))
print('=========================')
print(getattr(foo_obj, 'x'))
print(getattr(foo_obj, 'z'))
结果:
True
False
=========================
10
Traceback (most recent call last):
File "F:/python_work/python_oldboyedu_learn/day23/反射.py", line 14, in <module>
print(getattr(foo_obj, 'z'))
AttributeError: 'Foo' object has no attribute 'z'
setattr(foo_obj, 'z', 100)
print(hasattr(foo_obj, 'z'))
print('===================')
delattr(foo_obj, 'z')
print(hasattr(foo_obj, 'z'))
结果:
True
===================
False
反射应用:
class FileControl:
def run(self):
while True:
# 让用户输入上传或下载命令
user_input = input('请输入 上传 upload 或 下载 download:').strip()
# 通过用户输入的字符串判断方法是否存在,然后调用相应的方法
if hasattr(self, user_input):
func = getattr(self, user_input)
func()
break
else:
print('输入有误!')
def upload(self):
print('文件正在上传。。。')
def download(self):
print('文件正在下载中。。。')
file_control_obj = FileControl()
file_control_obj.run()
结果:
请输入 上传 upload 或 下载 download:as
输入有误!
请输入 上传 upload 或 下载 download:upload
文件正在上传。。。