Python面向对象OOP

面向对象的三大属性:

  1. 封装 根据 职责属性方法 封装 到一个抽象的
  2. 继承 实现代码的重用,相同的代码不需要重复的编写
  3. 多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度

1. 创建对象时自动调用初始化方法

  • 当使用类名()创建对象时,为对象分配空间后,自动调用init方法
  1. class Cat:
  2. def __init__(self):
  3. print('这是一个初始化方法!')
  4. # 使用类名()创建对象的时候,会自动调用初始化方法(__init__)
  5. tom = Cat()

Python面向对象OOP - 图1

2.在初始化方法内部定义属性

  1. class Cat:
  2. def __init__(self):
  3. self.name = 'Tom'
  4. print('这是一个初始化方法!')
  5. # 使用类名()创建对象的时候,会自动调用初始化方法(__init__)
  6. tom = Cat()
  7. print(tom.name)

Python面向对象OOP - 图2

3.初始化同时设置初始值

  1. class Cat:
  2. def __init__(self,name):
  3. self.name = name
  4. print('这是一个初始化方法!')
  5. # 使用类名()创建对象的时候,会自动调用初始化方法(__init__)
  6. tom = Cat('tom')
  7. print(tom.name)

Python面向对象OOP - 图3

4.内置方法del方法和对象生命周期

  • 当一个对象被从内存中销毁前,会调用del方法。

    • __init__ 改造初始化方法,可以让创建对象更加灵活
    • __del__ 如果希望在对象被销毁前,再做一些事情,可以考虑一下 __del__ 方法

生命周期

  • 一个对象从调用 类名() 创建,生命周期开始
  • 一个对象的 __del__ 方法一旦被调用,生命周期结束
  • 在对象的生命周期内,可以访问对象属性,或者让对象调用方法
  1. class Cat:
  2. def __init__(self,name):
  3. self.name = name
  4. print('这是一个初始化方法!')
  5. def __del__(self):
  6. print('这个对象被销毁了')
  7. # 使用类名()创建对象的时候,会自动调用初始化方法(__init__)
  8. tom = Cat('tom')
  9. print(tom.name)
  10. del tom # del关键字可以删除一个对象

Python面向对象OOP - 图4

5.内置方法str方法定制变量输入信息

  1. class Cat:
  2. def __init__(self,name):
  3. self.name = name
  4. print('这是一个初始化方法!')
  5. def __del__(self):
  6. print('这个对象被销毁了')
  7. # 使用类名()创建对象的时候,会自动调用初始化方法(__init__)
  8. tom = Cat('tom')
  9. print(tom.name)
  10. print(tom)
  11. del tom

当不自定义str方法时,直接打印对象效果为:

Python面向对象OOP - 图5

可以看到打印出来的是main.类名 object at 对象的内存地址

当我们自定义了之后:

  1. class Cat:
  2. def __init__(self,name):
  3. self.name = name
  4. print('这是一个初始化方法!')
  5. def __del__(self):
  6. print('这个对象被销毁了')
  7. def __str__(self):
  8. return '我最帅'
  9. # 使用类名()创建对象的时候,会自动调用初始化方法(__init__)
  10. tom = Cat('tom')
  11. print(tom.name)
  12. print(tom)
  13. del tom

Python面向对象OOP - 图6打印出了我们设置的返回的内容。

6.封装特性和案例

1.封装的概念

  1. 封装 是面向对象编程的一大特点
  2. 面向对象编程的 第一步 —— 将 属性方法 封装 到一个抽象的
  3. 外界 使用 创建 对象,然后 让对象调用方法
  4. 对象方法的细节 都被 封装类的内部

2.小明爱跑步案例

  1. class Person:
  2. def __init__(self,name,weight):
  3. self.name = name
  4. self.weight = weight
  5. def __str__(self):
  6. return f'我的名族叫:{self.name},我的体重是:{self.weight}公斤'
  7. def run(self):
  8. print(f'{self.name}爱跑步')
  9. self.weight -= 0.5
  10. def eat(self):
  11. print(f'{self.name}爱跑步')
  12. self.weight += 1
  13. xiaoming = Person('小明',75.0)
  14. print(xiaoming)
  15. xiaoming.run()
  16. print(xiaoming)
  17. xiaoming.eat()
  18. print(xiaoming)

Python面向对象OOP - 图7

