python小小白

Pyhon面向对象|类、实例化、对象、继承、多态

2019-12-31  本文已影响0人  凡有言说

1.面向对象的思想

Python是一种面向对象语言。面向对象没有那么玄乎,可以理解成“对象就是一个角色”。面向对象就是对象是个服务生,我们面对着他,不需要了解太多,只需要知道他能给为我们做些什么,当需要相关服务时,直接找他就行。

比如,字符串就是一个对象,当我们需要用到字符串替换时,直接找str就行,它有自己独特的功能replace,直接调用就行:

str1 = "庆余年"
str1.replace("庆余年", "将夜")

'将夜'

其实Python中的数据类型都是一个个对象,我们直接用就可以,简单粗暴。这就是面向对象的好,它把实现细节都封装起来,不需要自己多花力气去实现,用就完了。

当Python中没有我们需要的服务,找不到服务生(对象)时,就需要自己根据需求创建对象。

2.对象的创建和操作

在了解如何创建和操作对象前,先来了解下类的知识。类是一个结构,它会提供必要的框架,通过这个结构,去实例化出一个又一个对象。

比如我们定义一个类是房子,它是一个结构,告诉我们房子的属性,比如层数,占地面积等等,接着我们就可以通过这个类,进行实例化,得到一个个对象实例,比如高楼,别墅等等,这些得到的对象,都是有“数据”的。

为了方便理解,下面以定义“人”为例:

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

使用关键字class就可以定义类,截止用__init__方法进行初始化。后面的self代表的是实例本身,nameage属于这个类的属性。

 self.name = name
 self.age = age

以上两行,声明每一个实例化得到的对象的属性值。

如何实例化呢?很简单,通过Person("zhangsan", 18)就可以实例化类,得到一个对象。zhangsan现在就是一个通过Person实例化得到的对象,名字是zhangsan,年龄是18。

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

zhang_san = Person("zhangsan", 18)
print(zhang_san.name)
print(zhang_san.age)

zhangsan
18

我们可以用这个类来实例化其他对象,比如wangwu:

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

wang_wu = Person("wangwu", 23)
print(wang_wu.name)
print(wang_wu.age)

wangwu
23

我们也可以定义共同的变量,比如:

class Person:
    
    hobby = "reading"
    
    def __init__(self, name, age):
        self.name = name
        self.age = age

zhang_san = Person("zhangsan", 18)
wang_wu = Person("wangwu", 23)
print(zhang_san.hobby)
print(wang_wu.hobby)

reading
reading

可以看出,不同的实例可以访问当类里的同一个变量。

除了定义属性外,还可以定义功能,就是我们通常说的方法,比如说和吃。

class Person:
    
    hobby = "reading"
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
    def say(self, something):
        return "{} 说 {}".format(self.name, something)
    def eat(self, food):
        return "{} 吃 {}".format(self.name, food)

zhang_san = Person("zhangsan", 18)
print(zhang_san.say("今天天不错"))
print(zhang_san.eat("担担面"))

zhangsan 说 今天天不错
zhangsan 吃 担担面

类和对象的知识是不是就结束了?其实并没有,还有更细的内容。

3.父类、子类、继承

如果我们把人类看做一个类,往下还可按照肤色进行细分,比如黄种人、白种人、黑种人等。这里人类就是“父类”,黄种人、白种人等就是“子类”。

人类有的属性和功能,继承得到的子类们也会具有,这些子类们不需要额外的操作。这种关系,在面向对象中,被叫做继承。

#父类
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def play(self, game):
        return "{} 玩 {}".format(self.name, game)

#子类继承父类
class Asian(Person):
    pass

Lisi = Asian("Lisi", 15)
print(Lisi.play("王者荣耀"))

Lisi 玩 王者荣耀

可以看到黄种人这个对象,可以直接调用它的父类Person的play方法。当然,子类也可以定义自己特有的属性和方法,比如:

#父类
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def play(self, game):
        return "{} 玩 {}".format(self.name, game)

#子类
class Asian(Person):
    def sing(self, song):
        return "{} 唱 {}".format(self.name, song)

Lisi = Asian("Lisi", 15)
print(Lisi.sing("你的答案"))

Lisi 唱 你的答案

如果希望子类和父类的功能不一样,比如父类是“唱”,子类是“动情地唱”:

#方法重写
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def sing(self, song):
        return "{} 唱 {}".format(self.name, song)

#子类
class Asian(Person):
    def sing(self, song):
        return "{} 动情地唱 {}".format(self.name, song)

Liyi = Person("Liyi", 40)
print(Liyi.sing("海阔天空"))
Liliu = Asian("Liliu", 16)
print(Liliu.sing("下山"))

Liyi 唱 海阔天空
Liliu 动情地唱 下山

上面的例子就是“方法的重写”

继续深入地讨论下父类和子类,父类也叫作基类、超类(super class)。类只是一个结构,在定义结构的时候,它并不是实例化出来的对象,只是个定义。那么在定义方法时,如果想要用到 super 类的方法,你就只能用 super 来调用它。

以下来源于 Python:类的继承,调用父类的属性和方法基础详解

以上我们了解过子类继承父类:

class Father():
    def __init__(self):
        self.a='aaa'  
    def action(self):
        print('调用父类的方法')
 
class Son(Father):
    pass
 
son=Son()     # 子类Son 继承父类Father的所有属性和方法
son.action()  # 调用父类方法
son.a         # 调用父类属性

调用父类的方法
'aaa'

子类重写方法:

class Father():
    def __init__(self):
        self.a='aaa'
    
    def action(self):
        print('调用父类的方法')
 
