了解__getitem__方法


138

我已经阅读了__getitem__Python文档中的大多数文档,但仍然无法理解它的含义。

因此,我所能理解的__getitem__就是用于实现类似的调用self[key]。但是它有什么用?

可以说我以这种方式定义了一个python类:

class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __getitem__(self,key):
        print ("Inside `__getitem__` method!")
        return getattr(self,key)

p = Person("Subhayan",32)
print (p["age"])

这将返回预期的结果。但是为什么要__getitem__首先使用?我还听说过Python __getitem__内部调用。但是为什么要这样做呢?

有人可以详细解释一下吗?


这可能是一个有趣的示例用法:如何正确地将dict子类化并覆盖getitemsetitem
roganjosh

4
__getitem__您的示例中的用法没有多大意义,但请想象您需要编写一个自定义列表或字典类的类,该类必须与使用的现有代码一起使用[]。在这种情况下__getitem__很有用。
Pieter Witvoet

Answers:


157

马聪(Cong Ma)很好地解释了__getitem__用途-但我想举一个可能有用的示例。想象一个为建筑物建模的类。在建筑物数据中,它包含许多属性,包括对占据每个楼层的公司的描述:

如果不使用,__getitem__我们将有一个像这样的类:

class Building(object):
     def __init__(self, floors):
         self._floors = [None]*floors
     def occupy(self, floor_number, data):
          self._floors[floor_number] = data
     def get_floor_data(self, floor_number):
          return self._floors[floor_number]

building1 = Building(4) # Construct a building with 4 floors
building1.occupy(0, 'Reception')
building1.occupy(1, 'ABC Corp')
building1.occupy(2, 'DEF Inc')
print( building1.get_floor_data(2) )

但是,我们可以使用__getitem__(及其对应的__setitem__)来使用Building类“ nicer”。

class Building(object):
     def __init__(self, floors):
         self._floors = [None]*floors
     def __setitem__(self, floor_number, data):
          self._floors[floor_number] = data
     def __getitem__(self, floor_number):
          return self._floors[floor_number]

building1 = Building(4) # Construct a building with 4 floors
building1[0] = 'Reception'
building1[1] = 'ABC Corp'
building1[2] = 'DEF Inc'
print( building1[2] )

是否__setitem__像这样使用,实际上取决于您计划如何抽象化数据-在这种情况下,我们决定将建筑物视为楼层的容器(并且您还可以为建筑物实现迭代器,甚至可以实现切片功能-即一次获取多个楼层的数据-这取决于您的需求。


15
只是分享我多次阅读答案后才学到的知识:一旦有了一个getitem,就不必显式调用该函数。当他调用时building1[2],内部调用本身称为getitem。因此,@ tony-suffolk-66的意义在于,可以在运行时通过简单地调用objectname [variablename]来检索该类的任何属性/变量。只是澄清一下,因为起初我还不清楚,所以在这里写下来希望对大家有所帮助。如果有多余,请删除
mithunpaul

3
@mithunpaul object [index]表示法不用于获取类的属性/变量/属性-它在容器对象上进行索引-例如从父级检索子级对象,而父级在其中维护其子级列表。在我的示例中-Building类是一个容器(在这种情况下为Floor名称),但它可能是Floor类的容器类。
托尼·萨福克

除非它不支持len(),你会得到一个TypeErrorTypeError: object of type 'Building' has no len()
Ciasto piekarz

支持len(以及其他功能,例如迭代等)并不是我的示例的目的。不过,实现dunder_len方法很简单。
托尼·萨福克

@ TonySuffolk66:在您的____getitem____循环的示例中,____ len____确定索引(底数)的可迭代性是否正确?
亚历克斯

73

[]通过键或索引获取项目的语法仅仅是语法糖。

在评估a[i]Python调用时a.__getitem__(i)(或type(a).__getitem__(a, i),但是这种区别是关于继承模型的,在这里并不重要)。即使的类a可能未明确定义此方法,它也通常是从祖先类继承的。

此处列出了所有(Python 2.7)特殊方法名称及其语义:https : //docs.python.org/2.7/reference/datamodel.html#special-method-names


8

magic方法__getitem__基本上用于访问列表项,字典条目,数组元素等。它对于快速查找实例属性非常有用。

在这里,我用一个示例类Person来显示这一点,该类可以通过“名称”,“年龄”和“出生日期”(出生日期)实例化。该__getitem__方法以一种可以访问索引实例属性的方式编写,例如,名字或姓氏,日期,日期,月份或年份等。

import copy

# Constants that can be used to index date of birth's Date-Month-Year
D = 0; M = 1; Y = -1

class Person(object):
    def __init__(self, name, age, dob):
        self.name = name
        self.age = age
        self.dob = dob

    def __getitem__(self, indx):
        print ("Calling __getitem__")
        p = copy.copy(self)

        p.name = p.name.split(" ")[indx]
        p.dob = p.dob[indx] # or, p.dob = p.dob.__getitem__(indx)
        return p

假设一个用户输入如下:

p = Person(name = 'Jonab Gutu', age = 20, dob=(1, 1, 1999))

借助__getitem__方法,用户可以访问索引属性。例如,

print p[0].name # print first (or last) name
print p[Y].dob  # print (Date or Month or ) Year of the 'date of birth'

很好的例子!当init中有多个参数时,我到处都在搜索如何实现getitem,而我一直在努力寻找合适的实现,最后看到了这一点!赞了,谢谢!
Rahul P
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.