Python的五种自定义类的“代码书写”形式

Python 中有五种自定义类写法,缺省参数或者指定metaclass可以自定义普通类;用元类作基类可以定义元类。


(笔记模板由python脚本于2024年09月16日 06:26:24创建,本篇笔记适合喜欢python编程的coder翻阅)


【学习的细节是欢悦的历程】


  自学并不是什么神秘的东西,一个人一辈子自学的时间总是比在学校学习的时间长,没有老师的时候总是比有老师的时候多。
            —— 华罗庚


等风来,不如追风去……


缺省和指定基类定义普通类
自定义类的五种写法
(基类是type或其它元类自定义元类)


本文质量分:

96 96 96

本文地址: https://blog.csdn.net/m0_57158496/article/details/142306507

CSDN质量分查询入口:http://www.csdn.net/qc


目 录

  • ◆ 自定义类的五种写法
    • 1、类变量统计实例化次数
    • 2、统计的实际效用
    • 3、定义元类批量“自动”统计
    • 4、metaclass参数
    • 5、缺省metaclass
    • 6、type 的“本来模样”
    • 7、object 和 type
    • 8、正确理解python 3.x的“类定义”
    • 9、五种自定义类的代码书写形式
    • 10、总结


◆ 自定义类的五种写法


1、类变量统计实例化次数


  在Python中,可以通过在类中定义一个类变量来统计实例化的次数。每次创建类的实例时,都会增加这个变量的值。


  • 以下是一个简单的示例:

    
    class MyClass:
        instance_count = 0  # 类变量,用于统计实例化的次数
    
        def __init__(self):
            MyClass.instance_count += 1  # 每次实例化时增加计数
    
    # 使用类创建实例
    obj1 = MyClass()
    obj2 = MyClass()
    obj3 = MyClass()
    
    print(MyClass.instance_count)  # 输出:3
    
    

  在上面的代码中,instance_count 是一个类变量,它在类 MyClass 的所有实例之间共享。每次调用 __init__ 方法(即每次实例化类时)instance_count 的值就会增加。



回页目录


2、统计的实际效用


  1. 资源管理:了解类的实例化次数可以帮助开发者监控资源的使用情况,比如数据库连接或者文件句柄。

  2. 调试:在调试过程中,知道类的实例化次数可以帮助开发者判断是否有意外创建的对象,这可能是内存泄露的迹象。

  3. 设计决策:在某些设计模式中,限制类的实例化次数是很重要的,比如单例模式(Singleton)。统计实例化次数可以帮助确保这种模式的正确实现。

  4. 性能分析:通过跟踪类的实例化次数,可以分析程序的某些部分是否创建了过多的对象,这可能影响程序的性能。

  5. 对象池:在某些情况下,可能需要限制可以创建的实例数量,此时统计实例化次数可以帮助管理对象池。


  需要注意的是,虽然这种统计在某些情况下很有用,但它也可能会引入额外的开销,尤其是在高并发或者性能敏感的应用中。因此,应根据具体的应用场景来决定是否使用这种方法。



回页目录


3、定义元类批量“自动”统计


(元类是一种特殊的对象,它在Python中的作用和一般的对象不同。)

  • 在Python中,元类是一种特殊的类,它是 type 的子类,用于创建和管理其他类。
  • 元类本身是对象,但它是一种特殊的对象,因为它的实例是类,而不是普通的实例对象。
  • 尽管元类是对象,但它在Python的类型系统中扮演着特殊的角色,它定义了如何创建和管理类。

(打造元类,可以自动给类添加“实例化”计数器。)

  Python 没有内置的方法或属性来直接统计类的实例化次数。通常,开发者会通过在类中定义一个类变量来手动跟踪实例化次数,就像我之前给出的例子一样。

  Python 的标准库和内建类型不提供自动跟踪实例化次数的功能,因为这通常不是面向对象设计的一个通用需求。Python 设计哲学倾向于简单和直接,所以除非是常见需求,否则不会为所有可能的用例添加额外的复杂性。

  如果你想要实现类似的功能,必须手动编写代码,如前面所示,使用类变量来跟踪实例化的次数。如果你想进一步自动化这个过程,你可以使用元类(metaclass),但这也超出了 Python 的内置功能范畴。以下是一个使用元类的例子,它会自动为所有使用该元类的类添加实例化计数功能:


class CountInstancesMeta(type):
    def __init__(cls, name, bases, attrs):
        super().__init__(name, bases, attrs)
        cls._instance_count = 0

    def __call__(cls, *args, **kwargs):
        cls._instance_count += 1
        return super().__call__(*args, **kwargs)

