Python学习面向对象1--封装,继承,多态

上次我们说到,关于python面向对象
面向对象是什么
面向对象和面向过程的区别
类和对象
python中如何定义类和实例化对象
类的属性和方法

这里我们讲面向对象的特征:封装,继承,多态,三大特征。
也有说抽象加在一起算作是四大特征,这一观点并未得到公认。

封装

什么是封装?

广义的封装:将事物的细节进行封起,提供好用的方法供使用者使用。
面向对象的封装:
1.将类的属性和方法封装成一个或者多个类,使用的时候调用对象的属性和方法。
2.将类的属性进行封装(私有化private),仅供类内部进行访问,提供公开的方法(getter和setter)进行访问。

python中如何实现封装

对于上面的第二点,才是面向对象封装特性的重点。
请看下面这段代码:

# -*- coding: utf-8 -*-

class Richman:
    
    def __init__(self):
        self.money = 1000000
        self.company = "alibaba"

        
    def speak(self):
        print("我对钱没有兴趣!")
        print("一个月一块钱的工资!")
    
if __name__ == "__main__":
    rich1 = Richman()
    print(rich1.money)
    rich1.money = 1000
    print(rich1.moneyA)

运行结果如下,可以看到可以直接访问对象的属性和修改属性,这样是极为不好的,不符合封装的特性。
在这里插入图片描述
如何修改呢,将属性进行私有化。

class Richman:
    
    def __init__(self):
        self.__money = 1000000
        self.__company = "alibaba"#__属性即是私有属性。

        
    def speak(self):
        print("我对钱没有兴趣!")
        print("一个月一块钱的工资!")
    
if __name__ == "__main__":
    rich1 = Richman()
    print(rich1.money)
    rich1.money = 1000
    print(rich1.moneyA)

修改为私有属性,则无法进行访问,如要进行访问则需要对外界提供公开的方法。
在这里插入图片描述
同理,属性可以私有,方法同样可以私有。

三种封装访问方式

上面说到封装特性的时候,采用getter,和setter进行提供公开的访问
1.getter和setter

class people:
    
    def __init__(self,name,age,gender):
        self.__name = name
        self.__age = age
        self.__gender = gender
        
    def __str__(self):
        return "name = "+ self.__name +",age = "+ self.__age
    
    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name
        
    def get_age(self):
        return self.__age
    
    def set_age(self,age):
        self.__age = age

if __name__ == "__main__":
    p1 = people("xuhaobo","18","男")
    print(p1.get_name())
    print(p1.get_age())
    print(p1)
    p1.set_name("wangwang")
    p1.set_age("20")
    print(p1)

提供了getter和setter可以对私有属性进行访问和修改。
在这里插入图片描述
2.将访问方法再进行封装,让用户感觉没有变化。
使用property方法
如下的:将之间的方法再提供给用户。用户使用起来没有变化,get在前,set在后
name = property(get_name,set_name)
age = property(get_age,set_age)

class people:
    
    def __init__(self,name,age,gender):
        self.__name = name
        self.__age = age
        self.__gender = gender
        
    def __str__(self):
        return "name = "+ self.__name +",age = "+ self.__age
    
    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name
        
    def get_age(self):
        return self.__age
    
    def set_age(self,age):
        self.__age = age

	name = property(get_name,set_name)
    age = property(get_age,set_age)

if __name__ == "__main__":
    p1 = people("xuhaobo","18","男")
    print(p1.name)
    print(p1.age)
    print(p1)
    p1.name = "wangwang"
    p1.age = "20"
    print(p1)

可以看到用户访问起来并没有觉得有任何不同。
在这里插入图片描述

3.使用property装饰器
可以说是property(get,set)的变式写法
将property()写为如下形式:

	@property #装饰器
    def gender(self):
        return self.__gender
    
    @gender.setter #一般使用私有属性的名称作为@的值
    def gender(self,gender):
        self.__gender = gender

代码如下:

class people:
    
    def __init__(self,name,age,gender):
        self.__name = name
        self.__age = age
        self.__gender = gender
        
    def __str__(self):
        return "name = "+ self.__name +",age = "+ self.__age
    
    def get_name(self):
        return self.__name

    def set_name(self,name):
        self.__name = name
        
    def get_age(self):
        return self.__age
    
    def set_age(self,age):
        self.__age = age

        
#property(get,set)的变式写法        
    @property 
    def gender(self):
        return self.__gender
    
    @gender.setter
    def gender(self,gender):
        self.__gender = gender

    
    name = property(get_name,set_name)
    age = property(get_age,set_age)
    
    
if __name__ == "__main__":
    p1 = people("xuhaobo","18","男")
    print(p1.name)
    print(p1.age)
    print(p1)
    p1.name = "wangwang"
    p1.age = "20"
    print(p1)
    print(p1.gender)
    p1.gender = "女"
    print(p1.gender)
    print(p1)