3.多个对象之间互不干扰

  1. class Person:
  2. def __init__(self,name,weight):
  3. self.name = name
  4. self.weight = weight
  5. def __str__(self):
  6. return f'我的名族叫:{self.name},我的体重是:{self.weight}公斤'
  7. def run(self):
  8. print(f'{self.name}爱跑步')
  9. self.weight -= 0.5
  10. def eat(self):
  11. print(f'{self.name}爱跑步')
  12. self.weight += 1
  13. xiaoming = Person('小明',75.0)
  14. xiaomei = Person('小美',45.0)
  15. print(xiaoming)
  16. xiaoming.run()
  17. print(xiaoming)
  18. xiaoming.eat()
  19. print(xiaoming)
  20. print('='*50)
  21. print(xiaomei)
  22. xiaomei.eat()
  23. print(xiaomei)
  24. xiaomei.run()
  25. print(xiaomei)

Python面向对象OOP - 图8

3.实例2-拜访家具

  1. class HouseItem:
  2. def __init__(self,name,area):
  3. self.name = name
  4. self.area = area
  5. def __str__(self):
  6. return f'{self.name},占地面积是{self.area}平方'
  7. class House:
  8. def __init__(self,house_type,area):
  9. self.house_type = house_type
  10. self.area = area
  11. self.free_area = area
  12. self.item_list = []
  13. def __str__(self):
  14. return f'房子户型是{self.house_type},占地面积是{self.area}'
  15. def add_item(self,item):
  16. if self.area >= item.area:
  17. self.item_list.append(item.name)
  18. self.free_area -= item.area
  19. else:
  20. print('房子空间不足!')
  21. bed = HouseItem('席梦思',4.0)
  22. chest = HouseItem('衣柜',2.0)
  23. table = HouseItem('餐桌',1.5)
  24. print(bed)
  25. print(chest)
  26. print(table)
  27. house = House('三室一厅',50)
  28. print(house)
  29. house.add_item(bed)
  30. house.add_item(chest)
  31. house.add_item(table)
  32. print(house.item_list)
  33. print(house.free_area)

4.士兵突击

  1. class Gun:
  2. def __init__(self,model):
  3. self.model = model
  4. self.bullet_count = 0
  5. def add_bullet(self,count):
  6. self.bullet_count += count
  7. def shoot(self):
  8. if self.bullet_count == 0:
  9. print(f'{self.model}子弹不足!')
  10. return
  11. print('biubiubiu')
  12. self.bullet_count -= 1
  13. class Soldier:
  14. def __init__(self,name):
  15. self.name = name
  16. self.gun = None
  17. def fire(self):
  18. if self.gun is None:
  19. print(f'{self.name}还没有枪!')
  20. return
  21. print(f'冲啊{self.name}...')
  22. self.gun.add_bullet(50)
  23. self.gun.shoot()
  24. ak47 = Gun('ak47')
  25. xushanduo = Soldier('许三多')
  26. xushanduo.fire()
  27. xushanduo.gun = ak47
  28. print(xushanduo.gun)
  29. xushanduo.fire()

Python面向对象OOP - 图9

7.私有属性和私有方法

1.私有属性

  1. class Women:
  2. def __init__(self,name):
  3. self.name = name
  4. self.__age = 18
  5. def secret(self):
  6. print(f'我的名字是{self.name},年龄是{self.__age}')
  7. xiaomei = Women('小美')
  8. xiaomei.secret()
  9. print(xiaomei.__age)

Python面向对象OOP - 图10

  • 程序运行后发现报了一个错误, ‘Women’ object has no attribute ‘__age’,说明age属性不能直接被访问,而可以通过类中方法访问。

2.私有方法

  1. class Women:
  2. def __init__(self,name):
  3. self.name = name
  4. self.__age = 18
  5. def __secret(self):
  6. print(f'我的名字是{self.name},年龄是{self.__age}')
  7. xiaomei = Women('小美')
  8. xiaomei.secret()
  • 上面代码中,我将之前的secret方法名的前面加上了两个下划线,这个方法就变成了私有方法,只有在类中可以调用,而想在类的外面调用就会报错:

Python面向对象OOP - 图11

3.伪私有属性和伪私有方法

  1. class Women:
  2. def __init__(self,name):
  3. self.name = name
  4. self.__age = 18
  5. def __secret(self):
  6. print(f'我的名字是{self.name},年龄是{self.__age}')
  7. xiaomei = Women('小美')
  8. xiaomei._Women__secret()
  9. print(xiaomei._Women__age)

