Python高级用法之元类metaclass

本文详细介绍了Python中的元类(metaclass),探讨了元类的概念,如何动态创建类,以及元类的主要用途,包括值的域限制、隐式转换、执行命名约定等。元类主要用于控制类的创建过程,通过定义元类可以实现类的定制化,如验证子类定义、添加新属性等。文中还展示了元类创建的步骤,通过案例说明了如何使用元类实现属性转换、创建API、注册子类等功能,并给出了多个实际应用场景。
摘要由CSDN通过智能技术生成

在理解元类之前,我们需要再理解一下Python中的类。在Python中,一切皆为对象,我是指所有的东西——都是对象,它们要么是类的实例,要么是元类的实例。这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类或元类创建而来。类可以实例化即创建实例对象,我们可以对实例进行赋值。同样的,类本身也是对象,即类对象。元类即是批量创建类的工厂。

  • 类也是对象

在Python中,类也是一种对象。只要使用关键字class,Python解释器在执行的时候就会创建一个类对象。我们可以对类赋值,可以增加属性,可以将它作为函数参数进行传递。例子如下:

class DemoClass(object):
    pass
def foo(obj):
    print(obj)
foo(DemoClass)

##输出:
<class '__main__.DemoClass'>
  • 动态的创建类

因为类也是对象,我们可以使用关键字class动态的创建类

def named_class(obj_name):
    if obj_name == "Demo":
        class Demo(object):
            def data(self):
                print("demo")
        return Demo  
    elif obj_name == "Test":
        class Test(object):
            def data(self):
                print("Test")
        return Test
cls_name = named_class("Demo")

print(cls_name)  # 返回的是类,不是类的实例
print(cls_name())  ##可以通过这个类创建类实例

##输出:
<class '__main__.named_class.<locals>.Demo'>
<__main__.named_class.<locals>.Demo object at 0x1043102b0>

但这还不够动态,因为仍然需要自己编写整个类的代码。

通过一个参数调用 type 时,会生成现有类的 type 信息。通过三个参数调用 type 时,会创建一个新的类对象。调用 type 时,参数是类名、基类列表以及指定类的名称空间的字典(所有字段和方法)。

type能动态的创建类。type可以接受一个类的描述作为参数,然后返回一个类。使用type定义类格式:

type(类名, 父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))

举个例子:

class TypedClass(object):
    test_attr = "test"
    def test(self):
        print("hello")

#也可以这样定义
def test():
    print("hello")
TypedClass = type('TypedClass', (object,), {"test": test})  # 函数作为类的属性
print(TypedClass) ##类对象
print(TypedClass.__dict__)
print(TypedClass().test)

##输出
<class '__main__.TypedClass'>
{'test': <function test at 0x101c62e18>, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'TypedClass' objects>, '__weakref__': <attribute '__weakref__' of 'TypedClass' objects>, '__doc__': None}
<bound method test of <__main__.TypedClass object at 0x103c1c550>>

可以看到,在Python中,类也是对象,你可以动态的创建类。这就是当你使用关键字class时Python在幕后做的事情,而这就是通过元类来实现的。

  • 元类

元类是什么

通过上文的描述,我们知道了Python中的类也是对象。元类就是用来创建这些类(对象)的,元类就是类的类,你可以这样理解为:

MyClass = MetaClass()    #元类创建
MyObject = MyClass()     #类创建实例
实际上MyClass就是通过type()来创创建出MyClass类,它是type()类的一个实例;同时MyClass本身也是类,也可以创建出自己的实例,这里就是MyObject
函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。

元类的用处:

为了当创建类时能够自动地改变类。Python中可以使用元类控制类的创建过程,类可以看作是元类创建出来的实例。我们可以通过定义元类,开控制子类的创建,例如验证子类的定义是否合法,检查子类是否实现了某些特定的方法等。

就元类本身而言,它们其实是很简单的:

1)   拦截类的创建

2)   修改类

3)   返回修改之后的类

元类主要适用于以下场合:

  • 值的域限制
  • 隐式转换自定义类的值(您可能希望向用户隐藏编写类的所有这些复杂方面)
  • 执行不同的命名约定和样式准则(比如,“每种方法都应有一个文档字符串”)
  • 向类添加新的属性

在类定义本身中定义所有这种逻辑时使用元类,主要原因就是为了避免在整个代码库中出现重复代码。

元类的作用域:

当前类中如果有__metaclass__这个属性吗,Python会在内存中通过__metaclass__创建一个类对象。如果Python没有找到__metaclass__,它会继续在(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。现在的问题就是,你可以在__metaclass__中放置些什么代码呢?

class Foo(Bar):
    pass

在该类并定义的时候,它还没有在内存中生成,知道它被调用。Python做了如下的操作:
1)Foo中有__metaclass__这个属性吗?如果是,Python会在内存中通过__metaclass__创建一个名字为Foo的类对象(我说的是类对象,请紧跟我的思路)。
2)如果Python没有找到__metaclass__,它会继续在父类中寻找__metaclass__属性,并尝试做和前面同样的操作。
3)如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
4)如果还是找不到__metaclass__,Python就会用内置的type来创建这个类对象。

怎样创建元类:

现在的问题就是,你可以在__metaclass__中放置些什么代码呢?
答案就是:可以创建一个类的东西。那么什么可以用来创建一个类呢?type,或者任何使用到type或者子类化type的东西都可以。type是python中所有类的元类。我们定义元类时,都需要继承type(或者type的子类)。

编写自定义元类分为两个步骤:

1)编写元类类型的子类。

2)使用元类挂钩将新元类插入到类创建流程中。

我们使 type 类实现子类化,并修改魔术方法,比如 __init____new____prepare__ 以及 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值