详细讲解Python中的元类及其用法


本文摘自php中文网,作者巴扎黑,侵删。

1、用元类验证子类

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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__ 方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

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留言。

代码来自:

以上就是详细讲解Python中的元类及其用法的详细内容,更多文章请关注木庄网络博客!!

相关阅读 >>

Python中spyder怎么安装

Python终端会话是什么

Python复制中对象生命周期如何使用

tuple和list中,为什么只有前者才可以作为字典的key?

Python print怎么换行

Python lambda怎么用

Python file truncate() 方法是什么?能用在什么地方?

Python list删除元素时要注意的坑点

Python中print什么意思

正则表达式以及Python re库的使用

更多相关阅读请进入《Python》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...