Python面向对象OOP - 图12

  • 当定义一个私有属性时,如age,python会将它转换为_Womenage,所有我们可以使用xiaomei._Women_age来访问私有属性。同理,私有方法也是一样。

8.继承

1.单继承

  1. class Animal:
  2. def eat(self):
  3. print('吃')
  4. def drink(self):
  5. print('喝')
  6. def run(self):
  7. print('跑')
  8. def sleep(self):
  9. print('睡')
  10. class Dog(Animal):
  11. def bark(self):
  12. print('汪汪叫')
  13. wangcai = Dog()
  14. wangcai.eat()
  15. wangcai.drink()
  16. wangcai.run()
  17. wangcai.sleep()
  18. wangcai.bark()
  • 上面的代码中,我们并没有在Dog类中定义eat、drink、run、sleep,但却可以调用,这是因为Dog类继承了Animal的方法。

Python面向对象OOP - 图13

3.继承的传递性

  1. class Animal:
  2. def eat(self):
  3. print('吃')
  4. def drink(self):
  5. print('喝')
  6. def run(self):
  7. print('跑')
  8. def sleep(self):
  9. print('睡')
  10. class Dog(Animal):
  11. def bark(self):
  12. print('汪汪叫')
  13. class XiaoTianQuan(Dog):
  14. def fly(self):
  15. print('我会飞')
  16. wangcai = XiaoTianQuan()
  17. wangcai.eat()
  18. wangcai.drink()
  19. wangcai.run()
  20. wangcai.sleep()
  21. wangcai.bark()
  22. wangcai.fly()
  • 上面的程序中Dog类继承了Animal类,XiaoTianQuan类继承了Dog类,这样XiaoTianQuan类就拥有了Animal类和Dog类的所有属性和方法。

Python面向对象OOP - 图14

4.方法的重写

  1. class Animal:
  2. def eat(self):
  3. print('吃')
  4. def drink(self):
  5. print('喝')
  6. def run(self):
  7. print('跑')
  8. def sleep(self):
  9. print('睡')
  10. class Dog(Animal):
  11. def bark(self):
  12. print('汪汪叫')
  13. class XiaoTianQuan(Dog):
  14. def fly(self):
  15. print('我会飞')
  16. def bark(self):
  17. print('叫得跟普通狗不一样')
  18. xtq = XiaoTianQuan()
  19. xtq.bark()
  • 虽然父类中已经定义了bark方法,但是在XiaoTianQuan类中又重新定义了一个bark方法,当对象调用法法时,会调用自身类的方法。

Python面向对象OOP - 图15

5.扩展父类方法,super()对象调用父类方法

  1. class Animal:
  2. def eat(self):
  3. print('吃')
  4. def drink(self):
  5. print('喝')
  6. def run(self):
  7. print('跑')
  8. def sleep(self):
  9. print('睡')
  10. class Dog(Animal):
  11. def bark(self):
  12. print('汪汪叫')
  13. class XiaoTianQuan(Dog):
  14. def fly(self):
  15. print('我会飞')
  16. def bark(self):
  17. print('叫得跟普通狗不一样')
  18. super().bark()
  19. xtq = XiaoTianQuan()
  20. xtq.bark()
  • super().bark()调用父类的方法

Python面向对象OOP - 图16

6.使用父类名调用父类方法

  1. class Animal:
  2. def eat(self):
  3. print('吃')
  4. def drink(self):
  5. print('喝')
  6. def run(self):
  7. print('跑')
  8. def sleep(self):
  9. print('睡')
  10. class Dog(Animal):
  11. def bark(self):
  12. print('汪汪叫')
  13. class XiaoTianQuan(Dog):
  14. def fly(self):
  15. print('我会飞')
  16. def bark(self):
  17. print('叫得跟普通狗不一样')
  18. Dog.bark(self)
  19. xtq = XiaoTianQuan()
  20. xtq.bark()
  • Dog.bark(self)即使用父类名调用父类方法

Python面向对象OOP - 图17

8.父类的私有属性和方法

1.父类的私有属性和方法

  • 在子类中不能直接调用父类的私有属性和私有方法
  1. class A:
  2. def __init__(self):
  3. self.num1 = 100
  4. self.__num2 = 200
  5. def __test(self):
  6. print(f'这是A类的私有方法,{self.num1},{self.__num2}')
  7. class B(A):
  8. def demo(self):
  9. print(self.__num2,self.__test())
  10. b = B()
  11. b.demo()

