元类编程

属性获取

在python的类中, 如果想通过user.attr获取属性, 可以在init函数中定义, 也可以使用property装饰, 函数就相当于一个属性, attr.setter装饰器可以使用user.attr=xx来进行值的set, 注意, 如果函数名和属性名相同, 就会导致无限递归

getattribute, getattr这两个方法是寻找属性进行调用, getattribute无条件直接进入此方法, 比getatttr更优先, 是所有访问属性的入口, 因此在这里可以做更多的事情, 默认首先进入getattribute, 在发生error之前, 如果定义了getattr方法, 会进入调用, 不建议使用getattribute, 建议自行定义getattr方法来处理

属性描述符

只要实现(get, set, delete其中任何一种方法, 他都是属性描述符), 如果实现了get,set两种, 称之为数据描述符

如果user是某个类的实例(User), 那么user.age等价于getattr(user, “age”)

首先调用getattribute, 如果类也定义了getattr方法, 那么在getattribute抛出异常之前会进getattr

而对于属性描述符(get)的调用, 会发生在getattribute的内部

user = User(), 那么user.age调用顺序如下

  1. 如果age出现在User类或者其父类的dict中, 且age是数据描述符, 则会调用其get方法, 否则
  2. 如果age出现在user对象的dict中, 那么就会直接返回user.dict[“age”], 否则
  3. 如果age出现在User类或者父类的dict
  4. 1 如果是age是非数据描述符, 那么调用get方法, 否则
  5. 2 返回dict[“age”]
  6. 如果有getattr函数, 就会转入调用
  7. 抛出attributeerror异常

元类编程

在理解元类编程前, 要先理解类也是对象

object类是所有类的基类, Object是type的一个实例

type可以用来创建对象

User = type("User", (BaseClass, ), {"name":"user", "sayhello":sayhello}) # type(object_or_name, bases, dict) 类名, 继承, 属性

看以上代码, user类是由type创建的, 类名是User, 基类是BaseClass, 类里面的属性有name = “user”, 还有方法sayhello

因此我们可以让其继承自一个metaclass来动态创建类, 而metaclass也必须继承自type, 我们重写new方法, 就可以动态的控制类创建的过程, 如果一个类有metaclass, 那么实例化这个类时, 会首先进入metaclass的new方法, 携带所有参数, 然后进行逻辑处理, 最后调用父类的new方法, 转向实例类的init方法

来看这一段代码, 会发生什么

class UserMetaClass(type):
    def __new__(cls, *args, **kwargs):
        print('create:  ' + str(args[0]))
        return super().__new__(cls, *args, **kwargs)


class BaseUser(metaclass=UserMetaClass):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return "base user name:" + self.name


class User(BaseUser):
    pass


if __name__ == "__main__":
    user = User("test")
    print(user)

让我们来解释一下

  1. 扫描UserMetaclass
  2. 扫描BaseUser
  3. 带上BaseUser类的所有参数, 使用metaclass创建baseUser类, create: BaseUser
  4. 扫描User的参数
  5. 带上User类的参数, 因为他继承自BaseUser, 因此还会进入metaclass去创建User类
  6. 进入main函数
  7. 初始化user.name

文章作者: ajin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 ajin !
评论
 本篇
元类编程 元类编程
属性获取在python的类中, 如果想通过user.attr获取属性, 可以在init函数中定义, 也可以使用property装饰, 函数就相当于一个属性, attr.setter装饰器可以使用user.attr=xx来进行值的set, 注
2020-04-05
下一篇 
Protocol buffers Protocol buffers
什么是protocol buffers?protocol buffers是一个灵活的, 高性能的, 自动化的数据结构序列化机制, 就像xml, 但是更小, 更快, 更简单, 你可以定义你想要的数据结构, 然后使用特定的代码生成工具生成代码去
2020-04-03
  目录