我能否只部分覆盖__setattr__方法?

5

我正在模仿ConfigParser模块的行为,编写一个高度专业化的解析器,利用特定应用程序配置文件中一些明确定义的结构。这些文件遵循标准的INI结构:

[SectionA]
key1=value1
key2=value2

[SectionB]
key3=value3
key4=value4

对于我的应用程序,各个部分基本上是不相关的;不同部分的键之间没有重叠,所有用户只记得键名,从来不知道它们应该放在哪个部分。因此,我想在我创建的MyParser类中覆盖__getattr____setattr__,以允许像这样的快捷方式:

config = MyParser('myfile.cfg')
config.key2 = 'foo'
__setattr__ 方法首先尝试查找名为 key2 的部分并将其设置为 'foo'(如果存在)。假设没有这样的部分,则会在每个部分内查找名为 key2 的键。如果该键存在,则将其设置为新值。如果不存在,则解析器最终会引发 AttributeError
我已经构建了一个测试实现,但问题是我还想让一些纯属性免于此行为。我希望 config.filename 是一个简单的字符串,包含原始文件的名称,并且 config.content 是保存每个部分字典的字典。
有没有一种干净的方法在构造函数中设置 filenamecontent 属性,使它们避免被我的自定义 getter 和 setter 忽略?Python 会在调用自定义的 __setattr__ 之前在对象的 __dict__ 中查找属性吗?
2个回答

7

文件名内容传递给超类来处理它

class MyParser(object):
    def __setattr__(self, k, v):
        if k in ['filename', 'content']:
            super(MyParser, self).__setattr__(k, v)
        else:
                # mydict.update(mynewattr) # dict handles other attrs

我不喜欢在__setattr__方法中维护这些“特殊”属性的想法。看起来我可以在构造函数中使用你的super构造定义它们,之后获取它们就可以正常工作了;print config.filename会得到正确的结果。然而,设置属性却行不通,因为它会降入自定义的__setattr__并最终抛出错误。为什么Python在获取时捕获属性,但在设置时却没有呢? - Jeff Klukas
1
如果您不想在__setattr__中定义它们,那么您可以定义一个类属性(例如MyParser.specials而不是文字列表),但代码的流程是相同的。至于为什么获取操作有效,那不就是因为这些示例中没有定义__getattr__吗? - Cartroo
@Cartroo,我实际上是在参照我自己进行的一些测试,我确实实现了那些方法。结果发现,这是因为我复制了__getattr__逻辑,其中return语句结束了代码执行,而在__setattr__中,这些return语句现在设置变量而不会结束执行。所以我感知到的差异是我的错误,而不是基本的Python行为。 - Jeff Klukas

2
我认为以类似于字典的接口呈现文件内容会更加清晰,而将属性访问留给内部使用。不过这只是我的个人意见。
回答你的问题,__setattr__() 在检查 __dict__ 之前被调用,因此你可以实现它类似于以下代码:
class MyParser(object):

    specials = ("filename", "content")

    def __setattr__(self, attr, value):
        if attr in MyParser.specials:
            self.__dict__[attr] = value
        else:
            # Implement your special behaviour here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接