【问题标题】:Allow super to control __setattr__ on subclasses允许 super 控制子类上的 __setattr__
【发布时间】:2016-03-13 12:17:53
【问题描述】:

这个问题是关于基于super() 的对象的只读问题,以及是否/如何超级可以/应该控制子类上的__setattr__

上下文:

有没有办法编写 元类descriptor 使得作为包含属性 self.read_only = True 的类的子类的所有类都不能执行子类化getattr 以“set_”开头的函数,但self.read_only = False 可以在哪里?

我在想 object.__setattr__(self, name, value) 的覆盖:

在尝试进行属性分配时调用。这就是所谓的 而不是正常的机制(即将值存储在实例中 字典)。 name 是属性名称,value 是要成为的值 分配给它。

...是正确的方向,但我怀疑我对文档的解释是否正确。

示例:

Super 符合系统设计者的意图:

class BaseMessage(object):
    def __init__(self, sender, receiver, read_only=True):
        self.sender = sender
        self.receiver = receiver
        self.read_only = read_only

    def __setattr__(self, name, value):
        if self.read_only:
            raise AttributeError("Can't set attributes as message is read only.")
        else:
            # ? set attribute...(suggestion welcome)

    def get_sender(self):  # Is a "get" and not "set" call, so it should be callable disregarding self.read_only's value.
        return self.sender

    def get_receiver(self):
        return self.receiver

由对所有后果了解有限的系统扩展器制作:

class MutableMessage(BaseMessage):
    def __init__(self, sender, receiver, topic, read_only=False):
        super().__init__(sender=sender, receiver=receiver, read_only=read_only)
        self.topic = topic

    # this call should be okay as super's property is read_only=False.
    def set_topic_after_init(new_topic):
        self.topic = topic

class ImmutableMessage(BaseMessage):
    def __init__(self, sender, receiver, topic):  # read_only=True !
        super().__init__(sender=sender, receiver=receiver, read_only=read_only)
        self.topic = topic

    # this call should fail as super's property is read_only=True.
    def set_topic_after_init(new_topic):  
        self.topic = topic

示例说明

MutableMessage 中,系统扩展程序明确声明 read_only 为 False,并且知道添加函数 set_topic 的后果。

ImmutableMessage(下)中,系统扩展程序忘记声明消息应该是read_only=False,这应该导致supers __setattr__raise AttributeError

核心问题: 下面示例中所示的用法是否足以一致地应用于基于 BaseMessage 类的所有类?

认为我是元编程的新手。因此,对我的示例的任何误解和/或扩展和更正的解释将是至高无上的。我了解hierarchy [1],但不了解python在继承过程中在幕后做了什么。

谢谢...

[1]:层次结构

Python 用于属性的搜索顺序如下:

  1. __getattribute____setattr__
  2. 数据描述符,如属性
  3. 来自对象__dict__的实例变量
  4. 非数据描述符(如方法)和其他类变量
  5. __getattr__

由于__setattr__ 排在第一位,如果你有一个,你需要让它变得聪明,除非你想让它处理你班级的所有属性设置。它可以通过两种方式中的任何一种变得聪明。

一个。使其仅处理特定的集合属性,或者,

b.让它处理除某些属性之外的所有属性。

如果您不希望它处理,请致电super().__setattr__

相关问题:

【问题讨论】:

    标签: python-3.x inheritance setattr


    【解决方案1】:

    这有点工作:

    class BaseMessage(object):
        def __init__(self, sender, receiver, read_only=True):
            self._sender = sender
            self._receiver = receiver
            self.read_only = read_only
    
        def __setattr__(self, name, value):
            # Have to use gettattr - read_only may not be defined yet.
            if getattr(self,"read_only",False):
                raise AttributeError("Can't set attributes as message is read only.")
            else:
                self.__dict__[name] = value
    
        def get_sender(self):    # Is a "get" and not "set" call, so it should be callable 
            return self._sender  # disregarding self.read_only's value.
    
        def get_receiver(self):
            return self._receiver
    
    
    class ImmutableMessage(BaseMessage):
        def __init__(self, sender, receiver, topic):  # read_only=True !
            # Have to make it read-write to start with
            super().__init__(sender=sender, receiver=receiver, read_only=False)
            # ... so we can set the topic
            self.topic = topic
            # Now make it read-only
            self.read_only = True
    
        # this call should fail as super's property is read_only=True.
        def set_topic_after_init(self,new_topic):  
            self.topic = new_topic
    
    • 设置属性很容易(只需设置__dict__)。
    • 显然,这一切都不会阻止有人故意覆盖__setattr__
    • 最大的缺点是您必须将子类创建为读写,以便您可以首先创建属性,然后将其标记为只读。我想不出一种自动化的方法。
      • 您可以将super.__init__ 调用设为派生__init__ 中的最后一个调用 - 但这感觉不太自然。
      • 或者,__setattr__ 可以遍历堆栈并发现它是否是从 __init__ 调用的 - 但这感觉很麻烦。

    【讨论】:

      猜你喜欢
      • 2018-10-13
      • 1970-01-01
      • 1970-01-01
      • 2014-04-13
      • 1970-01-01
      • 1970-01-01
      • 2014-10-12
      • 1970-01-01
      • 2019-07-09
      相关资源
      最近更新 更多