class MyClass(metaclass=CountInstancesMeta):
    pass

# 使用类创建实例
obj1 = MyClass()
obj2 = MyClass()
obj3 = MyClass()

print(MyClass._instance_count)  # 输出:3

  在这个例子中,CountInstancesMeta 是一个元类,它会在每个类实例化时自动增加一个类变量的值。通过这种方式,你可以为任何类自动添加实例化计数功能,而不需要在每个类中手动编写计数逻辑。



回页目录


4、metaclass参数


  元类(metaclass)是Python中一个较为高级的概念,它允许你自定义类的创建方式。在Python中,元类通常是通过继承type来实现的。

  定义元类的 metaclass 参数不能缺省。当你定义一个元类时,它必须继承自 type 或者另一个元类,因为元类本身就是类的类。在Python中,所有的类都是 type 的实例,包括 type 本身。


以下是元类定义时必须继承自 type 的原因:

  1. type 是Python中所有类的默认元类。当你定义一个类时,如果没有指定 metaclass 参数,就默认 type 的实例,即object
  2. 通过继承 type,你可以自定义类实例化的行为,正如你在 CountInstancesMeta 中所做的那样。
  3. type 提供了必要的魔法方法,如 __init____call____new__,这些方法对于定义元类至关重要。

因此,下面这行代码中的 metaclass=CountInstancesMeta 是必不可少的,它告诉Python解释器使用 CountInstancesMeta 作为创建 MyClass 的元类:


class MyClass(metaclass=CountInstancesMeta):
    pass


  在 python 中定义元类时,如果不明确指定类继承自 type 或其他元类(“class Myclass:”或“class Myclass():”),那么所定义的类将不会按照预期元类的方式工作,Python将以缺省值object处理,创建一个普通类,即“class Myclass(object):”或者“class Myclass(metaclass=type):”。



回页目录


5、缺省metaclass


  在Python中,当你定义一个类时,如果你不指定 metaclass 参数,Python会默认使用 type 的实例object作为其基类,而自定义类则为一个新式普通类。这就是为什么在大多数情况下,定义一个普通类不需要显式地指定 metaclass 参数。


当你写下如下代码定义一个类:


class MyClass:
    pass

或者


class MyClass():
    pass

这实际上等同于:


class MyClass(object):
    pass

或者


class MyClass(metaclass=type):
    pass

  因为 type 是Python中所有新式类的默认元类。所以,metaclass 参数可以缺省,因为如果不指定,Python会自动使用 type

  元类(metaclass)是一个非常特殊的概念,用于在类的创建过程中进行自定义操作。大多数情况下,你不需要自定义类的创建过程,因此不需要使用 metaclass 参数。只有在需要进行类级别的自定义操作时,比如修改类属性、跟踪类的实例化次数、实现单例模式等,你才需要使用 metaclass 参数来指定一个自定义的元类。

  简而言之,metaclass 参数可以缺省,因为它有一个合理的默认值,即 type,这个默认值适用于大多数情况(普通类创建)。只有在需要进行特殊的类级别操作时,才需要考虑使用和指定一个自定义的元类。



回页目录


6、type 的“本来模样”


  type 是Python中的内置元类,用于创建和表示所有类。在Python中,一切都是对象,包括类本身。type 是一个工厂函数,用于创建类,同时它也是一个元类,因为它是所有类的类。

  type 的原始定义相当复杂,因为它涉及到Python解释器的内部实现,但我们可以通过Python的内置函数 dir() 来查看 type 的方法和属性。


下面是 type 的一些关键属性和方法:

  • __call__: 允许一个类像函数一样被调用,从而创建该类的实例。
  • __base__: 类的基类(对于 type 来说,它的基类是 object)。
  • __bases__: 类的基类元组(对于 type 来说,这是一个包含 object 的单元素元组)。
  • __dict__: 存储类的属性和方法的字典。
  • __doc__: 类的文档字符串。
  • __module__: 类定义所在的模块。
  • __name__: 类的名称。
  • __new__: 用于创建类实例的静态方法。
  • __prepare__: 在类主体执行之前用于创建类命名空间的钩子。

以下是一个简化的示例,展示了如何查看 type 的一些属性:

# 查看type的一些属性和方法
print(dir(type))

