面向对象—多态,反射
一、多态
1.什么是多态?
多态指的是同一种类型的事物,不同的形态
2.多态的目的:
’‘多态’‘也称之为’‘多态性’‘,目的是为了在不知道对象具体类型的情况下,统一对象调用方法的规范(比如:名字)。
多态的表现’‘形式之一’‘就是继承:
-先抽象,再继承
父类:定制一套统一的规范(比如:方法名统一)
子类:遵循父类的统一的规范(比如:子类遵循父类方法名的统一)
注意:在python中不会限制 子类必须遵循父类的规范,所以出现了抽象类。
3.多态的三种表现形式:
-继承父类
-耦合度高,程序的可扩展性低
-继承抽象类
-耦合度极高,程序的可扩展性低
-鸭子类型
-耦合度低,程序的可扩展性高
缺点:造成了代码的冗余
注意:在python中,强烈推荐使用鸭子类型
#子类遵循父类统一的规范,比如方法名一致
#动物类
class Animal:
def eat(self):
pass
def speak(self):
pass
#猪类
class Pig(Animal):
def eat(self): #方法名与父类一致
print('bia 唧。。。。')
def speak(self): #方法名与父类一致
print('哼哼哼。。。')
#猫类
class Cat(Animal):
def eat(self):
print('咬ji 咬ji。。。')
def speak(self):
print('喵喵喵。。。')
#狗类
class Dog(Animal):
def eat(self):
print('舔ji 舔ji 。。。')
def speak(self):
print('汪汪汪。。。')
animal1 = Dog()
animal2 = Cat()
animal3 = Pig()
#让动物们叫起来
animal1.speak() #汪汪汪。。。
animal2.speak() #喵喵喵。。。
animal3.speak() #哼哼哼。。
多态使用
#猪类
class Pig:
def eat(self):
print('bia 唧。。。')
def speak(self):
print('哼哼哼。。。')
#猫类
class Cat:
def eat(self):
print('咬ji ,咬ji。。。')
def speak(self):
print('喵喵喵。。。')
#狗类
class Dog:
def eat(self):
print('舔ji 舔ji。。。')
def speak(self):
print('汪汪汪。。。')
dog = Dog()
pig = Pig()
cat = Cat()
# dog.speak()
# pig.speak()
# cat.speak()
#多态之炫技
def SPEAK(animal):
animal.speak()
SPEAK(dog)
SPEAK(pig)
SPEAK(cat)
str1 = 'tank is very handsome!!!' #字符串也是类
list1 = ['tank','is', 'very', 'handsome!!'] #列表也是类
print(str1.__len__())
print(list1.__len__())
#自定义统计长度函数
def LEN(obj):
return obj.__len__()
print(LEN(str1))
print(LEN(list1))
二、抽象类
1、什么是抽象类?
在python内置的abc模块中,有一个抽象类
2、抽象的作用:
让子类必须遵循父类的编写规范
3、如何实现抽象类
-父类需要继承abc模块中,metaclass = abc.ABCMeta
-在父类的方法中,需要装饰上abc.abcstractmethod
注意:在python中不推荐使用抽象类
注意:子类必须按照父类的方法编写规范,缺一不可。(只要父类中有几个抽象方法,子类就必须要定义几个)
import abc
#父类
class Animal(metaclass=abc.ABCMeta): #变成抽象类
@abc.abstractmethod
#方法吃
def eat(self): #添加装饰器,变成抽象类方法
pass
#方法叫
@abc.abstractmethod
def speak(self): #添加装饰器。变成抽象类方法
pass
#猪类
class Pig(Animal):
def run(self):
pass
def eat(self): #与父类方法名必须一致,
print('bia 唧。。。')
def speak(self): #与父类方法名一致
print('哼哼哼。。。')
print(Pig.__dict__) #打印Pig类名称空间
print(Animal.__dict__) #打印Animal父类的名称空间
pig_obj = Pig()
三、鸭子类型
1.什么是鸭子类型?
不同的对象,只要长的像鸭子,动作行为像鸭子,那它就是鸭子!
鸭子类型是多态的一种表现形式
2.为什么要有鸭子类型?
不同对象,先抽象出相同类型的方法,给他们定制一套统一的规范,
所有的类,在定义时都按照统一的规范进行定义类的方法
#猪类
class Pig:
def eat(self):
print('bia 唧。。。')
def speak(self):
print('哼哼哼。。。')
#猫类
class Cat:
def eat(self):
print('咬ji 咬ji。。。')
def speak(self):
print('喵喵喵。。。')
#狗类
class Dog:
def eat(self):
print('舔ji 舔ji。。。')
def speak(self):
print('汪汪汪。。。')
'''
这三个类的方法,就称为鸭子类型
'''
四、classmethod 和 staticmethod
classmethod 与staticmethod都是python解释器内置的装饰器。
classmethod:
是一个装饰器,给在类内部定义的方法装饰,将类内部的方法变为‘’类的绑定方法‘’。
staticmethod(也叫静态方法):
是一个装饰器,给在类内部定义的方法装饰,将类内部的方法变为‘’非绑定方法‘’。
-对象的绑定方法(在类内部定义一个方法即可):
-由对象来调用,由谁来调用,会将谁(对象)当做第一个参数传入该方法
-类的绑定方法(在类内部方法中,使用classmethod装饰器):
-由类来调用,由谁来调用,会将谁(类)当做第一个参数传入该方法
-非绑定方法(在类内部方法中,使用staticmethod装饰器):
-可以由对象或类来调用,谁来调用都是一个普通方法(普通函数),方法需要传入几个参数,就得传入几个
#classmethod_Demo:
class DB:
__data = 'tank is very hangsome'
def __init__(self, user, pwd, role):
self.user = user
self.pwd = pwd
self.role = role
@classmethod #将类内部的方法变为''类的绑定方法''
def init(cls,user, pwd, role): #cls--->指的是类
#在类方法内部调用产生一个实例---->对象
return cls(user, pwd, role)
#查看数据方法
@classmethod
def check_db(cls, user, pwd, role): #cls--->指的是类
#在类方法内部调用类产生一个实例----》对象
obj = cls(user, pwd, role)
#1.查看数据前,必须要通过校验
if obj.user=='tank' and obj.pwd == '123' and obj.role == 'admin':
print('校验通过。。。')
print(cls.__data)
return cls.__data
DB.check_db('tank','123','admin') #类调用 tank is very hangsome
db_obj = DB('tank','123','admin')
# db_obj.check_db('tank','123','admin')
# __class__:查看当前对象的类
print(db_obj.__class__) #<class '__main__.DB'>
#staticmethod_Demo:
import uuid #用于产生随机字符串的模块
'''
uuid模块由时间戳及某种算法组合而成,会产生一串世界上独一无二字符串。
print(uuid.uuid4())
'''
class Foo:
@staticmethod
def func(res):
print(res)
obj = Foo()
#对象调用非绑定方法
obj.func(123) #123
#类调用非绑定方法
Foo.func(1234) #1234
五、isinstance与issubclass
isinstance 与issubclass 是python的内置模块:
-isinstance:判断一个对象是否是一个类的实例
-如果是:返回True
-如果不是:返回False
issubclass:判断一个类是否是另一个类的子类
-如果是:返回True
-如果不是:返回False
#isinstance: 判断一个对象是否是另一个类的实例
class Foo:
pass
class Boo:
pass
foo_obj = Foo()
boo_obj = Boo()
#print(isinstance(对象, 类))
print(isinstance(foo_obj, Foo)) #True
print(isinstance(boo_obj, Foo)) #False
#issubclass #判断一个类是否是另一个类的子类
class Father:
pass
class Sub(Father):
pass
class Foo:
pass
#print(issubclsss(子类, 父类)
print(issubclass(Sub, Father)) #True
print(issubclass(Foo,Father)) #False
六、反射
反射指的是通过‘’字符串‘’对对象、类的属性或方法进行操作
-hasattr:通过‘’字符串‘’判断对象的属性或方法是否存在
存在返回Ture,否则返回False
例:hasattr(对象, ’对象的属性或方法名字符串‘)
-getattr:通过‘’字符串‘’获取对象的属性或方法
存在返回获取属性或方法,否则返回报错
例:getattr(对象,’对象属性或方法名字符串‘, ’默认值‘)
-setattr:通过‘’字符串‘’设置对象的属性或方法
setattr(对象,’对象的属性或方法名字符串‘,‘属性值 ’)
-delattr:通过‘’字符串‘’删除对象的属性或方法
delattr(对象,’对象的属性或方法名字符串‘ )
注意:反射的四个方法都是python内置的
class Foo:
def __init__(self,x, y):
self.x = x
self.y = y
def tell_all(self, username1):
self.usname1 = username1
if username1 == 'han':
print('from .....')
foo_obj = Foo(10, 20,)
print(foo_obj.tell_all('han')) #打印from。。。返回None
#hasattr: 通过'字符串'判断对象的属性或方法是否存在
#通过字符串x 判断对象中是否存在x属性
print(hasattr(foo_obj, 'x')) #True
print(hasattr(foo_obj, 'y'))#True
print(hasattr(foo_obj, 'z'))#False
#getattr: 通过'字符串'获取对象属性或方法
res = getattr(foo_obj, 'x')
print(res) #10
#若属性不存在,则返回默认值
res1 = getattr(foo_obj, 'z', '默认值') #这里的'默认值'是自定义的,类似于字典.get的用法
print(res1) #默认值
#setattr
setattr(foo_obj, 'z', 30) # 为foo_obj 设置一个属性z,值为30
print(hasattr(foo_obj, 'z')) #True
#delattr
delattr(foo_obj, 'x')
print(hasattr(foo_obj, 'x')) #False
print(getattr(foo_obj, 'username1', '默认值')) #默认值,只能获取方法,不能获取方法内参数
print(getattr(foo_obj, 'tell_all', '默认值')('han')) #打印from。。。返回None
print(hasattr(foo_obj, 'tell_all')) #True
setattr(foo_obj, 'd',14)
print(getattr(foo_obj, 'd')) #14
print(foo_obj.__dict__) #查看名称空间:{'y': 20, 'usname1': 'han', 'z': 30, 'd': 14}
反射应用:
class FileControl:
def run(self):
while True:
# 让用户输入上传或下载功能的命令:
user_input = input('请输入 上传(upload) 或 下载(download) 功能:').strip()
# 通过用户输入的字符串判断方法是否存在,然后调用相应的方法
if hasattr(self, user_input):
func = getattr(self, user_input)
func()
else:
print('输入有误!')
def upload(self):
print('文件正在上传...')
def download(self):
print('文件正在下载...')
file_control_obj = FileControl()
file_control_obj.run()