Python中的self[name] = value是什么意思?

3

我是一名Python新手。我正在阅读基于Django的Taiga项目的代码部分。我无法理解其中的一行代码。

class Response(SimpleTemplateResponse):
    def __init__(self, data=None, status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None):
        super().__init__(None, status=status)
        self.data = data
        self.template_name = template_name
        self.exception = exception
        self.content_type = content_type

        if headers:
            for name, value in six.iteritems(headers):
                self[name] = value

我不太理解最后一行代码的含义。self[name] = value是什么意思?它创建了一个字典吗?如果是,我该如何在类外部调用或引用这个字典?如果不是,它的作用是什么?

5个回答

5
Taiga基于Django,这就是SimpleTemplateResponse的来源。它是HttpResponse的子类,也是一个类似字典的对象。
现在,循环首先检查是否有名称为headers并且不为None或False的键。如果已经设置,则假定headers是一个字典,并使用iteritems遍历字典的每个键/值对。然后,将相同的键和值复制为类的属性,使用self[name] = value
实际上,这意味着如果存在标头,则可以直接将其作为键访问该类。
以下是其操作的简单示例:
>>> class MyFoo(object):
...     def __init__(self):
...         self._data = {}
...     def __setitem__(self, a, b):
...         self._data[a] = b
...     def __getitem__(self, a):
...         return self._data[a]
...     def __delitem__(self, a):
...         del self._data[a]
...     def populate(self, d):
...        if d:
...           for k,v in d.iteritems():
...               self[k] = v
...
>>> headers = {'User-Agent': 'Python/2.7.5'}
>>> a = MyFoo()
>>> a.populate(headers)
>>> a['User-Agent']
'Python/2.7.5'

你可以看到MyFoo是一个简单的类,但它定义了一些特殊的方法__setitem____getitem____delitem__。这些方法使得该类的任何对象都可以像字典一样操作。 populate方法所做的事情与原始源代码中的循环相同;一旦运行完毕,字典的所有键都变成了结果MyFoo对象的键。
HttpResponse类的源代码中,你会注意到相同的__setitem____getitem____delitem__被定义(向下滚动到第140行)。

那么这与在类内部定义一个普通属性的字典并为其分配键/值对没有区别吗? - Captain Rib
它有点像那样,只是它添加了一些魔法方法,使得对象本身就像一个字典一样工作。 - Burhan Khalid
太棒了的例子!谢谢。 - Captain Rib

1
在Django中,HttpResponse已经被实现为一个容器(具有可通过字典访问的头部的HTTP响应类)。
更多关于容器的内容...
在Python中,可以通过实现某些魔术方法来创建容器对象。
一个用于更好理解的示例容器...
>>> class Container(object):
...     def __init__(self):
...         self.d = {}
...     def __setitem__(self, i, k):
...         print 'Setitem called for assignment!'
...         self.d[i] = k
...     def __getitem__(self, i):
...         print 'Getitem called for assignment!'
...         return self.d[i]
...     def __delitem__(self, i):
...         print 'Delitem called for assignment!'
...         del self.d[i]
... 

自从我们为赋值实现了__setitem__,为获取实现了__getitem__,为删除项目实现了__delitem__,现在Container对象支持这三种操作。
为容器对象的某个属性分配值。
>>> obj = Container()
>>> obj[1] = 'Assigned 1'
Setitem called for assignment!

当我们尝试通过调用类似于obj[--some_attr--] = value的方式将某些内容分配给该容器时,Python会检查该类的__setitem__方法,并且开发人员需要编写自己的逻辑来确定存储该值的位置,无论是字典还是其他数据结构。
从容器中检索值...
>>> obj[1]
Getitem called for retrieving!
'Assigned 1'

每当我们通过像obj[--some_attr--]这样的调用尝试从容器中检索某些内容时,Python都会检查该对象的__getitem__方法,并且开发人员需要编写自己的逻辑以返回或在其中执行某些操作。
从容器中删除值。
>>> del obj[1]
Delitem called for deleting item!

每当我们尝试通过del obj[--some_attr--]这样的方式从容器中删除某些内容时,Python会检查该对象是否有__delitem__方法...所以无论你在哪里看到self[item] = valueself[item]del self[item],都相当于在使用对象。

1

Response类实现了序列协议。这意味着它将拥有在其中定义的__setitem____getitem__魔法方法,使其表现得像任何序列或字典。


我刚刚阅读了一些关于序列协议的文章,你的回答真的帮助我很多,让我更好地理解了底层发生了什么。谢谢! - Captain Rib

0

你的SimpleTemplateResponse对象(Response的父类)将具有__getitem____setitem__方法。

我不知道从SimpleTemplateResponse继承的__getitem____setitem__方法会做什么,但我猜,在这种情况下,它将返回响应对象的属性。

本质上,你所做的是根据继承的__getitem____setitem__方法中的规则,将Response对象的特定属性设置为相应的值。

你可以在这里阅读更多。


-1
一个Python类的行为就像一个字典。 当你这样做: self["foo"] = 1234 你可以像访问self的普通属性一样访问它: print(self.foo) 对于函数也是如此。它用于动态扩展一个类。

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