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

发布于 2024-11-30 05:59:01 字数 1504 浏览 2 评论 0原文

我对 Python 还很陌生。最近,在进行大量 PHP 编程时,我习惯了一些创造性地使用 __get 和 __set“神奇”方法。仅当类的公共变量不存在时才会调用它们。

我试图在 Python 中复制相同的行为,但似乎失败了。鉴于似乎没有办法以 C++/PHP 方式实际定义类变量,当我尝试在类中正常使用变量(即通过 self)时,它最终会调用 __getattr__ !

如何定义我不希望受到 __getattr__ 影响的类属性?

下面是我想要做的一些示例代码,我在其中希望 self.Document 和 self.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)

I'm fairly new to Python. In programming a lot of PHP recently I got used to some creative use of __get and __set "magic" methods. These were only called when a public variable of the class wasn't present.

I'm trying to replicate the same behavior in Python, but seem to be failing miserably. Given there doesn't seem to be a way to actually define class variables in a C++/PHP way, when I try to use variables normally within my class (i.e. via self) it ends up calling __getattr__!

How do I define attributes of my class that I don't want affected by __getattr__?

Some sample code of what I'm trying to do is below, where I'd want self.Document and self.Filename NOT to invoke __getattr__.

Thanks for the help!

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

表情可笑 2024-12-07 05:59:01

仅当 Python 在实例本身或其任何基类中找不到该属性时,才会调用 __getattr__ 。简单的解决方案是将 DocumentFilename 添加到类中,以便找到它。

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

__getattr__ is only invoked when Python cannot find the attribute in the instance itself or in any of its base classes. The simple solution is to add Document and Filename to the class so it is found.

class ApplicationSettings(object):
    Document = None
    Filename = None
    RootXml = '<?xml version="1.0"?><Settings></Settings>'
    ...
忘东忘西忘不掉你 2024-12-07 05:59:01

这里你真正需要的是一个描述符。像这样挂钩 __getattr__ 和 __setattr__ 并不是真正推荐的方法。

What you really need here is a descriptor. Hooking __getattr__ and __setattr__ like that is not really recommended method.

夜空下最亮的亮点 2024-12-07 05:59:01

我会使用属性。使用@property装饰器使它看起来更好。

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

然后您可以访问Cx,它会自动调用x的getter,并在您分配给Cx时自动调用x的setter。

I would use Properties. Using the @property decorator makes it looks even nicer.

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

You can then access C.x and it will automatically call the getter for x, and automatically call the setter for x when you assign to C.x.

请你别敷衍 2024-12-07 05:59:01

显然,如果我检查 __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)

Apparently if I check for the attribute name in __setattr__ I can then call object's __setattr__ for the attributes I want to use normally. This feels pretty hoaky, but works.

    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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文