class Son(Father):
    def __init__(self):
        self.a='bbb'
    def action(self):
        print('子类重写父类的方法')
 
son=Son()     # 子类Son继承父类Father的所有属性和方法
son.action()  # 子类Son调用自身的action方法而不是父类的action方法
son.a

子类重写父类的方法
'bbb'

如果子类没有重写父类的方法,那么调用该方法的时候,会调用父类的方法,当子类重写了父类的方法,默认是调用自身的方法。

如果如果子类Son重写了父类Father的方法,如果想调用父类的action方法,可以利用super()

#如果在重新父类方法后,调用父类的方法
class Father():
    def action(self):
        print('调用父类的方法')
 
class Son(Father):
    def action(self):
        super().action()

son=Son()
son.action() 

调用父类的方法

如果自己也定义了 init 方法,那么父类的属性是不能直接调用的,可以在 子类的 init中调用一下父类的 init 方法。

class Father():
    def __init__(self):
        self.a='aaa'
 
class Son(Father):
    def __init__(self):
        super().__init__()
        #也可以用 Father.__init__(self)  这里面的self一定要加上

son=Son()
print(son.a) 

aaa

再来一个复杂点的例子

class Father():
    def __init__(self):
        self.a=1
        self.b=2
 
class Son(Father):
    def __init__(self):
        super().__init__()
        #也可以用 Father.__init__(self)  这里面的self一定要加上
    def add(self):
        return self.a+self.b
son=Son()
print(son.add())

3

父类在初始化过程中,直接对a,b分别赋值1,2。子类利用super(). __init__ ()继承了父类的初始化参数a和b,所以子类调用自身的add函数(add函数返回a和b的和)会返回结果值。

如果不对父类初始化直接赋值,并且子类在调用父类初始化过程中,增加额外自身需要的初始化参数值。

class Father():
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def dev(self):
        return self.a - self.b
 
 #调用父类初始化参数a,b并增加额外参数c
class Son(Father):
    def __init__(self,a,b,c=10):  # 固定值: 例如默认c=10,也可以显示地将c赋值
        Father.__init__(self,a,b)  
        self.c = c
    def add(self):
        return self.a+self.b
    def compare(self):
        if self.c > (self.a+self.b):
            return True
        else:
            return False
        
son=Son(1,2)         # 由于c在初始化过程中默认为10,所以c可以不用显示表达出来
print(son.dev())     # 调用父类dev函数
print(son.add())     # 子类自身add函数
print(son.compare()) # 子类自身compare函数

-1
3
True

以上都是单继承的情况,下面介绍多继承。比如说儿子的爸爸是黄种人,妈妈是白种人。

#多继承
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def eat(self, food):
        print(self.name, "调用的是Person方法,正在吃{}".format(food))

class AsianFather(Person):
    def eat(self, food):
        print(self.name, "调用的是AsianFather方法,正在吃{}".format(food))
        
class CaucasianMonther(Person):
     def eat(self, food):
        print(self.name, "调用的是CaucasianMonther方法,正在吃{}".format(food))

class Son(AsianFather, CaucasianMonther):
    pass

son = Son("Wangwu", 18)
son.eat("饺子")

Wangwu 调用的是AsianFather方法,正在吃饺子

4.多态

为什么调用的是 YellowPeopleFather 里的方法,而不是其他的方法。多重继承的子类,调用方法的顺序。在 Python 中,使用到的是 MRO,我们可以通过调用子类的 mro 方法来具体查看:

print(Son.__mro__)

(<class '__main__.Son'>, <class '__main__.AsianFather'>, <class '__main__.CaucasianMonther'>, <class '__main__.Person'>, <class 'object'>)

可以看到,这里是调用的顺序是
Son->AsianFather->CaucasianMother–>Person–>object
因为我们的 Son 类没有定义 eat 方法,所以我们才会看到 Son 是调用了 AsianFather里的 eat 方法。
我们可以举个例子再来验证下:

#多继承
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def eat(self, food):
        print(self.name, "调用的是Person方法,正在吃{}".format(food))

class AsianFather(Person):
    def eat(self, food):
        print(self.name, "调用的是AsianFather方法,正在吃{}".format(food))
        
class CaucasianMonther(Person):
     def eat(self, food):
        print(self.name, "调用的是CaucasianMonther方法,正在吃{}".format(food))

class Son(AsianFather, CaucasianMonther):
    def eat(self, food):
        print(self.name, "调用的是Son方法,正在吃{}".format(food))

son = Son("Wangwu", 18)
son.eat("饺子")

Wangwu 调用的是Son方法,正在吃饺子

如果我们想在 Son 里面使用AsianFather的 eat 方法,可以根据MRO顺序,使用super。其实调用 super 的时候,就是调用 MRO 顺序的下一个类。

#多态
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def eat(self, food):
        print(self.name, "调用的是Person方法,正在吃{}".format(food))

class AsianFather(Person):
    def eat(self, food):
        print(self.name, "调用的是AsianFather方法,正在吃{}".format(food))
        
class CaucasianMonther(Person):
     def eat(self, food):
        print(self.name, "调用的是CaucasianMonther方法,正在吃{}".format(food))

class Son(AsianFather, CaucasianMonther):
    def eat(self, food):
        super().eat(food)
        #super(Son, self).eat(food)
        
son = Son("Wangwu", 18)
son.eat("饺子")

Wangwu 调用的是AsianFather方法,正在吃饺子

参考资料:
什么是面向对象编程思想
如何创建和操作 Python 对象?类、实例化、对象之间的关系?
Python:类的继承,调用父类的属性和方法基础详解
Python编程:封装、继承、多态

公众号.png
上一篇下一篇

猜你喜欢

热点阅读