Dict ve collections.abc.MutableMapping birlikte alt sınıflama bir yolu var mı?


26

Örnek uğruna alt sınıf yapmak istediğimi varsayalım dict ve tüm anahtarların büyük harfle :

class capdict(dict):
    def __init__(self,*args,**kwds):
        super().__init__(*args,**kwds)
        mod = [(k.capitalize(),v) for k,v in super().items()]
        super().clear()
        super().update(mod)
    def __getitem__(self,key):
        return super().__getitem__(key.capitalize())
    def __setitem__(self,key,value):
        super().__setitem__(key.capitalize(),value)
    def __delitem__(self,key):
        super().__detitem__(key.capitalize())

Bu bir ölçüde işe yarıyor,

>>> ex = capdict(map(reversed,enumerate("abc")))
>>> ex
{'A': 0, 'B': 1, 'C': 2}
>>> ex['a']
0

ancak elbette, yalnızca uygulamayı hatırladığım yöntemler için, örneğin

>>> 'a' in ex
False

istenen davranış değildir.

Şimdi, "çekirdek" olanlardan türetilebilen tüm yöntemleri doldurmanın tembel yolu karışacaktır collections.abc.MutableMapping. Sadece burada işe yaramıyor. Sanırım söz konusu yöntemler ( __contains__örnekte) zaten tarafından sağlanmıştır dict.

Pastanı almanın ve yemenin bir yolu var mı? MutableMappingSadece geçersiz kıldığım yöntemleri görmemize izin vermek için biraz sihir mi?


Kullanmanız gerekmeyebilir MutableMapping. Bkz. Büyük / küçük harfe duyarlı olmayan sözlük .
martineau

@martineau teşekkürler, dediğim gibi sadece bir örnek oldu.
Paul Panzer

Kullanabilirsin os._Environ.
Peter Wood

Yanıtlar:


26

Ne yapabilirsin:

Bu büyük olasılıkla iyi (yani değil en temiz tasarımı) dışarı çalışmaz, ancak gelen miras alacak MutableMapping gelen daha sonra ilk ve dict saniye.

Daha sonra MutableMapping uyguladığınız yöntemleri kullanır (çünkü arama zincirinde ilk olanlar bunlar):

>>> class D(MutableMapping, dict):
        def __getitem__(self, key):
            print(f'Intercepted a lookup for {key!r}')
            return dict.__getitem__(self, key)


>>> d = D(x=10, y=20)
>>> d.get('x', 0)
Intercepted a lookup for 'x'
10
>>> d.get('z', 0)
Intercepted a lookup for 'z'
0

Daha iyi yol:

En temiz yaklaşım (anlaşılması ve test edilmesi kolaydır) sadece MutableMapping'den miras almak ve daha sonra temel veri deposu olarak (miras yerine kompozisyonla) düzenli bir dikte kullanarak gerekli yöntemleri uygulamaktır:

>>> class CapitalizingDict(MutableMapping):
        def __init__(self, *args, **kwds):
            self.store = {}
            self.update(*args, **kwds)
        def __getitem__(self, key):
            key = key.capitalize()
            return self.store[key]
        def __setitem__(self, key, value):
            key = key.capitalize()
            self.store[key] = value
        def __delitem__(self, key):
            del self.store[key]
        def __len__(self):
            return len(self.store)
        def __iter__(self):
            return iter(self.store)
        def __repr__(self):
            return repr(self.store)


>>> d = CapitalizingDict(x=10, y=20)
>>> d
{'X': 10, 'Y': 20}
>>> d['x']
10
>>> d.get('x', 0)
10
>>> d.get('z', 0)
0
>>> d['w'] = 30
>>> d['W']
30

Teşekkürler! Ben her iki emir denedim yemin edebilirim ... İlgi dışı, ben superaçık dicts için tüm s takas "yapabilirim" yöntemini kullandığınızda, o zaman lendöner dışında, iş gibi görünüyor 0. Bu nereden geliyor?
Paul Panzer

2
__Len _ () __ ' den gelen super () çağrısı mro:' da bir sonrakine gider (D, MutableMapping, dict). Bu her zaman 0 döndüren MutableMappiing .__ len __ () yöntemidir. Doğrudan çağrılması amaçlanmamıştır - her zaman geçersiz kılınması gerekir. Bu yüzden dict.__len__(self)doğrudan aramalısınız . Ve bu, "bu muhtemelen iyi sonuç vermeyecek"
dememin
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.