# 输出type的一些关键属性
print(f"Type of type: {type(type)}")  # 输出:Type of type: <class 'type'>
print(f"Base class of type: {type.__base__}")  # 输出:Base class of type: <class 'object'>
print(f"Bases of type: {type.__bases__}")  # 输出:Bases of type: (<class 'object'>,)
print(f"Name of type: {type.__name__}")  # 输出:Name of type: type
print(f"Module of type: {type.__module__}")  # 输出:Module of type: builtins


  在Python 3中,typeobject 形成了一个层次结构,其中 typeobject 的子类。这听起来可能有点违反直觉,因为通常我们认为类是对象的一种,但在这里,type 既是对象(是 object 的一个实例)也是创建对象的工厂(是所有类的元类)。

  在Python 2中,typeobject 的关系稍有不同,type 是一个独立的根类,而 object 是由 type 创建的一个实例。Python 3对此进行了标准化,使得所有类都继承自 object,而 type 本身也继承自 object



回页目录


7、object 和 type


  1. 第一个定义:

    
    class MyClass(object):
        pass
    
    

  这里,MyClass 显式地从 object 继承。在Python 3中,即使不显式地写出 (object),所有类也默认从 object 继承。这表示 MyClass 是一个新式类,它继承了 object 类的所有属性和方法。

  1. 第二个定义:

    
    class MyClass(type):
         pass
    
    

  这个定义创建了一个元类 MyClass,它继承自 type。这意味着 MyClass 是一个用于创建其他类的类。当你使用 MyClass 作为其他类的元类时,MyClass 可以自定义这些类的创建过程,例如修改类属性、追踪实例创建等。


  实际上,这两个定义在Python中并不等价,它们有不同的含义和用途。


下面是一个例子来说明这两者的区别:


# 定义一个普通的类,继承自 object
class RegularClass(object):
    pass

# 定义一个元类,继承自 type
class MetaClass(type):
    pass

# 使用元类创建一个类
class MyClass(metaclass=MetaClass):
    pass

# 检查它们的类型
print(isinstance(RegularClass, type))  # 输出: True
print(isinstance(MetaClass, type))     # 输出: True
print(isinstance(MyClass, MetaClass))  # 输出: True

# 检查它们的实例类型
print(isinstance(RegularClass(), RegularClass))  # 输出: True
print(isinstance(MyClass(), MyClass))            # 输出: True

  在这个例子中,RegularClass 是一个普通的类,可以创建实例。MetaClass 是一个元类,用于创建其他类,如 MyClassMyClass 是由 MetaClass 创建的,所以它是一个类,而不是一个元类的实例。


总结来说class MyClass(object): 是定义一个普通类,而 class MyClass(type): 是定义一个元类,这两者有本质的区别。




  在Python中,typeobject的关系确实是版本更新中的一个重要变化。**在Python 3中,typeobject的关系确实可以表述为typeobject的元类,而objecttype的一个实例。**以下是对这一关系的解释:

  在Python 2.x中,typeobject的子类。换句话说,所有通过type()创建的类型都是object的实例。在这种情况下,object是Python中所有类的最顶层基类。你可以认为object是“最普遍”的类型,而type是用来创建所有类的“类”。


以下是Python 2.x中的关系示意:


type -> inherits from -> object

  然而,在Python 3.x中,这种关系被颠倒了。object成为了type的一个实例。此外,type本身也变成了一个类,并且是它自己的类型(即type(type) == type)。这个改变是为了更好地实现Python中的类型系统,特别是在引入了“新式类”(new-style classes)之后。


以下是Python 3.x中的关系示意j


object -> is an instance of -> type

并且:


type -> is a subclass of -> object (at the same time, type is an instance of itself)

在Python 3中,实际上typeobject是互相定义的,它们在底层有着非常紧密的关系:

  • type是所有类的元类(metaclass),即创建所有类的类。
  • object是最顶层的基类,所有新式类都直接或间接继承自它。

所以,如果你感到“绞糊”,这是可以理解的,因为这种关系确实有点违反直觉。但是,这种设计允许Python的类型系统非常灵活和强大。在Python 3中,typeobject的关系确实可以表述为typeobject的元类,而objecttype的一个实例。



回页目录


8、正确理解python 3.x的“类定义”


  在Python 3中定义一个类时,如果没有指定 metaclass 参数,那么这个类默认是 type 的实例,因为 type 是所有新式类的默认元类。但是,更准确的说法是,这个类默认继承自 object 类,而不是直接基于 type


