2017-03-08 8 views
6

, bazı sihirli yöntemlerle desteği ile, bir Foo sınıfını içeren bir kütüphane kurduk Say __add__() ve __radd__() ki: 3 + foo hesaplanırken,Python'da genişletilebilir büyü yöntemleri için en iyi yöntemler var mı?

>>> class Foo(object): 
...  def __add__(self, rhs): 
...   print("Foo.__add__", rhs) 
...  def __radd__(self, lhs): 
...   print("Foo.__radd__", lhs) 
... 
>>> foo = Foo() 
>>> foo + 3 
Foo.__add__ 3 
>>> 3 + foo 
Foo.__radd__ 3 

, piton ilk type(3).__add__(3, foo) çağırır, ancak bu NotImplemented döndürür olarak, geri düşüyor type(foo).__radd__(foo, 3) için:

>>> type(3).__add__(3, foo) 
NotImplemented 

benim kütüphanenin üstünde kütüphanelerini kurmak edebilmek için geliştiriciler istiyorum, kütüphane bir sınıfiçeren demekve onların tam kontrole sahip olmasını istiyorum. Özellikle, diğer kütüphanenin foo + bar numaralı telefonun foo.__add__(bar) veya bar.__radd__(foo)'u aramasına karar vermesine izin veren bazı mekanizmalar uygulamak istiyorum.

Bu NumPy'nin bunu __array_priority__ şemasını kullanarak çözdüğünü görüyorum. Ancak bu bazı baş ağrılarına neden oluyor gibi görünüyor (bu konuyla ilgili soru ve sorunların sayısı göz önünde bulundurularak). Başka en iyi uygulamalar var mı?

+1

Bunun da mevcut sınıflarla çalışmasını istiyor musunuz? –

+0

Sorunuz oldukça ilginç olmasına rağmen, ayrıntılardan yoksundur. İstenilen davranışların farklı yönlerini çözebilir misiniz? –

cevap

1

Popüler bir seçenek LHS'nin tarafından desteklenen türlerinin bir listesini tutmak ve RHS tip listede değilse, o zaman NotImplemented dönmek:

class Foo(object): 
    SUPPORTED_TYPES = (int, Foo) 
    def __add__(self, rhs): 
     if isinstance(type(rhs), SUPPORTED_TYPES): 
      [...] # compute self + rhs 
     else: 
      return NotImplemented 

Bu iyi çalışıyor rhs akıllı alt tipi olmadığı sürece SUPPORTED_TYPES'dan biri: kontrolünü ele geçirmenin bir yolu yoktur. Ayrıca, bu şekilde listeleme türleri çok esnek değildir. Ördek kodlamaya dayanarak, kodlanmış tiplerin bir listesinden daha iyi olabilir.

1

Basit seçenek LHS (o RHS en value() yöntemini çağırır aşağıdaki örnekte) yapması gereken ve durumda onu yakalamak ve dönüş, bir özel durum ne olursa olsun yapalım çalışmaktır NotImplemented:

class Foo(object): 
    [...] 
    def __add__(self, rhs): 
     try: 
      return self._value + rhs.value() 
     except AttributeError: 
      return NotImplemented 

Basit olması gibi, SUPPORTED_TYPES'un bir listesini tutmaya gerek yoktur. Bununla birlikte, RHS'nin bu görevle ilgisi olmayan bir value() yöntemini uygulamasının bir riski vardır, bu yüzden biraz riskli olabilir. Üstelik, rhs'un sonuç üzerinde tam kontrol elde etmesinin kolay bir yolu yoktur. Python

, bu af dilemeye yerine yukarıdaki gibi, izin istemek genellikle daha iyi, ama rhsvalue() yöntemi olup olmadığını kontrol etmek tercih edilebilir:

class Foo(object): 
    def __add__(self, rhs): 
     rhs_value_func = getattr(rhs, "value", None) 
     if rhs_value_func is None: 
      return NotImplemented 
     else: 
      return self._value + rhs_value_func() 
0

Bir diğer seçenek etmektir NumPy onun __array_priority__ ile yaptığı biraz gibi __foo_priority__ gibi bir özellik kullanmak:

class Foo(object): 
    __foo_priority__ = 0 
    def __add__(self, rhs): 
     delegate = True 
     try: 
      rhs_prio = type(rhs).__foo_priority__ 
      delegate = (self.__foo_priority__ < rhs_prio) 
     except AttributeError: 
      delegate = True 
     if delegate: 
      return NotImplemented 
     else: 
      return self.value_ + rhs.value() 

Bu seçenek biraz daha karışık, ama oldukça esnektir. Bu seçeneğe sahip tek (küçük) sorun, fazladan bir özniteliğe sahip olması için rhs'un türünü gerektirdiğinden, bu öznitelik olmadan mevcut bir türse rhs denetimini vermenin bir yolu yoktur.