python中的封装,继承与多态

1、封装

1.1 封装的概念

为什么需要使用封装技术?
为了保障数据的安全性,降低代码的耦合度。
如何定义封装?
将具有统一功能或相关的代码块进行高度抽象的处理过程。
封装的具体表现形式?
其主要的表现形式就是将一段代码块高度抽象成一个函数、一个类或类中的方法。

1.2 访问修饰符

在类中定义的变量还是方法,基本上都可以通过实例对象或类本身进行快速访问调用。而我们在设计类的时候,有些变量或方法不希望让类外部进行调用,其仅供类内部使用。这样可以在一定程度上保护数据,以免受到外部误操作的意外篡改,导致数据不一致
所以为了更好地保护数据,Python提供了三种访问权限级别: 公有、私有 和 受保护
公有修饰的变量和方法,类的内部或外部均可调用访问。即为大家公共的数据。
私有修饰的变量和方法,仅供类内部使用,本类外部无法访问调用。即不开放数据。
受保护修饰的变量和方法,在程序中只有本类及其子类可以调用。即受限的数据。
Python编程语言很巧妙地使用“下划线+标识符”的命名规则,实现了对变量和方法的访问控制。
1、标识符开头无下划线,该变量或方法为公有权限(即类内外均可访问调用)如:self.name or def show(self)
2、标识符开头双下划线,该变量或方法为私有权限(即仅类内部自己可以访问调用)如:self.__name def __show(self)
3、标识符开头单下划线,该变量或方法为保护权限(即类本身及其子类可以访问调用)如:self._name def _show(self)

1.2.1访问修饰符在变量中的使用

class ClassName():
    def __init__(self,arg1,arg2,arg3):
        #定义一个公有实例变量
        self.publicVairable=arg1
        #定义一个受保护实例变量
        self._projectVairable=arg2
        #定义一个私有实例变量
        self.__privateVairable=arg3
if __name__=='__main__':
    obj1=ClassName(1,2,3)
    print(obj1.publicVairable)#1
    print(obj1._projectVairable)#2
    print(obj1.__privateVairable)#报错

但是可以通过创建公有实例方法,公有实例方法属于类本身,因此其可以访问私有的实例变量。从而达到私有变量对外隐藏,但通过公有方法可以访问的目的。

class ClassName():
    def __init__(self,arg1,arg2,arg3):
        #定义一个公有实例变量
        self.publicVairable=arg1
        #定义一个受保护实例变量
        self._projectVairable=arg2
        #定义一个私有实例变量
        self.__privateVairable=arg3
    
    def show(self):
        print(self.publicVairable)
        print(self._projectVairable)
        print(self.__privateVairable)

    def __str__(self):
        print(self.publicVairable)
        print(self._projectVairable)
        print(self.__privateVairable)
        return ''

if __name__=='__main__':
    obj1=ClassName(1,2,3)
    obj1.show()
    print(obj1)

1.2.2访问修饰符在方法中的使用

同样的道理,访问修饰符下划线,也可以在类的方法中使用;
这样,我们的类中方法也进行了调用管控。

class ClassName():
    def __init__(self,arg1,arg2,arg3):
        #定义一个公有实例变量
        self.publicVairable=arg1
        #定义一个受保护实例变量
        self._projectVairable=arg2
        #定义一个私有实例变量
        self.__privateVairable=arg3
        #调用私有方法
        self.__privateMethod()
    
    def __privateMethod(self):
        print('私有实例方法,仅在类内部调用')
        
if __name__=='__main__':
    obj1=ClassName(1,2,3)
    obj1.__privateMethod()#报错

1.3 @property 属性装饰器

