python - الفرق بين__str__ و__repr__؟




magic-methods (14)

ما الفرق بين __str__ و __repr__ في بايثون؟

__str__ (قراءة كـ "dunder (double-underders)") و __repr__ (قراءة كـ "dunder-repper" (لـ "represent")) كلاهما أساليب خاصة تقوم بإرجاع سلاسل استنادًا إلى حالة الكائن.

يوفر __repr__ سلوكًا احتياطيًا إذا كان __str__ مفقودًا.

لذا يجب أولاً كتابة __repr__ الذي يسمح لك بإعادة إنشاء كائن مكافئ من السلسلة التي ترجعها باستخدام eval أو بكتابتها في حرف حرف في غلاف Python.

في أي وقت لاحق ، يمكن للمرء كتابة __str__ لتمثيل سلسلة يمكن للمستخدم قراءته للمثيل ، عندما يعتقد المرء أنه ضروري.

__str__

إذا قمت بطباعة كائن أو تمريره إلى format أو str.format أو str ، إذا تم تعريف طريقة __str__ ، فسيتم استدعاء هذه الطريقة ، وإلا سيتم استخدام __repr__ .

__repr__

يتم __repr__ الأسلوب __repr__ بواسطة __repr__ وما هو صدى على shell python الخاص بك عندما يقوم بتقييم تعبير يقوم بإرجاع كائن.

نظرًا لأنه يوفر نسخة احتياطية لـ __str__ ، إذا كان يمكنك كتابة واحدة فقط ، فابدأ بـ __repr__

إليك المساعدة repr في repr :

repr(...)
    repr(object) -> string

    Return the canonical string representation of the object.
    For most object types, eval(repr(object)) == object.

بمعنى ، بالنسبة لمعظم الكائنات ، إذا قمت بكتابة ما تتم repr بواسطة repr ، فيجب أن تتمكن من إنشاء كائن مكافئ. لكن هذا ليس التنفيذ الافتراضي.

التنفيذ الافتراضي لـ __repr__

الكائن الافتراضي __repr__ هو ( مصدر C Python ) شيء مثل:

def __repr__(self):
    return '<{0}.{1} object at {2}>'.format(
      self.__module__, type(self).__name__, hex(id(self)))

ويعني ذلك افتراضياً أنك ستقوم بطباعة الوحدة التي ينتمي إليها الكائن ، واسم الفئة ، والتمثيل السداسي العشري لموقعها في الذاكرة - على سبيل المثال:

<__main__.Foo object at 0x7f80665abdd0>

هذه المعلومات ليست مفيدة للغاية ، ولكن لا توجد طريقة لاشتقاق كيف يمكن للمرء أن ينشئ بدقة تمثيلًا قانونيًا لأي مثيل معين ، وأنه أفضل من لا شيء ، على الأقل يخبرنا كيف يمكننا التعرف عليه بشكل فريد في الذاكرة.

كيف يمكن أن يكون __repr__ مفيدًا؟

دعونا ننظر إلى مدى الفائدة التي يمكن أن تكون ، وذلك باستخدام بيثون قذيفة وكائنات datetime . نحتاج أولاً إلى استيراد وحدة datetime :

import datetime

إذا datetime.now في shell ، فسنشاهد كل شيء نحتاجه لإعادة إنشاء كائن datetime مكافئ. يتم إنشاؤه من قبل datetime __repr__ :

>>> datetime.datetime.now()
datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)

إذا قمنا بطباعة كائن تاريخ / وقت ، فإننا نرى تنسيقًا سهل القراءة (في الواقع ، ISO). يتم تنفيذ ذلك بواسطة __str__ من datetime:

>>> print(datetime.datetime.now())
2015-01-24 20:05:44.977951

إنها مسألة بسيطة لإعادة إنشاء الكائن الذي فقدناه لأننا لم __repr__ لمتغير من خلال النسخ واللصق من إخراج __repr__ ، ومن ثم طباعته ، وحصلنا عليه في نفس الناتج البشري __repr__ للقراءة مثل الكائن الآخر:

>>> the_past = datetime.datetime(2015, 1, 24, 20, 5, 36, 491180)
>>> print(the_past)
2015-01-24 20:05:36.491180

كيف أقوم بتنفيذها؟

