2012-06-04 20 views
14

Sadece sınıf tanımlarında __repr__ yöntemini ayarlamak için örnekler gördüm. __repr__ işlevlerini tanımlarında ya da tanımladıktan sonra değiştirmek mümkün mü?Python'da bir işlevin reprini değiştirmek mümkün mü?

başarı olmadan teşebbüs ettik ...

>>> def f(): 
    pass 
>>> f 
<function f at 0x1026730c8> 
>>> f.__repr__ = lambda: '<New repr>' 
>>> f 
<function __main__.f> 

cevap

14

Evet, işlevi gerçekten bir işlev olmaktan vazgeçmeye istekli iseniz.

Birincisi, yeni tip bir sınıf tanımlayın:

def withrepr(reprfun): 
    def _wrap(func): 
     return reprwrapper(reprfun, func) 
    return _wrap 

Ve şimdi fonksiyonu ile birlikte repr tanımlayabilirsiniz:

import functools 
class reprwrapper(object): 
    def __init__(self, repr, func): 
     self._repr = repr 
     self._func = func 
     functools.update_wrapper(self, func) 
    def __call__(self, *args, **kw): 
     return self._func(*args, **kw) 
    def __repr__(self): 
     return self._repr(self._func) 

bir dekoratör işlevinde Ekle

@withrepr(lambda x: "<Func: %s>" % x.__name__) 
def mul42(y): 
    return y*42 

Şimdi repr(mul42)'<Func: mul42>'

+3

Dekoratörlerin adını ve dekore edilmiş işlevlerin belgelerini güncellemek için lütfen 'functools.wraps' kullanın. – schlamar

+1

Sorun, 'print mul42 .__ name__', bir işlev için beklenmeyen bir AttributeError öğesinin yükseltilmesidir. Yani şöyle olurdu: 'geri sarma (func) (reprwrapper (reprfun, func))' bunu düzeltmek için. – schlamar

+1

@ ms4py Bu durumda, "update_wrapper" ın biraz daha uygun/dolaysız olduğunu düşünüyorum. Sarıcı sınıfını değiştirdim, böylece bunu yapıcısında yapıyor. Bu şekilde, "withrepr" dekoratörünü kullanmak yerine sınıfı doğrudan kullansanız bile güncelleme gerçekleşir. – kwatford

5

Hayır, repr(f) yerine type(f).__repr__(f) olarak yapılır çünkü.

3

Bunu yapmak için, verilen sınıf için __repr__ işlevini değiştirmeniz gerekir, bu durumda yerleşik işlev sınıfı (types.FunctionType). Python'da yerleşik sınıfları düzenleyemediğinizden, bunları yalnızca alt sınıflara ayıramazsınız.

Ancak, takip edebilecek iki yaklaşım vardır: kwatford olarak

  1. Wrap bazı işlevler
  2. Kendi repr fonksiyonu ile kendi temsil protokolünü oluşturun önerdi. Örneğin, işlev sınıfına eklenemeyen, ancak __myrepr__ yöntemlerini ilk olarak görüntüleyen myrepr işlevini tanımlayabilirsiniz, ancak önerdiğiniz gibi (özel sınıflarınızın ve nesnelerinizin yanı sıra) ayrı işlev nesnelerine ekleyebilirsiniz, ardından varsayılan olarak __myrepr__ bulunamıyorsa repr. Bunun olası uygulama olacaktır:

    def myrepr(x): 
        try: 
        x.__myrepr__ 
        except AttributeError: 
        return repr(x) 
        else: 
        return x.__myrepr__() 
    

    Sonra __myrepr__ yöntemlerini tanımlamak ve myrepr işlevini kullanabilirsiniz. Alternatif olarak, işlevinizi varsayılan repr yapmak ve repr'u kullanmaya devam etmek için __builtins__.repr = myrepr da yapabilirsiniz. Bu yaklaşım, tam olarak ne istediğinizi yapmakla bitecek olsa da, __builtins__'un düzenlenmesi her zaman istenmeyebilir.

İlgili konular