类属性、类方法、静态方法、单例

类的结构

术语一 实例

使用面向对象开发,1是设计类

使用 类名()创建对象,创建对象的动作有两步:

在内存中为对象分配空间

调用初始化方法__init__为对象初始化

创建对象后,内存中就有了一个对象的实实在在的存在一实例

 

因此,通常也会把:

1.创建出来的对象叫做实例

2.创建对象的 动作 叫做 实例化

3.对象的属性 叫做 实例属性

4.对象调用的方法 叫做 实例方法

在程序执行时

1.对象各自拥有自己的 实例属性

2.调用对象方法,可以通过 self

访问自己的属性

调用自己的方法

结论

每一个对象,都有自己独立的内存空间,保存各自不同的属性

多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用,传递到方法内部

类是一个特殊的对象

Python中一切皆对象:

class AAA:定义的类属于类对象

obj1=AAA()属于实例对象

在程序运行时,同样会被加载到内存

在python中,是一个特殊的对象一类对象

在程序运行时,类对象 在内存中 只有一份,使用一个类可以创建出很多个对象实例

除了封装实例 属性 方法 外,类对象可以拥有自己的属性 方法

1.类属性

2.类方法

通过类名.的方式可以访问类的属性或者调用类的方法

 

类属性和实例属性

概念和使用

类属性 就是给 类对象中定义的 属性

通常用来记录与这个类相关的特征

类属性不会用于记录具体对象的特征

示例需求

定义一个工具类

每件工具都有自己的name

需求--知道使用这个类,创建了多少个工具对象

 

"""
定义一个工具类
每件工具都有自己的
name---->实例属性
需求
--知道使用这个类,创建了多少个工具对象----》类属性
"""
class Tools(object):
    count = 0 #类属性,用来描述这个类创建了多少个实例

    def __init__(self,name):#初始化方法,是用来给对象(实例赋予属性值的)
        self.name = name   #实例属性

        #通过这个类创建多少个对象,做一个计数count
        #思路:每创建一个对象,就会调用一次__init__(self)方法,每调用一次__init__,就对count做一个+1的操作
        Tools.count += 1


tool1=Tools("斧子")  #创建实例
too12=Tools("匕首")
tool3 =Tools("工兵铲")

print(Tools.count)#输出通过类创建的对象数

类的获取机制

python中属性的获取存在一个向上查找机制

 

因此,要访问类属性有两种方式:

1.类名.类属性

2.对象.类属性(不推荐)

注意

如果使用对象类.属性=赋值语句,只会给对象添加一个属性,而不会影响到类属性的值

class Tools(object):
    count = 0 #类属性,用来描述这个类创建了多少个实例

    def __init__(self,name):#初始化方法,是用来给对象(实例赋予属性值的)
        self.name = name   #实例属性

        #通过这个类创建多少个对象,做一个计数count
        #思路:每创建一个对象,就会调用一次__init__(self)方法,每调用一次__init__,就对count做一个+1的操作
        Tools.count += 1


tool1=Tools("斧子")  #创建实例
too12=Tools("匕首")
tool3 =Tools("工兵铲")

print(Tools.count)#输出通过类创建的对象数
print(tool1.count)#注意:count属性,是Tools这个类的,但是可以被实例访问
print(id(tool1.count),id(Tools.count)) #2061306888496 2061306888496

tool1.count = 100 #该定义方式,只是给Tool1增加了一个属性count,增加了一个tool1.count的内存空间
                # 而不会改变类属性的值
print(id(tool1.count),id(Tools.count)) #2061306888496 2061306888496

print(Tools.count)  #---->3

 

类方法

类属性就是针对类对象定义的属性

使用 赋值语句 在class 关键字 下方可以定义 类属性

类属性 用于记录与这个类相关的特征

类方法 就是记录与这个类相关的方法

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

语法如下

@classmethod

def method_name(cls):

pass

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

类方法的 第一个参数 应该是cls

哪一个类 调用的方法,方法内的cls就是哪一个类的引用

这个参数和 实例方法的第一个参数和self类似

提示使用其他名称也可以,不过习惯使用cls

通过类名,调用类方法调用方法时,不需要传递cls参数

在方法内部

可以通过 cls,访问类的属性

也可以通过cls调用其他的类方法

示例需求

定义一个工具类

每件工具都有自己的name

需求--------在封装一个show_tool_count的类方法,输出使用当前这个类,创建的对象个数

class Tools(object):
    count = 0

    def __init__(self,name):
        self.name = name
        Tools.count += 1


    #创建类方法
    @classmethod
    def show_tool_count(cls):
        print(f"目前创建了{cls.count}个,工具实例了!")#类方法内部,访问了类属性
        #print(self.name)#类方法内部,不能访问实例属性,也不能调用实例方法
tool1 = Tools("burpsuit")
tool2 = Tools("冰蝎")

Tools.show_tool_count()

 

 

在类方法内部,可以直接使用cls访问类属性或者调用类方法

静态方法

在开发时,如果需要在中封装一个方法,这个方法:

不需要访问实例属性或者调用实例方法

不需要访问类属性或者调用类方法

这个时候,可以把这个方法封装成一个静态方法

语法如下

@staticmethod

def  static_name():

pass

静态方法

静态方法 需要用修饰器 @staticmethod来标识,告诉解释器这是一个静态方法

通过类名,调用静态方法

class Dog:
    def __init__(self):
        self.name = "旺财"

    @staticmethod
    def run():
        """
       
定义了一个静态方法 静态方法不需要访问实例属性,也不需要调用实例方法
                        静态方法不需要访问类属性 也不需要访问调用类方法
       
:return:
        """

       
print("狗跑了...")

wangcai = Dog() #根据类创建实例
wangcai.run()

 