利用面向对象的编程思想,我们会将所有的事物都先抽象成一个类,而类中有描述该事物的属性和行为。称属性为实例变量(其实不是很好理解)。
Python提供了装饰器@property,可以将方法定义成属性,后续可以使用 obj.属性名称的方式输出
为了更好地体现封装,在面向对象编程中创建类的规范:
所有的属性都必须为私有(安全保护,防止类外直接访问操作);
使用公有的setter(写入)和 getter(读取)方法操作(对外暴露操作,可间接访问私有变量)。

# 创建一个类
class Person():
 
    # 构造方法
    def __init__(self):
        # 定义一个私有的实例变量但未初始化
        self.__name = None
        pass
 
    # 定义name属性
    @property
    def name(self):
        return self.__name  
     
    # 定义设置name的实例方法
    @name.setter
    def name(self, value):
        print('>> 调用name属性的name.setter')
        if not isinstance(value, str):
            raise TypeError('应该为一个字符串类型')
        self.__name = value
     
    # 设置获取name的实例方法
    @name.getter
    def name(self):
        print('>> 调用name属性的getter')
        return self.__name 
 
 
# 脚本程序入口
if __name__ == '__main__':
    # 使用Person类创建一个对象
    obj = Person()    
    # 设置obj的name属性
    obj.name = '张三'
    # 输出obj的name属性
    print(obj.name)

1.4 定义一个操作对象的规范

一个标准的类在创建时,需遵循以下四必须标准规范:
1、类必须定义构造方法 __init__
2、类必须定义对象输出 __str__
3、类属性必须为私有
4、类必须设置公有属性访问函数

2、继承

2.1 继承的概念

继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。

2.2 继承的语法

父类-子类的纵向编程模式。
创建父类
class MainClass():
…………
pass
创建子类继承父类
class SubClass(MainClass):
…………
pass
一般共有的方法可以抽象出来放在父类中,子类在继承父类的同时凸显出自己个性的方法。
注意:子类不重写 __init__,实例化子类时,会自动调用父类定义的__init__。
重写__init__时,实例化子类,就不会调用父类已经定义的__init__。

class Animal():
    def eat(self):
        print('%s 吃' %self.name)
    def drink(self):
        print('%s 喝' %self.name)

class Cat(Animal):
    def __init__(self,name):
        self.name=name
    def call(self):
        print('%s 喵喵' %self.name)

class Dog(Animal):
    def __init__(self,name):
        self.name=name
    def call(self):
        print('%s 旺旺' %self.name)

if __name__=='__main__':

    cat=Cat('折耳猫')
    cat.eat()
    cat.drink()
    cat.call()
    dog=Dog('二哈')
    dog.eat()
    dog.drink()
    dog.call()

2.3 多继承

Python的类可以继承多个类,不像很多高级编程语言Java和C#那样只能继承一个类(单根语系)。
特别注意:在Python2.x版本中,类如果继承了多个类,那么其对象调用寻找方法的方式有两种,分别是:深度优先 和 广度优先(python3中默认均为新式类)。
当类是经典类时,多继承情况下,会按照深度优先方式查找
当类是新式类时,多继承情况下,会按照广度优先方式查找

2.4 super

在Python面向对象的继承特征下,若子类需调用父类的方法,则需要使用super()来实现。

class Cat(Animal):
    def __init__(self,name):
        self.name=name
    
    def call(self):
        print('%s 喵喵' %self.name)
        print(super().eat())

3、多态

Python不支持多态并且也用不到多态,多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚鸭子类型(英语:duck typing),其是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由当前方法和属性的集合决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试。“鸭子测试”可以这样表述:当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子”。在 duck typing 中,关注的不是对象的类型本身,而是它是如何使用的。与此同时,与 duck typing 相对应的风格是 normal typing,后者由对象类型决定了对象的特性。在使用 duck typing 的语言中,也可以编写一个 “鸭子动作” 函数,它能够接受一个任意类型的对象,并调用它的 “飞”、“跑” 等方法。换言之,只要传入对象具有正确的 “飞”、“跑” 等方法,就都可以被函数正常接受和调用。

你可能感兴趣的:(python,开发语言)