أثناء التطوير ، ستحتاج إلى إعادة إنتاج الكائنات في الحالة نفسها ، إن أمكن. هذا ، على سبيل المثال ، هو كيف يعرف الكائن datetime __repr__ ( مصدر Python ). إنه معقد إلى حد ما ، بسبب كل السمات اللازمة لإعادة إنتاج مثل هذا الكائن:

def __repr__(self):
    """Convert to formal string, for repr()."""
    L = [self._year, self._month, self._day, # These are never zero
         self._hour, self._minute, self._second, self._microsecond]
    if L[-1] == 0:
        del L[-1]
    if L[-1] == 0:
        del L[-1]
    s = ", ".join(map(str, L))
    s = "%s(%s)" % ('datetime.' + self.__class__.__name__, s)
    if self._tzinfo is not None:
        assert s[-1:] == ")"
        s = s[:-1] + ", tzinfo=%r" % self._tzinfo + ")"
    return s

إذا كنت تريد أن يكون للكائن تمثيل أكثر قابلية للقراءة ، فيمكنك تنفيذ __str__ next. في ما يلي كيفية تنفيذ الكائن datetime ( مصدر Python ) __str__ ، والذي يمكن استخدامه بسهولة لأنه يحتوي بالفعل على وظيفة لعرضه بتنسيق ISO:

def __str__(self):
    "Convert to string, for str()."
    return self.isoformat(sep=' ')

تعيين __repr__ = __str__ ؟

هذا هو نقد لإجابة أخرى هنا تشير إلى وضع __repr__ = __str__ .

الإعداد __repr__ = __str__ سخيفة - __repr__ هو احتياطي لـ __str__ __repr__ كتابة __repr__ ، المكتوبة لاستخدام المطورين في تصحيح الأخطاء ، قبل كتابة __str__ .

تحتاج إلى __str__ فقط عندما تحتاج إلى تمثيل نصي للكائن.

استنتاج

قم بتعريف __repr__ للكائنات التي تكتبها بحيث يكون لك __repr__ الآخرين مثالًا يمكن إعادة إنتاجه عند استخدامه أثناء تطويره. قم بتعريف __str__ عندما تحتاج إلى تمثيل سلسلة بشرية يمكن قراءتها.

ما الفرق بين __str__ و __repr__ في Python ؟


باختصار ، يجب أن يكون هدف __repr__ غير واضح وأن __str__ يكون قابلاً للقراءة.

هنا هو مثال جيد:

>>> import datetime
>>> today = datetime.datetime.now()
>>> str(today)
'2012-03-14 09:21:58.130922'
>>> repr(today)
'datetime.datetime(2012, 3, 14, 9, 21, 58, 130922)'

قراءة هذه الوثائق لـ repr:

repr(object)

إرجاع سلسلة تحتوي على تمثيل قابل للطباعة لكائن. هذه هي نفس القيمة الناتجة عن التحويلات (علامات الاقتباس العكسي). من المفيد في بعض الأحيان أن تتمكن من الوصول إلى هذه العملية كوظيفة عادية. بالنسبة للعديد من الأنواع ، تقوم هذه الوظيفة بمحاولة لإرجاع سلسلة من شأنها أن تعطي كائنًا ذا نفس القيمة عند تمريره إلى eval() ، وإلا يكون التمثيل عبارة عن سلسلة محاطة بأقواس زاوية تحتوي على اسم نوع الكائن معًا مع معلومات إضافية غالبًا بما في ذلك اسم وعنوان الكائن. يمكن للفئة التحكم في ما __repr__() هذه الدالة __repr__() خلال تحديد طريقة __repr__() .

هنا هو وثائق str:

str(object='')

إرجاع سلسلة تحتوي على تمثيل قابل للطباعة لطيف كائن. لسلسلة ، هذا إرجاع السلسلة نفسها. الفرق مع repr(object) هو أن str(object) لا يحاول دائمًا إرجاع سلسلة مقبولة لـ eval() ؛ هدفها هو إرجاع سلسلة قابلة للطباعة. إذا لم يتم تحديد أي وسيطة ، فأرجع السلسلة الفارغة ، '' .


أكثر وضوحا من blog

شارع يشبه toString. تم إنشاؤها حتى تتمكن من طباعة reprs البيانات مثل التسلسل ، أو المخلل. كيف يمكنني إعادة إنشاء هذا الكائن إذا كنت بحاجة إلى القيام بذلك باستخدام eval ()

>>> import datetime
>>> now = datetime.datetime.now() 
>>> str(now)
'2015-04-04 20:51:31.766862'
>>> repr(now)
'datetime.datetime(2015, 4, 4, 20, 51, 31, 766862)'
>>mydate = eval(repr(now))

