Python面向对象学习整理(二)

三、使用继承,封装,多态

3.1 使用继承

示例代码如下

class Dog():

    def __init__(self,name,age):
        self.name = name
        self.age = age

    # 定义公共方法
    def bark(self):
        print(f"{self.name} can bark")

class pipi(Dog):

    def play(self):
        print(f"{self.name} 会打滚")

class dandan(Dog):

    def other(self):
        print(f"{self.name} 会杂技")

dog1 = pipi("皮皮",2)
dog2 = dandan("蛋蛋",3)
dog1.play()
dog1.bark() # 调用公共的方法
dog2.other()

我们在上面的代码找那个分别编写了 pipi 类 和 dandan 类,它们分别继承于 Dog 类,因此他们都会具备 Dog 类具有的属性和方法,然后他们也可以拥有他们独有的属性和方法

3.2 方法的覆盖

3.2.1 一般的方法覆盖情况

假设有这种情况,子类和父类拥有同样的方法名,但是我们调用的方法是属于父类的还是子类的呢?我们改一下代码看看。

class Dog():

    def __init__(self,name,age):
        self.name = name
        self.age = age
        
    def bark(self):
        print(f"{self.name} can bark")

    def eat(self):
        print(f"{self.name} 喜欢吃鸡肉")

class pipi(Dog):

    def play(self):
        print(f"{self.name} 会打滚")

    def eat(self):
        print(f"{self.name} 喜欢吃火腿")


dog1 = pipi("皮皮",2)
dog1.eat()

运行结果:

皮皮喜欢吃火腿

所以我们发现,当子类和父类方法同名时,子类方法会覆盖父类的方法。

3.2.2 init 方法覆盖

当子类没有 init 方法的时候,它会直接继承 父类的 init 方法

当子类 定义了 init 方法的时候,在子类的 init() 中调用父类的 init()方法,和上面情况类似,区别就是调用父类 init() 方法的时机

子类定义了 init(),子类__init__() 中没有调用父类的方法,这时候注意,父类的私有属性无法调用,子类调用私有属性的 get 和 set 方法会报错

3.3 封装

封装的核心:封装是隐藏对象中一些不希望被外部访问到的属性或方法

在学习 Java 的过程中,我们进行封装操作的时候,设置属性的访问权限为 private(只在当前类可以访问),所以我们会使用 getter 和 setter 方法来修改属性的值。在 Python 中我们也可以使用 同样的 getter 和 setter 方法

3.3.1 封装程度(**)

class Dog():
# 安全性问题,属性值不能乱改
def init(self,name,age):
# 方式一,换一个属性名保存
self.hidden_name = name
self.hidden_age = age

def getAge(self):
    return self.hidden_age

def setAge(self, age):
    if age < 0 or age > 150:
        raise ValueError('年龄值不合格')
    self.hidden_age = age

虽然我们这样做, 还是不希望 hidden_xx 属性被外部访问,因此使用更高级的封装

3.3.2 封装程度(***)
class Retangle():

    # 内部访问,使用 hidden 任然可以被访问
    # 使用 __作为私有属性,是外部不可以被访问
    def __init__(self,width, height):
        self.__width = width
        self.__height = height

    def setWidth(self,width):
        self.__width = width

    def getWidth(self):
        return self.__width

    def setHeight(self,height):
        self.__height = height

    def getHeight(self):
        return self.__height

我们使用 ‘__’ 作为隐藏属性,使外部不可见,这也是很常用的一种方法,

接下来解释一下 双下划线的作用:

在 Python 中,双下换线是作为隐藏属性而存在的,但它其实还是可以通过方法访问的到的,在 Python 内部当中,双下划线实际上是把 属性换了一个更复杂的方式表示,比 hidden_属性 更复杂,它其实是把 __xxx 替换成了 _类名__属性名 表示。

所以 Python 中的封装一般做到这一步就差不多了


3.3.3 封装程度(******)

使用装饰器把 getter 和 setter 更好的封装

class Person():
    '''
        __xxxx 成为隐藏属性
        __name -> _Person__name

        使用 _xxx 作为私有属性,没有特殊需求,不要修改私有属性
        类一般使用属性或方法不可见可以使用单下划线
    '''
    # 使用一个
    def __init__(self,name):
        self.__name = name

    @property
    def name(self):
        return self.__name

    '''
        setter
        getter 方法更好的使用
        @property,将一个 get 方法,转换为对象属性
        @属性名.setter 讲一个 set 方法,转换为对象属性
        两者缺一不可
    '''

    # setter 方法的的装饰器: @属性名.setter
    @name.setter
    def name(self, name):
        self.__name = name



p = Person('猴赛雷')
p.name = 'aaa' # 使用属性的方式 调用 setter 和 getter
print(p.name)

3.4 多态

多态:它指的是一个声明为 A类型的变量,可能是指 A类型的对象,也可以是 A类型的任何子类对象

class Dog():

    def __init__(self,name,age):
        self.name = name

        if age > 100:
            raise ValueError("狗狗的年龄不可能这么大")
        self.__age = age

    def getAge(self):
        return self.__age

    def setAge(self,age):
        if age > 100:
            raise ValueError ("狗狗的年龄不可能这么大")
        self.__age = age

    # 定义公共方法
    def bark(self):
        print(f"{self.name} can bark")

    def eat(self):
        print(f"{self.name} 喜欢吃鸡肉")

class pipi(Dog):

    def play(self):
        print(f"{self.name} 会打滚")

    def eat(self):
        print(f"{self.name} 喜欢吃火腿")

    # 方法覆盖
    def bark(self):
        print(f"{self.name} 在叫,嘻嘻....")
class dandan(Dog):

    def other(self):
        print(f"{self.name} 会杂技")

def dog_bark(dog):
    if isinstance(dog, Dog):
        dog.bark()

d = Dog("阿拉斯加",3)
dog_bark(d)

d1 = pipi("小皮",2)
dog_bark(d1)

d2 = dandan("蛋蛋",1)
dog_bark(d2)

在上面的代码中,我们定义了一个 dog_bark() 方法,它可以介绍父类的对象,也可以接受子类的对象

使用多态,我们并不需要给每一个 子类定义一个调用 bark() 的方法,pipi_bark(), dandan_bark(),只需要定义一个 dog_bark(), 在调用的时候给它传递对应的子类对象即可。

面向对象三大特点总结

面向对象三大特征

1.封装(把一些重要属性封装起来,防止被查看)

  • 确保数据安全
  1. 继承(扩展)
  • 保证对象的访问扩展性
  1. 多态 (满足条件就是某种事务)
  • 保证程序的灵活性

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