Python面向对象OOP - 图18

2.通过父类的共有方法间接访问父类的私有方法和属性

  1. class A:
  2. def __init__(self):
  3. self.num1 = 100
  4. self.__num2 = 200
  5. def __test(self):
  6. print(f'这是A类的私有方法,{self.num1},{self.__num2}')
  7. def test(self):
  8. print(f'私有方法:{self.__num2}')
  9. self.__test()
  10. class B(A):
  11. def demo(self):
  12. print(f'共有属性:{self.num1}')
  13. self.test()
  14. b = B()
  15. b.demo()
  • 可以通过父类的共有方法访问父类属性和调用父类方法

Python面向对象OOP - 图19

9.多继承

1.多继承

  1. class A:
  2. def test(self):
  3. print('test方法')
  4. class B:
  5. def demo(self):
  6. print('demo方法')
  7. class C(A,B):
  8. pass
  9. c = C()
  10. c.test()
  11. c.demo()
  • 多继承使子类继承所有父类的所有属性和方法。

Python面向对象OOP - 图20

  • 若继承的多个类中的方法有重名的情况,会调用存在同名的继承的类的第一个。

2.MRO方法搜索顺序

  1. class A:
  2. def test(self):
  3. print('A----test方法')
  4. def demo(self):
  5. print('A----demo方法')
  6. class B:
  7. def test(self):
  8. print('B----test方法')
  9. def demo(self):
  10. print('B----demo方法')
  11. class C(A,B): # 继承A,B类
  12. pass
  13. c = C()
  14. c.test()
  15. c.demo()
  16. print(C.__mro__)

print(C.mro)打印一个类的MRO

Python面向对象OOP - 图21

  • 输出了一个元组,这个元组代表当对象执行一个属性或者方法时,调用的顺序,先是在自己类中查找,找不到再去第一个父类,接着第二个。

3.super()函数:调用父类的构造方法

使用super()函数,但如果涉及多继承,该函数只能调用第一个直接父类的构造方法。

Super().init会调用第一个父类的构造方法。

那如果要调用多个父类的构造方法该如何实现呢?只需要父类名.init(self)即可实现

4.新式类和经典类

objectPython 为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir 函数查看

  • 新式类:以 object 为基类的类,推荐使用

  • 经典类:不以 object 为基类的类,不推荐使用

  • Python 3.x 中定义类时,如果没有指定父类,会 默认使用 object 作为该类的 基类 —— Python 3.x 中定义的类都是 新式类

  • Python 2.x 中定义类时,如果没有指定父类,则不会以 object 作为 基类

新式类经典类 在多继承时 —— 会影响到方法的搜索顺序

  1. class A(object):
  2. pass
  3. a = A()
  4. dir(a)
  1. ['__class__',
  2. '__delattr__',
  3. '__dict__',
  4. '__dir__',
  5. '__doc__',
  6. '__eq__',
  7. '__format__',
  8. '__ge__',
  9. '__getattribute__',
  10. '__gt__',
  11. '__hash__',
  12. '__init__',
  13. '__init_subclass__',
  14. '__le__',
  15. '__lt__',
  16. '__module__',
  17. '__ne__',
  18. '__new__',
  19. '__reduce__',
  20. '__reduce_ex__',
  21. '__repr__',
  22. '__setattr__',
  23. '__sizeof__',
  24. '__str__',
  25. '__subclasshook__',
  26. '__weakref__']

上面这些都是基类object自带的方法。

10.多态

1.多态的概念

  • 多态*:不同的子类对象条用相同的父类方法,产生不同的执行结果

    • 多态可以增加代码的灵活度
    • 继承重写父类方法为前提
    • 是调用方法的技巧,不会影响到类的内部设计

2.实例

  1. class Dog:
  2. def __init__(self,name):
  3. self.name = name
  4. def game(self):
  5. print(f'{self.name}蹦蹦跳跳的玩耍!')
  6. class XiaoTianQuan(Dog):
  7. def game(self):
  8. print(f'{self.name}飞到天上去玩耍!')
  9. class Person:
  10. def __init__(self,name):
  11. self.name = name
  12. def geme_with_dog(self,dog):
  13. print(f'{self.name}和{dog.name}快乐的玩耍!')
  14. dog.game()
  15. wangcai = Dog('旺财')
  16. wangcai1 = XiaoTianQuan('飞天旺财')
  17. xiaoming = Person('小明')
  18. xiaoming.geme_with_dog(wangcai)
  19. print('='*50)
  20. xiaoming.geme_with_dog(wangcai1)
  • 可以看到针对传入不同的对象输出的结果是不一样的。