بصرف النظر عن جميع الإجابات المقدمة ، أود أن أضيف بعض النقاط: -

1) يتم استدعاء __repr__() عند كتابة اسم الكائن ببساطة على وحدة تحكم python تفاعلية ثم الضغط على Enter.

2) يتم استدعاء __str__() عند استخدام كائن مع عبارة الطباعة.

3) في حالة ، إذا كان __str__ مفقودًا ، __str__ بالطباعة وأي وظيفة تستخدم str() __repr__() للكائن.

4) __str__() من الحاويات ، عندما يتم التذرع بتنفيذ __repr__() لعناصرها المحتواة.

5) str() استدعائها ضمن __str__() المحتمل أن تتكرر دون حالة قاعدة ، والخطأ في أقصى عمق للتكرار.

6) __repr__() يمكن استدعاء repr() الذي سيحاول تجنب العودية لا نهائية تلقائيا ، لتحل محل الكائن الممثلة بالفعل مع ...


بكل بساطة:

يستخدم __str__ لإظهار تمثيل سلسلة للكائن الخاص بك ليتم قراءته بسهولة من قبل الآخرين.

يستخدم __repr__ لإظهار تمثيل سلسلة للكائن.

لنفترض أنني أريد إنشاء فئة Fraction حيث يكون تمثيل سلسلة الكسر هو "(1/2)" ويتم تمثيل الكائن (فئة الكسر) على أنه "الكسر (1،2)"

حتى نتمكن من إنشاء فئة كسور بسيطة:

class Fraction:
    def __init__(self, num, den):
        self.__num = num
        self.__den = den

    def __str__(self):
        return '(' + str(self.__num) + '/' + str(self.__den) + ')'

    def __repr__(self):
        return 'Fraction (' + str(self.__num) + ',' + str(self.__den) + ')'



f = Fraction(1,2)
print('I want to represent the Fraction STRING as ' + str(f)) # (1/2)
print('I want to represent the Fraction OBJECT as ', repr(f)) # Fraction (1,2)

تغطي الإجابات الممتازة بالفعل الفرق بين __str__ و __repr__ ، والتي بالنسبة لي تتلخص في القراءة السابقة حتى من قبل المستخدم النهائي ، وتكون الأخيرة مفيدة قدر الإمكان للمطورين. بالنظر إلى ذلك ، أجد أن التنفيذ الافتراضي لـ __repr__ يفشل غالبًا في تحقيق هذا الهدف لأنه يغفل المعلومات المفيدة للمطورين.

لهذا السبب ، إذا كان لديّ حساب بسيط بما يكفي ، فأنا أحاول بشكل عام أن أحصل على أفضل ما في العالمين مع ما يلي:

def __repr__(self):
    return '{0} ({1})'.format(object.__repr__(self), str(self))

شيء صغير:

class Demo:
  def __repr__(self):
    return 'repr'
  def __str__(self):
    return 'str'

demo = Demo()
print(demo) # use __str__, output 'str' to stdout

s = str(demo) # __str__ is used, return 'str'
r = repr(demo) # __repr__ is used, return 'repr'

import logging
logger = logging.getLogger(logging.INFO)
logger.info(demo) # use __str__, output 'str' to stdout

from pprint import pprint, pformat
pprint(demo) # use __repr__, output 'repr' to stdout
result = pformat(demo) # use __repr__, result is string which value is 'str'

في الصفحة 358 من كتاب Python scripting for computational science by Hans Petter Langtangen ، تنص بوضوح على أن

  • يهدف __repr__ إلى تمثيل سلسلة كامل للكائن ؛
  • و __str__ هو إرجاع سلسلة لطيفة للطباعة.

لذا ، أفضل أن أفهمهم

  • repr = إعادة إنتاج
  • str = string (التمثيل)

من وجهة نظر المستخدم على الرغم من أن هذا هو سوء الفهم الذي أدليت به عند التعلم بيثون.

يتم إعطاء مثال صغير ولكنه جيد أيضًا على نفس الصفحة كما يلي:

مثال

In [38]: str('s')
Out[38]: 's'

In [39]: repr('s')
Out[39]: "'s'"

In [40]: eval(str('s'))
Traceback (most recent call last):

  File "<ipython-input-40-abd46c0c43e7>", line 1, in <module>
    eval(str('s'))

  File "<string>", line 1, in <module>

