多继承、多态、类属性以及类方法

本文深入解析Python中的面向对象编程概念,包括多继承、多态、类属性与实例属性的区别,以及类方法、实例方法和静态方法的使用。通过具体代码示例,详细阐述这些概念的应用场景和工作原理。

一、多继承

  • 多继承定义:子类有多个父类,并且具有他们的特征
class Base(object):
    def test(self):
        print("----Base---")

class A(Base):
    def test1(self):
        print("----test1")

class B(Base):
    def test2(self):
        print("----test2")

class C(A, B):
    pass

c = C()
c.test1()
c.test2()
c.test()

打印的结果如下:
在这里插入图片描述

多继承的注意点①:

class Base(object):
    def test(self):
        print("----Base---")

class A(Base):
    def test(self):
        print("----A")

class B(Base):
    def test(self):
        print("----B")

class C(A, B):
   	def test(self):
   		print("----C")

c = C()
c.test()

此时这么多类里面都含有test方法,输出结果只调用C类的test,如果自己的类里面含有这个方法的话,就只调用自己的方法就结束了,不会再调用父类的。

情况②:

class Base(object):
    def test(self):
        print("----Base---")

class A(Base):
    def test(self):
        print("----A")

class B(Base):
    def test(self):
        print("----B")

class C(A, B):
   	pass

c = C()
c.test()

此时c的类里没有test这个方法,那么它就会到它的父类里去找是否含有test这个方法,如果有就调用。

类名.__mro__的使用

class Base(object):
    def test(self):
        print("----Base---")

class A(Base):
    def test1(self):
        print("----B")

class B(Base):
    def test(self):
        print("----C")

class C(A, B):
    pass

c = C()
c.test()
print(C.__mro__)
  • 通过使用类名.__mro__的方式可以查看 决定着调用一个方法的时候,搜索的顺序,如果在某个类中找到了这个方法,那么就停止搜索。以上面一个程序为例,它的搜索顺序如下:
    在这里插入图片描述

二、多态

多态定义:定义时的类型和运行时的类型不一样,此时就称为多态。

class Dog(object):
    def print_self(self):
        print("大家好,我是xxxxx")

class Xiaotq(Dog):
    def print_self(self):
        print("hello everybody, 我是你们的大哥...., 我是xxxx")

def introduce(temp):
    temp.print_self()

dog1 = Dog() # 创建了一个dog1的对象,dog1保存了创建对象的引用
dog2 = Xiaotq()

introduce(dog1) # 将dog1作为函数形参传递给函数,此时temp也指向这个对象,此时这个对象内部就能调用它自己的方法
introduce(dog2)
  • 首先需要理解的是,在Python里面,所有传递函数形参或者赋值的时候,都是引用,所以temp也指向dog1新创建的对象。
  • 这里定义的introduce函数就能体现多态的作用,当输入给introduce的形参为dog1对象的时候,调用的就是它父类里的那个方法,如果输入的是dog2的时候,那么调用的就是它的子类自己的这个方法。
  • 所以这里的多态指的是:当你写完程序之后,你仅仅知道它调用了一个方法,但是你不确定它是调用的是基类的方法还是子类的方法,但是在真正执行程序的那个时候,你才能根据当前的对象是谁来确定你调用的是哪个的方法。

Note:

  • Python既支持面向对象,也支持面向过程。
  • Python面向对象的三个要素是:封装、继承、多态
  • 封装:函数和全局变量找了一个类封在一起就叫做对象
  • 继承:子类继承父类的功能
  • 多态:定义的时候不确定调用的是哪个功能,而在真正调用的时候才确定是调用子类的还是父类的方法。

三、类属性和实例属性

class Tool(object):
    # 属性
    num = 0

    # 方法
    def __init__(self, new_name):
        self.name = new_name
        Tool.num += 1

