【问题标题】:Normal attributes in a class implementing getattr / setattr [duplicate]实现getattr / setattr的类中的普通属性[重复]
【发布时间】:2015-12-01 16:43:48
【问题描述】:

我有这个:

class MySession:

    def __init__(self, session):
        session['my-data'] = {}  # my data is here
        self._session = session

    def __getattr__(self, name):
        return self._session['my-data'][name]

    def __setattr__(self, name, value):
        my_data = self._session['my-data']
        my_data[name] = value
        self._session['my-data'] = my_data


obj = MySession({})
obj.x = 3

基本上我想用对象属性访问来封装对会话(子)字典的访问。但我做不到,因为这会导致无限递归,我猜是因为这样做:

self._session = session

调用setattr,后者又调用getattr,后者又调用getattr等

如何在实现 getattr / setattr 的类中预初始化一些(普通)属性?

【问题讨论】:

  • 这会导致同样的无限递归:self.session 再次调用 getattr

标签: python


【解决方案1】:

__getattr__ 方法仅对普通属性字典中不存在的属性调用。 __setattr__ 但是被无条件调用(它的镜像实际上是__getattribute__ 而不是__getattr__)。如果您可以在__init__ 中正确设置您的_session 属性,则无需担心其他方法中的任何内容。

要添加属性而不遇到任何递归,请使用super(MySession, self).__setattr__ 调用您从object 继承的方法的版本(在Python 2 中,您应该始终从object 继承,以使您的类成为新的- style 类,在 Python 3 中是默认的)。您也可以直接调用object.__setattr__,但如果您最终使用多重继承,则使用super 会更好。

class MySession(object):
    def __init__(self, session):
        session['my-data'] = {}
        super(MySession, self).__setattr__("_session", session) # avoid our __setattr__

    def __getattr__(self, name):
        return self._session['my-data'][name] # this doesn't recurse if _session exists

    def __setattr__(self, name, value):
        my_data = self._session['my-data']
        my_data[name] = value
        self._session['my-data'] = my_data

【讨论】:

  • 太好了,谢谢。关于我对 setattr 的实现:我知道这很尴尬,但这与会话在 django 中的工作方式有关:设置子键不会更新会话。这是一个常见的 django 陷阱。 docs.djangoproject.com/en/1.8/topics/http/sessions
  • TypeError: super() takes at least 1 argument (0 given)。我正在使用 python 2.7
  • 啊,由于缺少 object 作为类的基础,我假设您使用的是 Python 3。在 Python 2 中,您肯定想要这样(或者 super 无论您如何称呼它都不会起作用)。您还需要为 super 调用提供参数,因为 Python 2 的版本不能像 Python 3 那样自动推断类。我已经更新了在 Python 2 上工作的答案,并将 __setattr__ 实现恢复为您所说的方式。
【解决方案2】:

您可以先初始化,然后再更改 setter getter:

def __init__(self, session):
    session['my-data'] = {}
    self._session = session
    self.__setattr__ = self._setattr
    self.__getattr__ = self._getattr

当然假设self._setattrself._getattr 已实现:)

【讨论】:

  • 不幸的是它不起作用。 _getattr 未使用。这确实很奇怪。
猜你喜欢
  • 2015-09-19
  • 2019-07-06
  • 1970-01-01
  • 1970-01-01
  • 2015-12-26
  • 1970-01-01
  • 2014-04-05
  • 1970-01-01
  • 2013-03-11
相关资源
最近更新 更多