NameError: name 's' is not defined


In [41]: eval(repr('s'))
Out[41]: 's'

من http://pyref.infogami.com/__str__ بواسطة effbot:

__str__ "يحسب تمثيل سلسلة" غير رسمي "لكائن ما. يختلف هذا عن __repr__ في أنه ليس من الضروري أن يكون تعبيرًا صحيحًا لـ Python: يمكن استخدام تمثيل أكثر ملاءمة أو موجزة بدلاً من ذلك."


يلخص Alex جيداً ، لكن من المدهش أنه كان مقتضباً للغاية.

أولاً ، دعني أكرر النقاط الرئيسية في مشاركة أليكس :

  • التطبيق الافتراضي عديم الفائدة (من الصعب التفكير في واحد لن يكون ، ولكن نعم)
  • الهدف __repr__ هو أن يكون لا لبس فيه
  • __str__ الهدف هو أن تكون قابلة للقراءة
  • يستخدم __str__ حاويات الكائنات __repr__

التنفيذ الافتراضي لا طائل منه

هذا في الغالب مفاجأة لأن افتراضات بايثون تميل إلى أن تكون مفيدة إلى حد كبير. ومع ذلك ، في هذه الحالة ، يجب أن يكون __repr__ الافتراضي لـ __repr__ هو تصرف مثل:

return "%s(%r)" % (self.__class__, self.__dict__)

قد يكون خطيرًا جدًا (على سبيل المثال ، من السهل جدًا الدخول في العودية اللانهائية إذا كانت الأشياء تشير إلى بعضها البعض). حتى بيثون الشرطة خارج. لاحظ أن هناك افتراضي واحد صحيح: إذا تم تعريف __repr__ ، و __str__ لا ، فإن الكائن سيتصرف كما لو كان __str__=__repr__ .

هذا يعني ، بعبارات بسيطة: يجب أن يحتوي كل كائن تقوم بتطبيقه على __repr__ وظيفيًا يمكن استخدامه لفهم الكائن. يعد تنفيذ __str__ اختياريًا: افعل ذلك إذا كنت تحتاج إلى وظيفة "طباعة جميلة" (على سبيل المثال ، استخدام من قبل مولد تقرير).

الهدف من __repr__ هو أن يكون لا لبس فيه

دعني أخرج وأقول ذلك - أنا لا أؤمن بالمصححات. لا أعرف حقًا كيفية استخدام أي مصحح أخطاء ، ولم أستخدمه على الإطلاق بجدية. علاوة على ذلك ، أعتقد أن الخطأ الكبير في مصححات الأخطاء هو طبيعتها الأساسية - فقد حدثت معظم الأخطاء التي قمت بتصحيحها منذ فترة طويلة ، في مجرة ​​بعيدة. هذا يعني أنني أعتقد ، بحماس ديني ، في قطع الأشجار. قطع الأشجار هو شريان الحياة لأي نظام خادم آمن للنار والنسيان. يجعل بايثون من السهل تسجيل الدخول: مع بعض الأغلفة المحددة للمشروع ، كل ما تحتاجه هو

log(INFO, "I am in the weird function and a is", a, "and b is", b, "but I got a null C — using default", default_c)

ولكن يجب عليك القيام بالخطوة الأخيرة - تأكد من أن كل كائن تقوم بتطبيقه له repr مفيد ، بحيث يمكن أن يعمل مثل هذا الكود فقط. هذا هو السبب في ظهور الشيء "eval": إذا كان لديك معلومات كافية لذلك eval(repr(c))==c ، فهذا يعني أنك تعرف كل شيء يجب معرفته حول c . إذا كان ذلك سهلاً ، على الأقل بطريقة غير واضحة ، فافعل ذلك. إن لم يكن ، تأكد من حصولك على معلومات كافية حول c أي حال. عادة ما أستخدم "MyClass(this=%r,that=%r)" % (self.this,self.that) : "MyClass(this=%r,that=%r)" % (self.this,self.that) . هذا لا يعني أنه بإمكانك بناء MyClass فعليًا ، أو أن هذه هي الحجج الصحيحة للمنشئ - ولكنها نموذج مفيد للتعبير عن "هذا هو كل شيء تحتاج إلى معرفته عن هذا المثيل".

