Python学习之面向对象(封装、继承、多态)

举报
徐同学呀 发表于 2022/02/22 22:26:47 2022/02/22
【摘要】 面向对象 关于面向对象大家应该很熟知,即使说不出他的概念,但是至少记住他的三大特征:封装、继承、多态。 封装 所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对...

面向对象

关于面向对象大家应该很熟知,即使说不出他的概念,但是至少记住他的三大特征:封装、继承、多态。

封装

所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

类的定义

基本形式:

class ClassName(object):
    pass
  
 
  • 1
  • 2
  1. class定义类的关键字.
  2. ClassName类名,类名的每个单词的首字母大写(驼峰规则).
  3. object是父类名,object是一切类的基类。在python3中如果继承类是基类可以省略不写。
  4. pass 是类身体,由变量(类变量、实例变量)、方法组成(实例方法、静态方法、类方法)

示例:

class Animal():
    eye=2  #类变量
    def __init__(self,name):
        self.animalName=name#实例变量
        print("我是初始化方法,也可以叫我构造器")
    def move(self):
        print("我是实例方法")
    @staticmethod
    def eat(food):
        Animal.eye
        print("我是静态方法:",Animal.eye)
    @classmethod
    def run(cls):
        print("我是类方法:",cls.eye)
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

定义一个Animal类:

  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 实例变量:定义在方法中的变量,属于实例。
  • 初始化方法__init__:被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法。
  • 实例方法:类的实例化对象调用,
  • self:代表类的实例,而非类本身,self 在定义实例方法时是必须有的,虽然在调用时不必传入相应的参数。
  • 静态方法:用@staticmethod修饰,类可以不用实例化就可以调用该方法,当然也可以实例化调用,不强制要求传递参数。
  • 类方法:用@classmethod修饰,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数。

类的实例化

实例化

没有new关键字,只需要一个实例名来接收类,并且赋上需要初始的值

dog=Animal("阿黄")
cat=Animal("喵喵")
  
 
  • 1
  • 2

调用方法:

实例方法的调用:
当实例调用时,默认将当前实例传进去。
类调用时,只能以 类名.method(类实例) 形式调用。

dog.move()
cat.move()
  
 
  • 1
  • 2

静态方法的调用:实例和类调用,没有默认的参数传进函数

Anmial.eat()
dog.eat()
  
 
  • 1
  • 2

类方法的调用:
当实例调用classmethod方法时,默认会把当前实例所对应的类传进去,
当类调用classmethod方法时,默认把此类传进去。

Anmial.run()
dog.eat()
  
 
  • 1
  • 2

至于__init__(),是在实例化对象时自动调用

调用变量:

print(dog.eye)#2
print(dog.animalName)#阿黄
print(cat.eye)#2
print(cat.animalName)#喵喵
  
 
  • 1
  • 2
  • 3
  • 4

一个完整的示例:

class Animal():
    eye=2  #类变量
    def __init__(self,name):
        self.animalName=name#实例变量
        print("我是初始化方法,也可以叫我构造器")
    def move(self,way):
        print("我是实例方法:","%s在%s移动"%(self.animalName,way))
    @staticmethod
    def eat(self,food):
        Animal.eye
        print("我是静态方法:","%s吃%s"%(self.animalName,food))
    @classmethod
    def run(cls,self):
        print("我是类方法:","%s有%s只眼睛"%(self.animalName,cls.eye))
dog=Animal("阿黄")#我是初始化方法,也可以叫我构造器
cat=Animal("喵喵")#我是初始化方法,也可以叫我构造器
dog.move("马路上")#我是实例方法: 阿黄在马路上移动
Animal.eat(dog,"骨头")#我是静态方法: 阿黄吃骨头
Animal.eat(cat,"小鱼")#我是静态方法: 喵喵吃小鱼
Animal.run(dog)#我是类方法: 阿黄有2只眼睛
Animal.run(cat)#我是类方法: 喵喵有2只眼睛
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

类的私有属性和私有方法

对于python中的类属性,或者方法,可以通过双下划线_或者单下划线来实现一定程度的私有化。

  • _:以单下划线开头只能允许其本身与子类进行访问,(对于实例只是隐藏起来了,可访问,可修改)。(protected)

  • __:以双下划线开头只能允许类本身调用,类的实例不能直接调用。(private)

python 的私有不是真正的私有,只是约定俗称的规则。即使私有了我们依然可以通过
dog._Animal__leg(但是dog._Animal_a 不可以访问)来访问私有变量__leg。当然设计者也可以在类中设置方法让访问者操作私有属性。

示例:

class Animal():
    __leg="四条腿"
    _eye="两只眼睛"
    def __init__(self,name):
        self.__name=name
    def get__leg(self):
        return self.__leg
    def set__leg(self,leg):
        self.__leg=leg
    def __play(self):
        print("%s在玩"%self.__name)
