多态和属性自省(六)

一、面向对象三大特征:封装,继承,多态

多态:指的是一类事物有多种形态,一个抽象类有多个子类(因而多态的概念依赖于继承),不同子类的对象调用相同的方法,产生不同的执行结果,多态可以提高代码的灵活度

继承:在python中,一个类可以继承一个类,也可以继承多个类,被继承的类叫父类(或者叫基类,base class),继承的类叫子类

封装:将数据和方法放在一个类中就构成了封装

class Animal(object):
    def func(self):
        print('动物类的func方法')

class Cat(Animal):
    '''猫类'''
    def func(self):
        print('这是猫类特性相关方法')

class Dog(Animal):
    '''狗类'''
    def func(self):
        print('这是狗类相关方法')


def func(ani_obj):
    ani_obj.func()

if __name__ == '__main__':
    a1 = Animal()
    c1 = Cat()
    d1 = Dog()

    print(isinstance(a1, Animal))
    print(isinstance(c1, Animal))
    print(isinstance(d1, Animal))
    func(a1)
    func(c1)
    func(d1)

注意:在python中的参数没有类型限制,所以多态在python中的提现不是很严谨,多态的概念是应用在在Java,c#这一类强类型语言中,而python崇尚鸭子类型。

二、鸭子类型

概念:它并不要求严格的继承体系,关注的不是对象类型本身,而是它如何使用的,一个对象只要‘看起来像鸭子,走路起来像鸭子’,那它就可以被看作是鸭子。

鸭子类型提现:

静态语言:对于静态语言(java,c#)来讲,上面传入的对象必须是base类型或它的子类,否则将无法调用func()方法。

动态语言:对于动态语言python来讲,上面传入的不一定是base类型,也可以是其他类型,只要内部实现一个func()方法就行,这就是鸭子类型的提现。

class Animal(object):
    def func(self):
        print('动物类的func方法')

class Cat(Animal):
    '''猫类'''
    def func(self):
        print('这是猫类特性相关方法')

class Dog(Animal):
    '''狗类'''
    def func(self):
        print('这是狗类相关方法')

class Hero(object):
    def func(self):
        print('这是hero相关方法')

def func(ani_obj):
    ani_obj.func()

if __name__ == '__main__':
    a1 = Animal()
    c1 = Cat()
    d1 = Dog()
    h1 = Hero()

    print(isinstance(a1, Animal))
    print(isinstance(c1, Animal))
    print(isinstance(d1, Animal))
    print(isinstance(h1, Animal))
    func(a1)
    func(c1)
    func(d1)
    func(h1)

Hero不是Animal类型,但是可以调用func()方法,就是鸭子类型。

多态的意义:开放封闭原则

1、对于一个变量,我们只需知道它是base类型,无需确切地知道它的子类型,就可以放心的调用func()方法(调用方法只管地套用,不管细节)

2、当需要新增功能,只需新增一个base的子类实现func()方法,就可以再原来的基础上进行功能扩展,这就是注明的‘开放封闭’原则

3、对扩展开放:允许新增base子类

4、对修改封闭:不需要修改依赖base类型的func()等

三、数据和自省

私有属性:以单下划线或者双下划线开头的被称之为私有属性

私有属性定义:

单下划线开头:_attr

双下划线开头:__attr

class MyClass(object):
    attr = 100 #公有属性
    _attr1 = 1000 #私有属性,在外部可以直接访问
    __attr1 = 10000 #私有属性,在外部不可以直接访问,被改名了,所以在外部访问不了,但是_MyClas__attr1

t = MyClass()
#查看该类所有的属性和方法
print(t.__dict__)

python私有属性并没有真正私有化,但可以用下划线得到伪私有,有一项大多数python代码都遵循的习惯:带有下划线,前缀的名称应视为非公开的API的一部分(无论是函数,方法还是数据成员),它被视为实现细节,如有更改恕不通知。

__dict__

类调用__dict__属性,返类属性和方法字典

实例调用__dict__属性,返回实例相关的属性和方法字典

class MyClass(object):
    attr = 100 #公有属性
    _attr1 = 1000 #私有属性,在外部可以直接访问
    __attr1 = 10000 #私有属性,在外部不可以直接访问,被改名了,所以在外部访问不了,但是_MyClas__attr1
print(MyClass._attr1)
print(MyClass._MyClass__attr1)
t = MyClass()
#查看该类所有的属性和方法
print(t.__dict__)#实例相关属性和方法
print(MyClass.__dict__)#类相关属性和方法字典

 __slots__:通过定义slots属性来限制实例对象属性,只能绑定slots指定的属性。不能添加slots之外的属性

class Hero(object):
    __slots__ = []
    pass

h = Hero()
print(h.__dict__)

执行结果:报错,此时的__dict__没有创建,被slots覆盖了

自定义属性访问机制:

内置函数:

setattr:设置属性

getattr:获取属性值

delattr:删除属性值

class Hero(object):
   def __init__(self, name):
       self.name = name
h = Hero('sinder')
h.gender = 'bouns'
setattr(h, 'age', 18)
print(getattr(h, 'age'))

del h.gender
delattr(h, 'gender')

print(h.__dict__)

__setattr__:

 

lass Hero(object):
    def __init__(self, name):
       self.name = name

    def __setattr__(self, key, value):
        '''给对象设置属性时会调用此方法'''
        print('正在设置属性key:{},value:{}'.format(key, value))
        object.__setattr__(self, key, value)  # 重写__setattr__,一定要去调用父类的__setattr__方法
h = Hero('sinder')
setattr(h, 'age', 18)

执行结果:增加属性

__delattr__:

class Hero(object):
    def __init__(self, name):
       self.name = name
    def __delattr__(self, item):
        print(F'这个是item:{item}')
        object.__delattr__(self, item)
h = Hero('sinder')
setattr(h, 'age', 18)
print('删除前,实例属性:', h.__dict__)
delattr(h, 'age')
print('删除后,实例属性:', h.__dict__)
 

执行结果:

__

posted @ 2019-08-20 10:03  sinder2018  阅读(23)  评论(0)    收藏  举报