ملاحظة: استخدمت %r أعلاه وليس %s . أنت دائمًا تريد استخدام repr() [أو %r تنسيق حرف ، بشكل مكافئ] داخل تنفيذ __repr__ ، أو كنت تهزم هدف repr. تريد أن تكون قادرًا على التمييز بين MyClass(3) و MyClass("3") .

الهدف من __str__ هو أن تكون قابلة للقراءة

على وجه التحديد ، ليس المقصود أن يكون لا لبس فيه - لاحظ أن str(3)==str("3") . وبالمثل ، إذا قمت بتطبيق تجريد IP ، فإن إظهار str # 192.168.1.1 هو على ما يرام. عند تنفيذ تجريد تاريخ / وقت ، يمكن أن يكون str "2010/4/12 15:35:22" ، وما إلى ذلك. الهدف هو تمثيله بطريقة يريد المستخدم ، وليس مبرمجًا ، قراءتها. يقطعون أرقاماً عديمة الفائدة ، يتظاهرون بأنهم طلاب آخرون - طالما أنه يدعم القراءة ، إنه تحسن.

يستخدم __str__ حاويات الكائنات __repr__

هذا يبدو مفاجئًا ، أليس كذلك؟ إنه قليل ، ولكن كيف يمكن قراءته

[moshe is, 3, hello
world, this is a list, oh I don't know, containing just 4 elements]

يكون؟ ليس جدا. على وجه التحديد ، قد تجد السلاسل في حاوية أنه من السهل جدًا إزعاج تمثيل السلسلة الخاصة به. في مواجهة الغموض ، تذكر أن بايثون تقاوم إغراء التخمين. إذا كنت تريد السلوك أعلاه عند طباعة قائمة ، فقط

print "[" + ", ".join(l) + "]"

(ربما يمكنك أيضًا معرفة ما يجب فعله بشأن القواميس.

ملخص

نفذ __repr__ لأي فئة تقوم بتنفيذها. هذا يجب أن يكون الطبيعة الثانية. نفذ __str__ إذا كنت تعتقد أنه سيكون من المفيد أن يكون لديك إصدار سلسلة يخطئ إلى جانب أكثر قابلية للقراءة لصالح مزيد من الغموض.


__repr__يستخدم في كل مكان، إلا printو strعندما __str__يعرف


str - ينشئ كائن سلسلة جديدًا من الكائن المحدد.

repr - لعرض تمثيل السلسلة الأساسي للكائن.

اوجه الاختلاف:

شارع ():

  • يجعل الكائن قابل للقراءة
  • يولد الإخراج للمستخدم النهائي

repr ():

  • يحتاج إلى رمز يستنسخ الكائن
  • يولد الإخراج للمطور

فهم __str__و __repr__حدسي وتميزها بشكل دائم على الإطلاق.

__str__عودة جسم سلسلة مقنعة من كائن معين للقراءة من العينين
__repr__عودة الجسم الحقيقي من جسم معين (العودة نفسها) لعدم الوضوح لتحديد.

انظر في مثال

In [30]: str(datetime.datetime.now())
Out[30]: '2017-12-07 15:41:14.002752'
Disguised in string form

بما يخص __repr__

In [32]: datetime.datetime.now()
Out[32]: datetime.datetime(2017, 12, 7, 15, 43, 27, 297769)
Presence in real body which allows to be manipulated directly.

يمكننا القيام بعملية حسابية على __repr__النتائج بشكل ملائم.

In [33]: datetime.datetime.now()
Out[33]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521)
In [34]: datetime.datetime(2017, 12, 7, 15, 47, 9, 741521) - datetime.datetime(2
    ...: 017, 12, 7, 15, 43, 27, 297769)
Out[34]: datetime.timedelta(0, 222, 443752)

إذا تم تطبيق العملية __str__

In [35]: '2017-12-07 15:43:14.002752' - '2017-12-07 15:41:14.002752'
TypeError: unsupported operand type(s) for -: 'str' and 'str'

لا يعود سوى خطأ.

مثال آخر.

In [36]: str('string_body')
Out[36]: 'string_body' # in string form

In [37]: repr('real_body')
Out[37]: "'real_body'" #its real body hide inside

نأمل أن يساعدك هذا في بناء أسباب ملموسة لاستكشاف المزيد من الإجابات.


"A basic requirement for a Python object is to provide usable 
 string   representations of itself, one used for debugging and
 logging, another for presentation to end users. That is why the  
 special methods __repr__ and __str__ exist in the data model."

من كتاب: Fluent Python





repr