dog=Animal("小狗")
print(dog._eye)#两只眼睛
print(dog.get__leg())#四条腿
print(dog._Animal__leg)#四条腿
#print(dog._Animal_eye)#AttributeError: 'Animal' object has no attribute '_Animal_eye'
dog.set__leg("三条腿")
print(dog.get__leg())#三条腿
print(dog._Animal__name)#小狗
dog._Animal__play()#小狗在玩
print(dog.__dict__)#{'_Animal__name': '小狗', '_Animal__leg': '三条腿'}
print(dir(dog))#dir查看类的所有属性和方法
['_Animal__leg', '_Animal__name', '_Animal__play', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_eye', 'get__leg', 'set__leg']
从上述也可以看出__leg ,在内存中是_Animal__leg
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

注:前后都有双下划线的是python的特殊方法如__init__(), __del__()等。

继承:

继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

python的继承分单继承和多继承。

单继承:

示例:

class man():
    __sing="唱歌"
    _dance="跳舞"
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def say(self):
        print("我是%s,我%s岁。"%(self.name,self.age))

class son(man):
    def __init__(self,sex,name,age):
        self.sex=sex
        super().__init__(name,age)
class girl(man):
    pass
son=son("男","张三",12)
son.say()#我是张三,我12岁。
girl=girl("小红",14)
girl.say()#我是小红,我14岁。
print(sorted(dir(son),reverse=True))
#['sex', 'say', 'name', 'age', '_man__sing', '_dance', '__weakref__', '__subclasshook__', '__str__', '__sizeof__', '__setattr__', '__repr__', '__reduce_ex__', '__reduce__', '__new__', '__ne__', '__module__', '__lt__', '__le__', '__init_subclass__', '__init__', '__hash__', '__gt__', '__getattribute__', '__ge__', '__format__', '__eq__', '__doc__', '__dir__', '__dict__', '__delattr__', '__class__']
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

son,girl都继承了man的属性和方法,从dir(son)可看出,__sing没有继承,_dance继承了。

多继承:

我举了一个祖孙三代的例子:
爷爷有一个名字,会说话,会踢足球;父亲继承了爷爷,但是会跑,并且重写了play方法会打篮球;小朋友是父亲的儿子,继承了父亲,自然也继承了爷爷,但是他并不会打篮球,他会踢足球。问题来了,爷爷和父亲都有play(),小朋友到底继承了谁的play()?

首先请看示例:

class Grandpa():
    def __init__(self,name):
        self.name=name
    def say(self):
        print("%s会说话"%self.name)
    def play(self):
        print("%s会踢足球"%self.name)
class Father(Grandpa):
    def run(self):
        print("%s会跑了"%self.name)
    def play(self):
        print("%s会打篮球"%self.name)
class Child(Father,Grandpa):
    def play(self):
        #super(Child, self).play()
        super(Father, self).play()
print(Child.__mro__)#(<class '__main__.Child'>, <class '__main__.Father'>, <class '__main__.Grandpa'>, <class 'object'>)
c=Child("小朋友")
c.run()#小朋友会跑了
c.say()#小朋友会说话
c.play()#小朋友会踢足球

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

我们可以通过Child.__mro__打印Child的继承路线:(请记住这个继承顺序,不能乱)

(<class '__main__.Child'>, <class '__main__.Father'>, <class '__main__.Grandpa'>, <class 'object'>)
  
 
  • 1

首先小朋友是他自己,其次他是Father的孩子,其次是Granpa的孙子,再其次他的祖先是object,这个继承顺序不能乱,就像祖孙三代的关系不能乱。

默认小盆友是继承了父亲的打篮球,但是我现在希望的是小盆友是继承爷爷的踢足球,那就要重写play方法,修改继承顺序:

super(Father, self).play()
#super里写的Father并不是继承Father,而是Father的上一辈Grandpa

#默认是这个样子的
super(Child, self).play()
  
 
  • 1
  • 2
  • 3
  • 4
  • 5

其实可以直接用类名调用相应的play方法(这样child就既会踢足球又会打篮球了)如:

def play(self):
    Grandpa.play(self)
    Father.play(self)

  
 
  • 1
  • 2
  • 3

当然继承里也不能这样写Child(Grandpa,Father)
因为这样写的继承顺序是:

(<class '__main__.Child'>, <class '__main__.Grandpa'>,  <class '__main__.Father'>,<class 'object'>)
  
 
  • 1

系统会报错:

TypeError: Cannot create a consistent method resolution
order (MRO) for bases Grandpa, Father

假如Father又有了一个实例属性age(其他都省略,我们只讨论init())

class Grandpa():
    def __init__(self,name):
        self.name=name
class Father(Grandpa):
    def  __init__(self,age,name):
        self.age=age
        super().__init__(name)
class Child(Father,Grandpa):
    '''def __init__(self,age,name):
        super().__init__(age)
        super(Father, self).__init__(name)'''
    def sing(self):
        print("我叫%s,我今年%s岁"%(self.name,self.age))
c=Child(12,"xfy")
c.sing()
f=Father(12,"f")
print(f.name)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Father自己有了__init__(),重写了Granpa的__init__(),所以要调用Grandpa的__init__(),这样Child就默认继承了Father的__init__(),他就有了name和age。

多态:

所谓多态就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。

python的多态并没什么好讲的

当派生类,重写了基类的方法时就实现了多态性。(子类重写父类方法)

python的封装、继承、多态就先告一段落,有任何疑问都可以留言评论。

文章来源: blog.csdn.net,作者:徐同学呀,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_36586120/article/details/79201338

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。