Bir sınıf nesnesi için özel bir dize temsili nasıl oluşturulur?


203

Bu sınıfı düşünün:

class foo(object):
    pass

Varsayılan dize gösterimi şuna benzer:

>>> str(foo)
"<class '__main__.foo'>"

Bunu özel bir dize haline nasıl getirebilirim?

Yanıtlar:


273

Uygulamak __str__()veya __repr__()sınıfın metaclass içinde.

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object):
  __metaclass__ = MC

print C

Kullanım __str__Eğer okunabilir bir stringification, kullanımı anlamına eğer __repr__kesin beyanlar.


2
Bir tür sınıf dekoratörü oluşturmak istiyorum, bu yüzden her biri için bir metasınıf yazmak zorunda kalmadan kolayca sınıflarım için özel dize gösterimleri ayarlayabilirim. Python'un metasınıflarına pek aşina değilim, o yüzden bana orada herhangi bir işaretçi verebilir misiniz?
Björn Pollex

Ne yazık ki bu sınıf dekoratörleri ile yapılamaz; sınıf tanımlandığında ayarlanmalıdır.
Ignacio Vazquez-Abrams

10
Space_C0wb0y @: Sen gibi bir dize ekleyebilirsiniz _representationsınıf gövdesine ve return self._representationiçinde __repr__()metaclass yöntemle.
Sven Marnach

@ BjörnPollex Bunu dekoratörle çekebilirsiniz, ancak dilin birçok incelikleriyle mücadele etmenizi beklerim. Ve bunu yapsanız bile, metasınıfı şu şekilde kullanmak zorundasınız çünkü __repr__temsili varsayılanı kullanmak istemiyorsunuz C. _representationÜye olmanın bir alternatifi , uygun bir metasınıf üreten bir metasınıf fabrikası oluşturmaktır __repr__(bunu çok kullanıyorsanız güzel olabilir).
Nisan'da skyking


22
class foo(object):
    def __str__(self):
        return "representation"
    def __unicode__(self):
        return u"representation"

10
Bu instances, sınıfın dize temsilini değiştirir, sınıfın kendisi için değil.
tauran

üzgünüm, yayınınızın ikinci bölümünü görmüyor. Yukarıdaki yöntemi kullanın.
Andrey Gubarev

6
@RobertSiemer Neden? Cevabı özellikle OP'nin sorusunu hedeflemese de, yine de yardımcı oluyor. Bana yardımcı oldu. Bir bakışta, örnek uygulama isteyen herhangi bir soru görmüyorum. Muhtemelen insanlar önce bu sayfaya gelirler.
akinuri

14

Eğer seçim yapmanız gerekiyorsa __repr____str__İlk uygulama veya bu uygulama için gitmeniz gerekiyorsa, tanımlanmadığı zaman varsayılan uygulama __str__çağrıları __repr__gibi.

Özel Vector3 örneği:

class Vector3(object):
    def __init__(self, args):
        self.x = args[0]
        self.y = args[1]
        self.z = args[2]

    def __repr__(self):
        return "Vector3([{0},{1},{2}])".format(self.x, self.y, self.z)

    def __str__(self):
        return "x: {0}, y: {1}, z: {2}".format(self.x, self.y, self.z)

Bu örnekte, reprdoğrudan tüketilebilen / yürütülebilen bir dize döndürürken strhata ayıklama çıktısı olarak daha kullanışlıdır.

v = Vector3([1,2,3])
print repr(v)    #Vector3([1,2,3])
print str(v)     #x:1, y:2, z:3

1
__repr__Vs __str__ile ilgili görüşünüz doğru olsa da bu, örneklerle değil, sınıf nesneleriyle ilgili asıl soruya cevap vermez.
Björn Pollex

Geri bildiriminiz için teşekkürler, tamamen denetledi. Cevabımı gözden geçireyim.
user1767754

Sanırım repr ve str uygulamaları değişti.
jspencer

4

Ignacio Vazquez-Abrams'ın onayladığı cevap oldukça doğru. Ancak Python 2 neslindendir. Şu anda geçerli olan Python 3 için bir güncelleme şöyle olacaktır:

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(object, metaclass=MC):
    pass

print(C)

Hem Python 2 hem de Python 3'te çalışan kod istiyorsanız, altı modül sizi ele alır:

from __future__ import print_function
from six import with_metaclass

class MC(type):
  def __repr__(self):
    return 'Wahaha!'

class C(with_metaclass(MC)):
    pass

print(C)

Son olarak, özel bir statik repr'ye sahip olmak istediğiniz bir sınıfınız varsa, yukarıdaki sınıf tabanlı yaklaşım harika çalışır. Ancak birkaç tane varsa, MCher birine benzer bir metasınıf oluşturmanız gerekir ve bu yorucu olabilir. Bu durumda, meta programlamayı bir adım daha ileri götürmek ve bir metasınıf fabrikası oluşturmak işleri biraz daha temiz hale getirir:

from __future__ import print_function
from six import with_metaclass

def custom_class_repr(name):
    """
    Factory that returns custom metaclass with a class ``__repr__`` that
    returns ``name``.
    """
    return type('whatever', (type,), {'__repr__': lambda self: name})

class C(with_metaclass(custom_class_repr('Wahaha!'))): pass

class D(with_metaclass(custom_class_repr('Booyah!'))): pass

class E(with_metaclass(custom_class_repr('Gotcha!'))): pass

print(C, D, E)

baskılar:

Wahaha! Booyah! Gotcha!

Metaprogramlama genellikle her gün ihtiyaç duyduğunuz bir şey değildir - ancak ihtiyacınız olduğunda, o noktaya gelir!


0

Sadece tüm güzel cevaplara ekleyerek, dekorasyonlu versiyonum:

from __future__ import print_function
import six

def classrep(rep):
    def decorate(cls):
        class RepMetaclass(type):
            def __repr__(self):
                return rep

        class Decorated(six.with_metaclass(RepMetaclass, cls)):
            pass

        return Decorated
    return decorate


@classrep("Wahaha!")
class C(object):
    pass

print(C)

stdout'u:

Wahaha!

Aşağı taraflar:

  1. CSüper bir sınıf olmadan ilan edemezsin (hayır class C:)
  2. Cörnekler garip bir türetmenin örnekleri olacaktır, bu yüzden __repr__örnekler için de a eklemek iyi bir fikir olabilir .
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.