3

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

语境:

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

我认为覆盖object.__setattr__(self, name, value)

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

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

例子:

正如系统设计者期望的那样:

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(下)中,系统扩展程序忘记声明 message 应该是 read_only=False这应该导致supers __setattr__to raise AttributeError

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

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

谢谢...

[1]:层次结构

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

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

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

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

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

对于您不希望它处理的那些,请致电super().__setattr__.

相关问题:

4

1 回答 1

0

这有点工作:

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
  • 设置属性很容易(只需 set __dict__)。
  • 显然,这一切都不会阻止有人考虑压倒一切__setattr__
  • 最大的缺点是您必须将子类创建为读写,以便您可以首先创建属性,然后将其标记为只读。我想不出一种自动化的方法。
    • 您也许可以将super.__init__调用作为派生中的最后一个调用__init__- 但这感觉不太自然。
    • 或者,__setattr__可以遍历堆栈并发现它是否被调用__init__- 但这感觉很麻烦。
于 2016-03-13T17:08:27.197 回答