Python - 如何定义不受 __getattr__ 影响的属性?

4 投票
4 回答
557 浏览
提问于 2025-04-16 23:55

我刚开始学习Python。最近在编写PHP时,我习惯了一些巧妙使用的__get__set“魔法”方法。这些方法只有在类的公共变量不存在时才会被调用。

我想在Python中实现相同的功能,但似乎一直失败。因为在Python中没有像C++或PHP那样定义类变量的方法,所以当我在类中正常使用变量(也就是通过self)时,结果却调用了__getattr__

我该如何定义我的类属性,以便不受__getattr__的影响呢?

下面是我想要实现的一些示例代码,我希望self.Documentself.Filename不会调用__getattr__

谢谢你的帮助!

class ApplicationSettings(object):
    RootXml = '<?xml version="1.0"?><Settings></Settings>'

    def __init__(self):
        self.Document = XmlDocument()
        self.Document.LoadXml(RootXml)

    def Load(self, filename):
        self.Filename = filename
        self.Document.Load(filename)

    def Save(self, **kwargs):
        # Check if the filename property is present
        if 'filename' in kwargs:
            self.Filename = kwargs['filename']

        self.Document.Save(self.Filename)

    def __getattr__(self, attr):
        return self.Document.Item['Settings'][attr].InnerText

    def __setattr__(self, attr, value):
        if attr in self.Document.Item['Settings']:
            # If the setting is already in the XML tree then simply change its value
            self.Document.Item['Settings'][attr].InnerText = value
        else:
            # Setting is not in the XML tree, create a new element and add it
            element = self.Document.CreateElement(attr)
            element.InnerText = value

            self.Document.Item['Settings'].AppendChild(element)

4 个回答

0

你这里真正需要的是一个描述符。像这样使用__getattr____setattr__并不是一个推荐的方法。

1

__getattr__ 这个方法只有在 Python 找不到某个属性的时候才会被调用,也就是说,如果这个属性不在实例本身或者它的父类里,Python 才会去用这个方法。解决这个问题的简单办法就是在类里面添加 DocumentFilename 这两个属性,这样 Python 就能找到它们了。

class ApplicationSettings(object):
    Document = None
    Filename = None
    RootXml = '<?xml version="1.0"?><Settings></Settings>'
    ...
0

看起来如果我在 __setattr__ 里检查一下属性的名字,我就可以正常调用对象的 __setattr__ 来处理我想用的属性。虽然这样做感觉有点奇怪,但确实有效。

    def __setattr__(self, attr, value):
        # Check for attributes we want to store normally
        if attr == 'Document' or attr == 'Filename':
            object.__setattr__(self, attr, value)
        # If the setting is already in the XML tree then simply change its value
        elif attr in self.Document.Item['Settings']:
            self.Document.Item['Settings'][attr].InnerText = value
        # Setting is not in the XML tree, create a new element and add it
        else:
            element = self.Document.CreateElement(attr)
            element.InnerText = value

            self.Document.Item['Settings'].AppendChild(element)

撰写回答