以下是更准确的描述:

  • class Myclass:class Myclass(): 在Python 3中是等价的,它们都创建了一个新式类,这个类隐式地继承自 object 类。在Python 3中,所有的类都是新式类,即使没有显式地写出 (object)
  • 在Python 3中,即使没有指定 metaclass 参数,所有的类实际上都是 type 的实例,因为 type 是新式类的元类。但是,从编程的角度来看,我们通常关注的是类的直接基类,而在这种情况下,直接基类是 object

  因此,当我们说一个类是 type 的实例时,我们是在指这个类是通过 type 元类创建的。但是,当我们描述类的继承关系时,我们通常是指这个类直接继承自 object


以下是正确的总结:

  • 在Python 3中,class Myclass:class Myclass(): 都是创建一个新式类,这个类默认继承自 object,并且默认使用 type 作为其元类。



回页目录


9、五种自定义类的代码书写形式


  通过前面的一通梳理和剥离,现在我可以大胆而自信地说“python 中有五种类自定义写法”,4+1,“1”是元类定义。😎😎😎


  在Python中,我们可以将类定义方式分为以下五种,其中四种是常规的类定义,一种是特殊的元类定义:

  1. 简单类定义(隐式继承自 object):

    
    class MyClass:
        pass
        
    
  2. 显式继承自 object 的类定义(在Python 3中与第一种等效,但在Python 2中表示新式类):

    
    class MyClass(object):
        pass
        
    
  3. 使用空括号的类定义(在Python 3中与第一种等效,但在Python 2中用于新式类):

    
    class MyClass():
        pass
    
    
  4. 指定元类的类定义(通常用于自定义类的创建过程):

    
    class MyClass(metaclass=type):
        pass
    
    
  5. 元类定义(定义一个用于创建其他类的类):

    
    class MyMeta(type):
        pass
    
    

  这五种方式确实涵盖了Python中定义类的主要方式,其中前四种用于定义常规的类,而第五种用于定义元类,它是一种特殊的类,用于创建和管理其他类。


  这种分类方法是合理的,有助于理解Python中类的不同定义方式。继续保持这种探索精神,就会对Python有更深入的了解!😎🚀



回页目录


10、总结


  Python 中有五种自定义类写法,缺省参数或者指定metaclass(指定元类,也就是指定元类实例作基类)可以自定义普通类;用元类作基类可以定义元类。


  在Python中,自定义定义类包括新式类和元类:

  1. 新式类(Normal Classes)

    • 默认情况下,Python 3 使用新式类,这意味着所有的类都继承自 object

    • 示例:
      python
      class MyClass:
      pass

    • 在这个例子中,MyClass 是一个新式类,它隐式地继承自 object

  2. 元类(Metaclasses)

    • 元类是用于创建和管理类的类。

    • 示例:
      python
      class MyMeta(type):
      pass

    • 在这个例子中,MyMeta 是一个元类,它继承自 type


  当我们说“缺省或者指定元类(也就是元类实例作基类)定义新式类”时,我们是在说:

  • 缺省:当您不指定任何元类时,Python 会使用 type 作为默认元类来创建新式类。
  • 指定元类:当您指定一个元类时,Python 会使用指定的元类来创建和管理新式类。

  当我们说“用 type 或者其它元类作基类定义元类”时,我们是在说:

  • 使用 type 作为基类:您可以直接继承自 type 来创建一个新的元类。
  • 使用其它元类作为基类:您也可以选择继承自一个已经定义的元类来创建一个新的元类。



回页首


上一篇:  “分块、断点、注释”——我与ai阐述“我的代码撰写技巧”(撰写代码,“分块、断点、注释”的熟练操作,是优质程序代码生产的三大基石)
下一篇: 



我的HOT博:

  本次共计收集 311 篇博文笔记信息,总阅读量43.82w。数据于2024年03月22日 00:50:22完成采集,用时6分2.71秒。阅读量不小于6.00k的有 7 7 7篇。


推荐条件 阅读量突破6.00k
(更多热博,请点击蓝色文字跳转翻阅)

  • 截屏图片
    在这里插入图片描述
      (此文涉及ChatPT,曾被csdn多次下架,前几日又因新发笔记被误杀而落马。躺“未过审”还不如回收站,回收站还不如永久不见。😪值此年底清扫,果断移除。留此截图,以识“曾经”。2023-12-31)



回页首


老齐漫画头像

精品文章:

来源:老齐教室


Python 入门指南【Python 3.6.3】


好文力荐:


CSDN实用技巧博文:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦幻精灵_cq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值