案例

  1. 设计一个 Game
  2. 属性
  3. 定义一个 类属性 top_score 记录游戏的 历史最高分
  4. 定义一个 实例属性 player_game 记录 当前游戏的玩家姓名
  5. 方法
  6. 静态方法 show_help 显示游戏帮助信息
  7. 类方法 show_top_score 显示历史最高分
  8. 实例方法 start_game 开始当前玩家的游戏
  9. 主程序步骤
  10. 查看帮助信息
  11. 查看历史最高分
  12. 创建游戏对象,开始游戏

import random
class Game(object):
    top_score = 0  #
类属性,用来记录历史最高分,默认为0

    def __init__(self, name):  #
实例属性 ,通过__init__进行实例化
       
self.player_name = name

    @staticmethod  #
静态方法
   
def show_help():
        print("
欢迎来到猜数字游戏。。。。")

    @classmethod
    def show_top_score(cls):  #
类方法 ,访问了 类属性
       
print(f"当前历史最高分是{cls.top_score}")

    def start_game(self):  #
实例方法
       
print(f"{self.player_name}进入了游戏。。。。")
        #
开始游戏,产生了分数
       
Game.top_score = random.randint(50, 1000)
        print(f"{self.player_name}
在游戏中获得了{Game.top_score}")


Game.show_help()
Game.show_top_score()
xiaoming = Game("
小明。。。")
xiaoming.start_game()

Game.show_top_score()

 

案例小结

1.实例方法---方法内部需要访问 实例属性

实列方法 内部口以使用类名. 访口类属性

2.类方法----方法内部只需要访问类属性或其他类方法

3.静态方法-方法内部,不需要访问 例属性和 类属性

单例 设计模式

设计模式

设计模式 前人工作的总结和提炼,通常,被人们广泛流传的设计都是针对 某一特定问题 的成熟的方案

使用 设计模式  是为了可重用代码、让代码更容易被他人理解、保证代码可靠性

单例 设计模式

目的 创建的对象,在系统中只有 唯一的一个实例

每一次执行 类名( ) 返回的对象,内存地址是相同的

单例设计模式的应用场景

音乐播放 对象

回收站 对象

打印机 对象

……

__new__ 方法

使用 类名( ) 创建对象时,Python 的解释器 首先会 调用 __new__ 方法为对象分配空间

__new__ 是一个 object 基类提供的内置的静态方法,是要作用有两个:

在内存中为对象分配空间

返回对象的引用

Python 的解释器获得对象的引用后,将引用作为第一个参数,传递给 __init__方法

重写 __new__ 方法的代码非常固定!

重写 __new__ 方法 一定要 return super().__new__(cls),用来返回对象的引用

否则 Python 的解释器得不到分配了空间的对象引用就不会调用对象的初始化方法

注意: __new__ 是一个静态方法,在调用时需要 主动传递 cls 参数

 

定义 MusicPlayer( ) 类,实例化对象

class MusicPlayer(object):
    def __init__(self):
        print("
播放器初始化")

#
创建播放器对象
play = MusicPlayer()
print(play)

 

重写 new 方法,验证new方法的作用和工作过程

class MusicPlayer(object):
    #
重写new方法
   
def __new__(cls):
        #1.
创建对象时,new方法会被自动调用
       
print("创建对象,分配空间")
        #2.
为对象分配空间
       
instance = super().__new__(cls)
        #3.
返回对象的引用
       
return  instance

    def __init__(self):
        print("
播放器初始化")

#
创建播放器对象
play = MusicPlayer()
print(play)

 

Python 中的单例

单例 创建的对象,在系统中只有唯一的一个实例à 保证 引用 的唯一性

定义一个 类属性,初始值是 None ,用于记录单例对象的引用

重写 __new__ 方法

如果类属性 is None,调用父类方法:__new__ 分配空间,并在类属性中记录结果

返回类属性中记录的对象引用

 

Python 中的单例

class MusicPlayer(object):
    pass
player1 = MusicPlayer()
print(player1)

player2 = MusicPlayer()
print(player2)

class MusicPlayer(object):
    #
记录第一次创建对象的引用
   
instance = None
    #
改进new方法
   
def __new__(cls,*args,**kwargs):
        #
判断类属性是否是空对象
       
if cls.instance is None:
            #
如果对象没有被创建,调用父类的方法,为第一个对象分配空间
           
cls.instance = super().__new__(cls)
        #
返回属性保存的对象引用
       
return cls.instance


player1 = MusicPlayer()
print(player1)

player2 = MusicPlayer()
print(player2)

 

 

只执行一次初始化工作

在每次使用 类名( ) 创建对象时,Python 的解释器都会自动调用两个方法:

__new__ 分配空间

__init__ 对象初始化

在对 __new__ 方法改造后,每次都会得到第一次被创建对象的引用

但是:初始化方法还会被再次调用

需求: 让初始化动作只被执行一次

class MusicPlayer(object):
    instance = None  # instance
设置为初始值 None,如果 创建过对象,
   
# 也就是 调用过 new方法了, instance 的值就不是 None

   
init_flag = False  # 定义一个初始值,用于标记 __init__方法,没有被再次执行

   
def __new__(cls, *args, **kwargs):  # 重写__new__方法
       
if cls.instance is None:  # 如果 之前没有执行过 new方法,则 cls.instance is None
            cls.instance = super().__new__(cls)  #
将 内存id 赋值给 cls.instance
        return cls.instance  #
重写 new方法后,将 内存 id 返回

   
def __init__(self):
        if MusicPlayer.init_flag == True:
            return
        print("
播放器初始化")
        MusicPlayer.init_flag = True


player1 = MusicPlayer()
player2 = MusicPlayer()
print(id(player1))  #
多个实例  2918561262816引用 是通过 __new__返回的
print(id(player2))

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值