【问题标题】:How to trigger a setter when declaring a class property?声明类属性时如何触发setter?
【发布时间】:2019-05-02 21:51:19
【问题描述】:

我有课;我们称之为Foo。它有一个key_type 类属性,其中包含一个类型:

class Key: pass

class Foo:
  key_type = Key

我想在键类型被初始化(*)时以及它发生变化时对其运行一些方法。

所以我在元类中创建了key_type 一个属性:

class Key: pass
class OtherKey: pass

class MetaFoo(type):
  _key_type = None

  @property
  def key_type(cls):
    return cls._key_type

  @key_type.setter
  def key_type(cls, value):
    print(f'Setting key_type to {value}')
    cls._key_type = value

class Foo(metaclass=MetaFoo):
  key_type = Key

if __name__ == "__main__":
  print(f"Foo's key type: {Foo.key_type}")
  Foo.key_type = OtherKey
  print(f"Foo's key type: {Foo.key_type}")

输出:

Foo's key type: None
Setting key_type to <class '__main__.OtherKey'>
Foo's key type: <class '__main__.OtherKey'>

似乎元类中_key_type 的定义覆盖了主类中key_type 的定义。但最重要的是,没有使用 Key 类型调用 setter。

预期输出:

Setting key_type to <class '__main__.Key'>
Foo's key type: <class '__main__.Key'>
Setting key_type to <class '__main__.OtherKey'>
Foo's key type: <class '__main__.OtherKey'>

(*) 我也希望它在初始化时发生的原因是 Foo 可以继承自。我想知道(在 MetaFoo 或 Foo 中)子类是否使用不同的 key_type

【问题讨论】:

  • 请注意,类主体分配给一个临时类命名空间。您可能想检查提供给 type.__prepare__ 命名空间的键是否实际分配,而不仅仅是复制。
  • 确实; key_type 的初始分配发生在元类的实例(即您的类Foo拥有属性之前。您只是分配了一个名称,该名称将在调用元类后成为属性。

标签: python


【解决方案1】:

class Fookey_type的定义实际上是在第三个参数(即dict)中添加了一个key-value对,用于MetaFoo的初始化,其他什么都不会。

因此,您可以操纵MetaFoo 的初始化来显式调用您的setter 方法。这可以通过覆盖元类的 __init__ 方法来完成:

class Key: pass
class OtherKey: pass

class MetaFoo(type):
  _key_type = None

  @property
  def key_type(cls):
    return cls._key_type

  @key_type.setter
  def key_type(cls, value):
    print(f'Setting key_type to {value}')
    cls._key_type = value

  def __init__(self, name, bases, kw):
    super(MetaFoo, self).__init__(name, bases, kw)
    for key, val in kw.items():
       setattr(self, key, val)


class Foo(metaclass=MetaFoo):
  key_type = Key

if __name__ == "__main__":
  print(f"Foo's key type: {Foo.key_type}")
  Foo.key_type = OtherKey
  print(f"Foo's key type: {Foo.key_type}")

输出:

Setting key_type to <class '__main__.Key'>
Foo's key type: <class '__main__.Key'>
Setting key_type to <class '__main__.OtherKey'>
Foo's key type: <class '__main__.OtherKey'>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多