在这里插入图片描述
故在定义类之时,一定要进行对类进行封装,私有化其属性,再提供公开的get和set进行访问。具有一定安全性。

继承

继承是什么?下一代获得上一代遗留的东西的过程称为继承。
在python之中,一个类如何继承另一个类呢,我通过代码进行演示。

class Richman:
    
    def __init__(self):
        self.money = 1000000
        self.mompany = "alibaba"

        
    def speak(self):
        print("我对钱没有兴趣!")
        print("一个月一块钱的工资!")

class Son(Richman):
    
    pass
    
if __name__ == "__main__":
    s1 = Son()
    print(s1.money)
    s1.money = 1000
    print(s1.money)
    s1.speak()

在这里插入图片描述
可以看到,son类中什么内容也没有写,是继承了richman中的属性和方法。
下面我将money属性改为私有,可以看到报错。
self.__money = 1000000
在这里插入图片描述
是因为继承只能继承公开的属性和方法,私有属性和方法无法继承

重写override

如果对继承的方法不满意怎么办,不合适,那么就需要对方法进行重写。

class Richman:
    
    def __init__(self):
        self.__money = 1000000
        self.mompany = "alibaba"

        
    def speak(self):
        print("我对钱没有兴趣!")
        print("一个月一块钱的工资!")
        
    def working(self):
        print("A你是个好同志,做事我放心!")
        print("B你是个lowB,干事不好!")        
    
class Son(Richman):
    def working(self):
        print("还是自己人来好一点!,我把自己兄弟叫来")
    
if __name__ == "__main__":
    s1 = Son()
    r1 = Richman()
    s1.speak()
    r1.speak()
    s1.working()
    r1.working()

对父类的working方法进行了重写,可以看到重写后则就是调用的是重写后在该类中的working,父类和子类中的方法,调用时是就近原则。
在这里插入图片描述

一道常见的面试题:

Python中有函数重载和方法重写吗?
答案:没有函数重载,有方法重写。
why:
overload:名称相同,参数不同或者类型不同的一些函数。
1.由于python是弱数据类型语言,则类型不会不相同,
2.由于py是解释型语言,执行时候后者所谓重载的函数会覆盖之前的函数,则没有重载。
重写就不用说了,上面演示的就是重写

继承的作用和目的是为了:代码复用和多态。代码复用是继承的本质。

super关键字和多继承

同样是面向对象,java不支持多继承。
py如何支持多继承的呢?
如 class Son(Richman,xxx,xxxx,…)一个类可以有多个父类。
这有一个问题:同时继承多个类,类中都用同一个方法,该如何调用呢?
在py3中现在使用的是新式类,采用广度优先,即继承的顺序来调用。
在旧式类中,采用的是深度优先,按照继承的类的深度来调用,如果深度想同,则再按照继承顺序。

super ,超级的意思,----》算是个指针,指向父类。
在子类中使用。
super().方法名()
使用如下:

# -*- coding: utf-8 -*-

class Richman:
    
    def __init__(self):
        self.__money = 1000000
        self.mompany = "alibaba"

        
    def speak(self):
        print("我对钱没有兴趣!")
        print("一个月一块钱的工资!")
        
    def working(self):
        print("A你是个好同志,做事我放心!")
        print("B你是个lowB,干事不好!")        
    
class Son(Richman):
    def working(self):
        print("还是自己人来好一点!,我把自己兄弟叫来")
    def test(self):
        super().working()
if __name__ == "__main__":
    s1 = Son()
    r1 = Richman()
    s1.speak()
    r1.speak()
    s1.working()
    r1.working()
    s1.test()

结果:
在这里插入图片描述
在初始化函数的时候,是对子类操作,不像其他语言。如下:

class RichMan:
    def __init__(self):
        print("这是父类!")
        
class Son(RichMan):
    def __init__(self):
        print("这是子类!")
        
        
if __name__ == "__main__":
    s1 = Son()

代码执行:
在这里插入图片描述
如果需要调用父类,则需要使用super。

class RichMan:
    def __init__(self):
        print("这是父类!")
        
class Son(RichMan):
    def __init__(self):
        super().__init__()
        print("这是子类!")
        
        
if __name__ == "__main__":
    s1 = Son()

在这里插入图片描述
super()调用的方法中是有参则传参。

多态

何为多态?
对象的多种状态。
在继承的基础上,父类引用指向子类实例的现象,称为多态。
比如java中父类list,一个子类arraylist。

List ls = new ArrayList()

父类调用子类方法,而py是弱数据类型,上面例子成为:

ls = ArrayList()

由于py是弱数据类型,天生就是支持多态的,则其不关心多态的问题。
这里就不多讲了。

今天的分享就到这里了,喜欢的小伙伴可以点赞和关注呀!博主持续分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章