zoukankan      html  css  js  c++  java
  • Python的元类

    1、用元类验证子类

    每当我们定义新类的时候,元类就会运行雅正代码,以确保这个新类符合规定的规范。
    Python系统把子类的class语句处理完毕,就会调用元类的 __new__ 方法。元类可以通过 __new__ 方法,获取子类、孙子类的名称,父亲及属性。
    这样使得我们不需要将验证代码放在本类 __init__ 方法中,等到构建对象再验证。

    下例中,定义一个边数小于3的子类,class语句一结束,元类的验证代码就会拒绝这个class。

    class ValidatePolygon(type):
        def __new__(meta, name, bases, class_dict):
            # Don't validate the abstract Polygon class
            if bases != (object,):
                if class_dict['sides'] < 3:
                    raise ValueError('Polygons need 3+ sides')
            return type.__new__(meta, name, bases, class_dict)
    
    class Polygon(object, metaclass=ValidatePolygon):
        sides = None  # Specified by subclasses
    
        @classmethod
        def interior_angles(cls):
            return (cls.sides - 2) * 180
    
    class Triangle(Polygon):
        sides = 3
    
    print(Triangle.interior_angles())
    
    

    2、用元类注册子类

    每次从基类中继承子类时,基类的元类都可以自动运行注册代码。
    这在需要反向查找 ‘reverse lookup’ 时很有用,使得在简单标识符和对应的类之间,建立映射关系。
    依然利用的是class语句执行完,自动调用元类的 __new__ 方法。

    import json 
    
    registry = {}
    
    def register_class(target_class):
        registry[target_class.__name__] = target_class
    
    def deserialize(data):
        params = json.loads(data)
        name = params['class']
        target_class = registry[name]
        return target_class(*params['args'])
    
    
    class Meta(type):
        def __new__(meta, name, bases, class_dict):
            cls = type.__new__(meta, name, bases, class_dict)
            register_class(cls)
            return cls
    
    
    class Serializable(object):
        def __init__(self, *args):
            self.args = args
    
        def serialize(self):
            return json.dumps({
                'class': self.__class__.__name__,
                'args': self.args,
            })
    
        def __repr__(self):
            return '%s(%s)' % (
                self.__class__.__name__,
                ', '.join(str(x) for x in self.args))
    
    
    class RegisteredSerializable(Serializable, metaclass=Meta):
        pass
    
    
    class Vector3D(RegisteredSerializable):
        def __init__(self, x, y, z):
            super().__init__(x, y, z)
            self.x, self.y, self.z = x, y, z
    
    
    v3 = Vector3D(10, -7, 3)
    print('Before:    ', v3)
    data = v3.serialize()
    print('Serialized:', data)
    print('After:     ', deserialize(data))
    
    print(registry)
    

    3、用元类注解类的属性

    使用元类像是在 class 语句上放置了挂钩,class语句处理完毕,挂钩就会立刻触发。
    下列中借助元类设置了 Filed.nameFiled.name

    class Field(object):
        def __init__(self):
            # These will be assigned by the metaclass.
            self.name = None
            self.internal_name = None
            
        def __get__(self, instance, instance_type):
            if instance is None: return self
            return getattr(instance, self.internal_name, '')
    
        def __set__(self, instance, value):
            setattr(instance, self.internal_name, value)
    
    
    class Meta(type):
        def __new__(meta, name, bases, class_dict):
            for key, value in class_dict.items():
                if isinstance(value, Field):
                    value.name = key
                    value.internal_name = '_' + key
            cls = type.__new__(meta, name, bases, class_dict)
            return cls
    
    
    class DatabaseRow(object, metaclass=Meta):
        pass
    
    
    class BetterCustomer(DatabaseRow):
        first_name = Field()
        last_name = Field()
        prefix = Field()
        suffix = Field()
    
    
    foo = BetterCustomer()
    print('Before:', repr(foo.first_name), foo.__dict__)
    foo.first_name = 'Euler'
    print('After: ', repr(foo.first_name), foo.__dict__)
    

    元类总结就到这里,自己也没有完全理解清楚。
    希望对此有深刻理解的pythoner留言。

    代码来自:https://github.com/bslatkin/effectivepython

  • 相关阅读:
    jperf windows
    Eclipse+Maven命令创建webapp项目<三>
    Eclipse+Maven创建webapp项目<二>
    Eclipse+Maven创建webapp项目<一>
    在java中定义有几种类加载器
    JAVA创建对象有哪几种方式 ?
    js创建对象的几种常用方式小结(推荐)
    maven安装以及eclipse配置maven
    MyEclipse 10.0安装及激活步骤
    jdk下载网址
  • 原文地址:https://www.cnblogs.com/lidyan/p/7157227.html
Copyright © 2011-2022 走看看