Python面向对象OOP - 图22

11.类属性

1.类属性的概念

Python中万物皆对象,类也是一个对象,class AAA()定义的称为类对象

用类创建的对象叫做实例对象。

  • 类属性就是给类对象中定义的属性
  • 通常用来记录与这个类相关的特性
  • 类属性不会用于记录具体对象的特此
  1. class Tool:
  2. # 定义类属性
  3. count = 0
  4. def __init__(self,name):
  5. self.name = name
  6. Tool.count += 1
  7. tool1 = Tool('斧头')
  8. tool2 = Tool('榔头')
  9. tool3 = Tool('水桶')
  10. print(Tool.count)

Python面向对象OOP - 图23

2.类属性的查找机制

访问类属性可以通过 类名.类属性 的方,在一定的情况下也可以通过 对象名.类属性,程序是如何做到的呢?

当实例对象访问某个属性时,会先查找是否有这个实例属性,如果找不到就会查找类属性是否有这个属性。

  1. class Tool:
  2. # 定义类属性
  3. count = 0
  4. def __init__(self,name):
  5. self.name = name
  6. Tool.count += 1
  7. tool1 = Tool('斧头')
  8. tool2 = Tool('榔头')
  9. tool3 = Tool('水桶')
  10. print(Tool.count)
  11. print(tool1.count)

Python面向对象OOP - 图24

运行结果表示: 属性名.类属性 在一定的情况下是可以实现的。

12.类方法

  • 类方法就是针对类对象定义的方法

  • 在类方法内部可以直接访问类属性或者调用其他的类方法

  • 类方法需要用装饰器修饰@classmethod来标识,告诉解释器这是一个类方法

  • 类方法的第一个参数是cls

    • 由哪一个类调用的方法,方法内的cls就是哪一个类的引用
    • 这个参数和实例方法的第一个参数是self类似
  • 通过类名.类方法名调用,调用方法时,不需要传递cls参数

  • 在方法内部

    • 可以通过cls.访问类的属性
    • 也可以通过cls.调用其他的类方法
  • 语法:
  1. @classmethod
  2. def 类方法名(cls):
  3. pass
  • 实例:
  1. class Tool:
  2. # 定义类属性
  3. count = 0
  4. def __init__(self,name):
  5. self.name = name
  6. Tool.count += 1
  7. @classmethod
  8. def show_tool_count(cls):
  9. print('工具对象的数量:',cls.count)
  10. tool1 = Tool('斧头')
  11. tool2 = Tool('榔头')
  12. tool3 = Tool('水桶')
  13. Tool.show_tool_count()

Python面向对象OOP - 图25

13.静态方法

  • 静态方法

    • 既不需要访问实例属性或者调用实例方法
    • 也不需要访问类属性或者调用类方法
  • 语法:
  1. @staticmethod
  2. def 静态方法名():
  3. pass
  • 实例:
  1. class Tool:
  2. # 定义类属性
  3. count = 0
  4. def __init__(self,name):
  5. self.name = name
  6. Tool.count += 1
  7. @classmethod
  8. def show_tool_count(cls):
  9. print('工具对象的数量:',cls.count)
  10. @staticmethod
  11. def static_method():
  12. print('这是一个静态方法')
  13. tool1 = Tool('斧头')
  14. tool2 = Tool('榔头')
  15. tool3 = Tool('水桶')
  16. Tool.show_tool_count()
  17. tool1.static_method()
  18. Tool.static_method()
  • 静态方法可以不用创建对象就可以调用,即用类名直接访问。

Python面向对象OOP - 图26

14.方法综合-案例分析

  1. class Game:
  2. top_score = 0 # 创建类属性
  3. def __init__(self,player_name): # 构造函数
  4. self.player_name = player_name
  5. @staticmethod # 创建静态方法
  6. def show_help():
  7. print('帮助信息:让僵尸进入大门!')
  8. @classmethod
  9. def show_top_score(cls): # 创建类方法
  10. print('历史最高分为:',cls.top_score)
  11. def start_game(self): # 创建实例方法
  12. print(f'{self.player_name}准备好,要开始游戏咯')
  13. Game.show_help() # 通过类名调用静态方法
  14. Game.show_top_score() # 调用类方法
  15. user1 = Game('葫芦娃') # 创建实例对象
  16. user1.start_game() # 调用实例方法

