面向对象的三大特征

  • 封装 :保证了数据的安全
  • 隐藏属性
  • property装饰器
  • 继承:保证了对象的可扩展性
  • 重写,super
  • 多重继承
  • 多态:保证了程序的灵活性


封装 :保证了数据的安全

封装是面向对象的三大特性之一
封装指的是隐藏对象中的一些不希望被访问的到的属性或者方法
如果隐藏一个对象的属性?
将对象的属性名,修改为一个外部不知道名字如何获取(修改的)对象的属性?
需要提供一个getter和setter方法使外部可以访问到该属性
getter获取对象中的指定属性(get_属性名)
setter获取对象中的指定属性(set_属性名)
使用封装确实增加了类的定义的复杂程度,但是也确保了数据的安全性
1.隐藏了属性名。使调用者无法随意的修改对象的属性
2.增了getter和setter方法,很好的控制属性是否是只读的
3.使用setter方法设置了属性,可以增加数据的验证,确保数据的值是否是正确的

// An highlighted block
class Dog:
    def __init__(self,name,age):
        self.hiden_name=name
        self.age=age
    def eat(self):
        print(self.hiden_name,'喜欢吃狗粮')
    def get_name(self)
        '''
        get_name获取对象name属性
        '''
        return self.hiden_name
    def set_name(self,name)
        '''
        get_name设置对象name属性
        '''
        self.hiden_name=name
pat=Dog('泰迪',10)
pat.eat()
pat.action()

隐藏属性

可以为对象的属性使用双下划线开头,__xxx
双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问
其实隐藏属性只不过是python自动为属性改了一个名字
实际上是将名字修改为了_类名_属性名 比如_name->_person_name

// An highlighted block
class Person:
 def __init__(self,name):
     self.__name=name
 def get_name(self) :
     return self.__name
p=Person('sim')
p.__name='住百家'#修改不了

property装饰器

// An highlighted block
class Person:
    def __init__(self,name):
        self._name=name
    # @property装饰器用来将一个get方法转换为对象的属性
    # 添加为property装饰器后,我们就可以像调用属性一样使用get方法了
    # 使用property装饰方法后,必须和属性名是一样的
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self,name):
        self._name=name
p=Person('猪八戒')
p.name='sun'
print(p.name)

继承:保证了对象的可扩展性

// An highlighted block
定义一个类Animal
class Animal:
    """docstring for Animal"""
    def run(self):
        print('动物会跑')

1.如何你让那个让一个类实现全部功能呢》
直接修改这个类,在这个类中添加我们需要的功能
修改起来麻烦,并且违反了OCP原则
2。直接创建一个新的类
创建一个新的类比较麻烦,并且需要大量的进行复制粘贴
3,直接从Animal中继承它的属性和方法
继承是面向三大特性之一
通过继承我们使一个类获取到其他类的属性和方法
在定义时,可以在类名后的括号中指定当前类的父类(超类,基类、super)
class Dog(Animal):
    pass
d=Dog()
d.run()
#所有的对象都是Object的实例
isinstance(Dog,object)
isinstance(d,Dog)#判断d是否是Dog的实例
如果在创建类时省略了父类,则默认父类为object
issubclass(Dog,Animal)#作用:一个类是否是另一个类的子类

重写,super

重写:如果在子类中有和父类同名的方法。则通过子类实例去调用方法是,会调用子类的方法而不是
父类的方法。这个特点我们称为叫做方法的重写(覆盖)

// An highlighted block
class Animal:
    def __init__(self,name):
        self._name=name
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self):
        self._name=name
    """docstring for Animal"""
    def run(self):
        print('动物会跑')
class Dog(Animal):
    def __init__(self,name,age):
        # 可以直接调用父类的_init_来初始化父类中定义的属性
        # super()可以用来获取当前调用的父类
        # 并且通过super()返回对象调用父类方法时,不需要传递self
        super().__init__(name)
        self._age=age
    def run(self):
        print('动物会跑')


d=Dog('旺财')
d.name='niu'

多重继承

// An highlighted block
class A(object):
    pass
class B(object):
    pass    
class C(A,B):
    pass
# 在python中支持多重继承,也就是我们可以为一个类同时指定多个父类
# 可以在类名()后边添加多个类,来实现多重继承
# 在开发中没有特殊情况,应该避免使用多重继承,因为多重继承会让我们的代码相对复杂
# 前边父类的方法会覆盖后边父类的方法
类名.__bases__这个属性可以用来获取当前类的所有的父类
print(A.__bases__)#返回值是一个元组

多态:保证了程序的灵活性

多态从字面上理解是多种形态
一个类可以以不同的形态呈现

// An highlighted block
class A:
    def __init__(self,name):
        self._name=name
    def __len__(self):
        return 10
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self):
        self._name=name
class B:
    def __init__(self,name):
        self._name=name
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self):
        self._name=name
class C:
    pass
a=A('sun')
b=B('zhu')
定义一个函数
对于say_Hello这个函数只要对象中含有name属性,他就可以作为参数传递
这个函数不需要考虑对象的类型,只要有name属性即可
def say_Hello(obj):
    print('你好%s'%obj.name)
    对于say2_Hello中我们做了一个类的检查,也就是只要obj是A类型对象时
    才可以使用
    违反了多态的函数只适用于一种类型的对象,无法处理其他类型的对象。这样导致函数适应性
    非常差
def say2_Hello(obj):
    if isinstance(obj,A)
    print('你好%s'%obj.name)
# len()
# 之所以一个对象能通过len()来获取长度是因为对象中具有一个特殊方法__len__

len(a)