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

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
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,578评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,701评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,691评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,974评论 1 318
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,694评论 6 413
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,026评论 1 329
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,015评论 3 450
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,193评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,719评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,442评论 3 360
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,668评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,151评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,846评论 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,255评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,592评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,394评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,635评论 2 380

推荐阅读更多精彩内容