tool1 = Tool("铁锹")
tool2 = Tool("兵工铲")
tool3 = Tool("水桶")
print(Tool.num)
  • 当创建完成一个对象之后,上述程序里self.xxx就是给这个对象添加一个属性。
  • 另一种定义属性的方法是定义在class里面,定义在def外面,这个时候定义的叫做类属性,如上述程序的num。
  • 实际上上述程序的运行流程如下:
    在这里插入图片描述
    程序通过tool1 = Tool(“铁锹”)这句话的过程是,根据Tool这个类创建了一个对象,返回一个引用保存到tool1里面,然后创建这个对象里面包含一个特殊的属性(变量),这个特殊的属性(变量)能够找到这个对象是通过哪一个类创造出来的对象。所以,当你创建完一个对象之后,这个对象多了一个特殊的属性,这个属性保存了这个类的引用。
    同理对于tool2和tool3都是含有的,只要创建了一个对象,它里面的一个特殊的属性就指向了这个类:
    在这里插入图片描述
    为什么创建了一个对象它里面就有一个特殊的属性来指向那个类呢?具体这么做的原因是:为了节省空间,不可能每创建了一个对象,就把类里面的方法在创建的对象里面复制一份,这样就浪费内存了。所以仅仅只在定义的类里面存放了一份代码,当这个对象真正去调用这个功能的时候就通过这个特殊的变量指向的类里去调用需要使用的方法。
  • 现在的问题是,上述创建的一个对象(蓝色的框框)保存了属性,需要占用了内存空间,所以称之为对象;Tool这个类保存了代码也是需要占用内存空间的,那么它也可被称之为对象。(总而言之,类在程序里面也是一个对象,为了区分类是一个对象,通过类创建出来的也是一个对象,此时就需要引入类对象和实例对象)
  • 实例对象里面的属性叫做实例属性,类对象里面的属性叫做实例属性。
  • 类对象的特点:只要定义了一个类,那么这个类对象就只有一个。只要通过这个类创建了一个新的子类,如上面的tool1、tool2和tool3所示,那么他们每个就代表自己的一个。实例属性就和自己的那个对象有关系,类属性就和类对象有关系。特点是:在tool1里的实例里面不能直接获取tool2的实例属性,需要通过特殊的方式来调用。
  • 类属性的特点:它在根据类对象创建出来的实例对象里的属性共享。
    在这里插入图片描述
  • 类属性只会在定义这个类的时候定义一次,不会因为你创建了一个实例对象就再次创建一次。

走一遍程序流程:

class Tool(object):
    # 类属性
    num = 0

    # 方法
    def __init__(self, new_name):
        # 实例属性
        self.name = new_name

        # 对类属性+=1
        Tool.num += 1

tool1 = Tool("铁锹")
tool2 = Tool("兵工铲")
tool3 = Tool("水桶")
print(Tool.num)

在这里插入图片描述
当程序从上往下来的时候,先定义了一个类对象,此时这个类里面包含类属性和若干方法,然后执行11行的代码tool1 = Tool("铁锹"),首先创建了一个对象,也就是右边蓝色框框里的内容,创建完一个实例对象之后就开辟了一片内存,创建完成对象之后紧接着就调用__init__方法(这个__init__方法并不在实例对象里面存着,是通过这个变量找到类对象,然后执行类对象里的__init__方法),当执行__init__方法的时候,此时的self指向的是实例对象,那么self.name就给实例对象里面添加一个属性叫做name,之后再运行Tool.num += 1,给类属性加1。

四、类方法、实例方法和静态方法

class Game(object):

    # 类属性
    num = 0

    # 实例方法
    def __init__(self):
        # 实例属性
        self.name = "laowang"

    # 类方法
    @classmethod
    def add_num(cls):
        cls.num = 100

	# 静态方法
	@staticmethod
	def print_menue():
		print('---------------')
		print("    穿越火线V1.0")
		print("	1、开始游戏")
		print("	2、结束游戏")
		print("-------------------")

game = Game()
# Game.add_num() # 可以通过类的名字调用类方法
game.add_num() # 还可以通过这个类创建出来的对象 去调用这个类方法
print(Game.num)
  • 加上@classmethod 的方法被称为类方法。
  • 加上@staticmethod 的方法叫做静态方法。
  • 实例方法必须有一个参数self,用来接收实例对象的引用,类方法必须有一个参数cls,用来接收类的引用,静态方法可以不用有参数,静态方法用来完成一些基本的功能,它既和类没有关系也和实例对象也没关系。因为一般开发的时候,要么用类就全用类,要么用函数就全部用函数,所以才会有静态方法的出现,为了防止一下出现函数,一下出现类。

调用静态方法的方式:

Game.print_menu() # 通过类 去调用静态方法

game.print_menu() # 通过实例对象 去调用静态方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值