__Getitem__ yöntemini anlama


140

__getitem__Python belgelerindeki belgelerin çoğunu inceledim, ancak hala anlamını kavrayamıyorum.

Yani tek anlayabildiğim, bunun __getitem__gibi çağrıları uygulamak için kullanıldığı self[key]. Ama bunun faydası nedir?

Diyelim ki şu şekilde tanımlanmış bir python sınıfım var:

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"])

Bu beklendiği gibi sonuçları döndürür. Ama neden __getitem__ilk etapta kullanalım ? Python'un __getitem__dahili olarak aradığını da duydum . Ama bunu neden yapıyor?

Lütfen birisi bunu daha detaylı açıklayabilir mi?


Bu bir örnek kullanım için ilgi çekici olabilir: Nasıl düzgün alt sınıf dict ve geçersiz kılma GetItem & setItem
roganjosh

4
__getitem__Sizin örnekte kullanımı anlamda bir sürü yapmak, ancak kullanımları bu kodu mevcut çalışmak zorunda olduğu, özel bir listesi-ya sözlük benzeri sınıfına yazmaya gerek hayal etmez []. Bu __getitem__yararlı olduğu bir durum .
Pieter Witvoet

Yanıtlar:


158

Cong Ma, neyin __getitem__kullanıldığını açıklamakta iyi bir iş çıkarıyor - ama size yararlı olabilecek bir örnek vermek istiyorum. Bir binayı modelleyen bir sınıf hayal edin. Binaya ilişkin verilerin içinde, her kattaki şirketlerin açıklamaları da dahil olmak üzere bir dizi öznitelik içerir:

Kullanmadan __getitem__şöyle bir sınıfımız olur:

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) )

Bununla birlikte , Yapı sınıfının kullanımını 'daha güzel' hale getirmek için __getitem__(ve onun muadilini __setitem__) kullanabiliriz.

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] )

Bu şekilde kullanıp kullanmamanız __setitem__gerçekten verilerinizi nasıl soyutlamayı planladığınıza bağlıdır - bu durumda bir binayı bir kat konteyneri olarak ele almaya karar verdik (ayrıca Bina için bir yineleyici ve hatta belki de dilimleme yeteneği de uygulayabilirsiniz. - yani, bir seferde birden fazla katın verilerini elde edin - bu, neye ihtiyacınız olduğuna bağlıdır.


15
Sadece cevabı birkaç kez okuduktan sonra öğrendiğim bir şeyi paylaşmak için: bir getitem'e sahip olduğunuzda, bu işlevi açıkça çağırmanız gerekmez. O aradığında building1[2], kendi içinde getitem'i çağırır. Dolayısıyla, @ tony-suffolk-66'nın ortaya koyduğu nokta, sınıfın herhangi bir özelliğinin / değişkeninin çalışma süresi boyunca basitçe nesne adı [variablename] çağrısı ile geri getirilebileceğidir. Başlangıçta benim için net olmadığı için bunu açıklığa kavuşturmak ve birisine yardımcı olacağını umarak buraya yazmak. Gereksizse lütfen silin
mithunpaul

3
@mithunpaul nesne [dizin] gösterimi, bir sınıfın özelliğini / değişkenini / özniteliğini almak için kullanılmaz - bir konteyner nesnesinde dizin oluşturur - örneğin, ebeveynin alt öğelerinin bir listesini tuttuğu bir ebeveynden bir alt nesneyi almak gibi. Örneğimde - Building sınıfı bir konteynerdir (bu durumda Kat adları), ancak Kat sınıfları için bir konteyner sınıfı olabilir.
Tony Suffolk 66

Desteklememesi dışında len()ve bir alacaksınız TypeError:TypeError: object of type 'Building' has no len()
Ciasto piekarz

Örneğimin amacı len'i (ve yineleme vb. Gibi diğer özellikleri) desteklemek değildi. Bir dunder_len yöntemi uygulamak önemsizdir.
Tony Suffolk 66

@ TonySuffolk66: ____len____, örneğinizde hangi ____getitem____ döngüsünde indeks (katlar) için yinelenebilir olduğunu belirlediği için bu doğru mu?
Alex

73

[]Anahtar veya dizin tarafından öğeyi almak için sözdizimi sadece sözdizimi şekerdir.

a[i]Python çağrılarını değerlendirdiğinizde a.__getitem__(i)(veya type(a).__getitem__(a, i), ancak bu ayrım kalıtım modelleriyle ilgilidir ve burada önemli değildir). Sınıfı abu yöntemi açıkça tanımlamasa bile, genellikle bir üst sınıftan miras alınır.

Tüm (Python 2.7) özel yöntem adları ve bunların anlambilimleri burada listelenmiştir: https://docs.python.org/2.7/reference/datamodel.html#special-method-names


8

Sihirli yöntem __getitem__temel olarak liste öğelerine, sözlük girişlerine, dizi öğelerine vb. Erişmek için kullanılır. Örnek özniteliklerinin hızlı bir şekilde aranması için çok kullanışlıdır.

Burada bunu 'ad', 'yaş' ve 'dob' (doğum tarihi) ile somutlaştırılabilen örnek bir Kişi sınıfı ile gösteriyorum. __getitem__Yöntem böyle vb ad veya soyadı, gün, ay veya dob yılı olarak endeksli örnek özelliklerini, erişebileceği bir şekilde yazılır

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

Bir kullanıcı girişinin aşağıdaki gibi olduğunu varsayalım:

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

__getitem__Yöntem yardımı ile kullanıcı indekslenmiş özniteliklere erişebilir. Örneğin,

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

Harika örnek! Ben nasıl uygulanacağına ilişkin her yerinde arıyordu getItem birden parametreler varken init ve ben düzgün şekilde uygulanmasını bulup nihayet bu gördüğümüz için mücadele oldu! Olumlu oy verildi ve teşekkür ederim!
Rahul P
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.