面向对象—多态,反射

一、多态

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()


原文地址:https://www.cnblogs.com/xy-han/p/11983214.html