Python面向对象OOP - 图27

15.new方法

  • 使用类名()创建对象时,Python解释器首先会调用new方法为对象分配空间。
  • new是一个有object基类提供的内置的静态方法。

    • 在内存中为对象分配空间
    • 返回对象的引用
  • Python的解释器获得对象的引用后,将引用作为第一个参数,传递给init方法。

重写new方法的代码非常固定。

  • 重写new方法一定要 return super().new(cls)
  • 否则Python的解释器得不到分配空间的对象引用,就不会调用初始化方法。
  • 注意:new是一个静态方法,在调用时需要主动传递cls参数
  1. class MusicPlayer:
  2. def __new__(cls, *args, **kwargs):
  3. print('这是new方法')
  4. return super().__new__(cls)
  5. def __init__(self):
  6. print('这是初始化方法!')
  7. mp3 = MusicPlayer()
  8. print(mp3)

Python面向对象OOP - 图28

new方法重写格式如下:

  1. class Person(object):
  2. def __new__(cls):
  3. return object.__new__(cls)
  • new至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供;new必须要有返回值,返回实例化出来的实例,可以return父类new出来的实例,或直接是object的new出来的实例。

  • object.new(cls)执行完返回的结果为Person类的实例对象

  1. class Person(object):
  2. def __init__(self):
  3. print("__init__")
  4. self.name="张三"
  5. def __new__(cls):
  6. print('__new__')
  7. ob = object.__new__(cls)#obPerson实例对象
  8. print(ob)
  9. return ob
  10. p1 = Person()
  11. print(p1.name)

Python面向对象OOP - 图29

  • p1=Person()该语句主要做了以下工作:
    首先调用Person的new方法,该方法通过object.new(cls)创建了Person实例对象,并返回。最后调用了该Person实例对象的init方法。

  • object.new()方法接收的参数是类对象,可以不是当前类对象cls,如果将cls换成其他类对象会发生什么呢,看下面代码的运行结果:

  1. class Dog(object):
  2. def __init__(self):
  3. self.name="旺财"
  4. print("Dog.__init__")
  5. class Person(object):
  6. def __init__(self):
  7. self.name="张三"
  8. print("Person.__init__")
  9. def __new__(cls):
  10. print('__new__')
  11. ob = object.__new__(Dog)
  12. return ob
  13. p1 = Person()
  14. print(type(p1))

Python面向对象OOP - 图30

  • 由结果得知p1是Dog类的实例,但是有个问题,Python解释器没有自动执行init方法,由结果可以看出并没有打印字符串initnew()没有正确返回当前类cls的实例,那init()将不会被调用。

16.单例设计模式

单例 - - 让类创建的对象,在系统中只有唯一一个实例

  1. 定义一个类属性,初始值是None,用于记录单例对象的引用
  2. 重写new方法
  3. 如果类属性is none ,调用父类方法分配空间,并在类属性中记录结果
  4. 返回类属性中记录的对象引用
  1. class MusicPlayer:
  2. instance = None
  3. def __new__(cls, *args, **kwargs):
  4. if cls.instance is None:
  5. cls.instance = super().__new__(cls)
  6. return cls.instance
  7. def __init__(self,name):
  8. self.name = name
  9. m1 = MusicPlayer('m1')
  10. print(m1)
  11. print(m1.name)
  12. m2 = MusicPlayer('m2')
  13. print(m2)
  14. print(m2.name)

Python面向对象OOP - 图31

  • 根据运行结果可以得出,对象的内存地址都是一样的,并没有分配多余空间。
  • 但是初始化方法执行了多次。

若想让初始化方法只执行一次:

  1. class MusicPlayer:
  2. instance = None
  3. init_flag = False
  4. def __new__(cls, *args, **kwargs):
  5. if cls.instance is None:
  6. cls.instance = super().__new__(cls)
  7. return cls.instance
  8. def __init__(self,name):
  9. if not MusicPlayer.init_flag:
  10. print('初始化播放器')
  11. MusicPlayer.init_flag = True
  12. m1 = MusicPlayer('m1')
  13. print(m1)
  14. m2 = MusicPlayer('m2')
  15. print(m2)

Python面向对象OOP - 图32

  • 只需在类中再创建一个类属性,在初始化方法中根据这个类属性的值判断是否执行。