python - __Str__ और__repr__ के बीच अंतर?




magic-methods (14)

Python में __str__ और __repr__ बीच क्या अंतर है?

https://code.i-harness.com


पायथन में __str__ और __repr__ बीच क्या अंतर है?

__str__ ("डंडर (डबल-अंडरस्कोर) स्ट्रिंग" के रूप में पढ़ें) और __repr__ ("डंडर-रिपपर" ("प्रतिनिधित्व" के लिए) के रूप में पढ़ें) दोनों विशेष विधियां हैं जो ऑब्जेक्ट की स्थिति के आधार पर स्ट्रिंग लौटाती हैं।

यदि __str__ गुम है तो __str__ बैकअप व्यवहार प्रदान करता है।

तो सबसे पहले एक __repr__ लिखना चाहिए जो आपको स्ट्रिंग से प्राप्त समकक्ष वस्तु को पुन: स्थापित करने की अनुमति देता है जैसे कि eval का उपयोग करके या इसे पायथन शेल में वर्ण-चरित्र के लिए टाइप करके।

किसी भी समय बाद में, कोई उदाहरण के उपयोगकर्ता-पठनीय स्ट्रिंग प्रस्तुति के लिए __str__ लिख सकता है, जब कोई मानता है कि यह आवश्यक है।

__str__

यदि आप किसी ऑब्जेक्ट को प्रिंट करते हैं, या format , str.format , या str , तो यदि एक str.format विधि परिभाषित की जाती है, तो उस विधि को बुलाया जाएगा, अन्यथा, __repr__ का उपयोग किया जाएगा।

__repr__

__repr__ विधि को बिल्टिन फ़ंक्शन repr द्वारा बुलाया जाता है और यह आपके पाइथन शेल पर प्रतिबिंबित होता है जब यह किसी ऑब्जेक्ट को लौटने वाली अभिव्यक्ति का मूल्यांकन करता है।

चूंकि यह __str__ लिए बैकअप प्रदान करता है, अगर आप केवल एक लिख सकते हैं, तो __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__ है ( सी पायथन स्रोत ) कुछ ऐसा है:

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 कहते हैं। अब, हम समतुल्य डेटाटाइम ऑब्जेक्ट को फिर से बनाने के लिए आवश्यक सब कुछ देखेंगे। यह डेटाटाइम __repr__ द्वारा बनाया गया है:

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

यदि हम डेटाटाइम ऑब्जेक्ट प्रिंट करते हैं, तो हम एक अच्छा मानव पठनीय (वास्तव में, आईएसओ) प्रारूप देखते हैं। यह __str__ द्वारा कार्यान्वित किया जाता है:

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

हमारे द्वारा खोए गए ऑब्जेक्ट को फिर से बनाने के लिए यह एक साधारण बात है क्योंकि हमने इसे __repr__ आउटपुट से प्रतिलिपि बनाने और चिपकाने के द्वारा एक चर को असाइन नहीं किया है, और फिर इसे प्रिंट कर रहा है, और हम इसे अन्य ऑब्जेक्ट के समान मानव पठनीय आउटपुट में प्राप्त करते हैं:

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

मैं उन्हें कैसे लागू करूं?

जैसे-जैसे आप विकास कर रहे हैं, यदि आप संभव हो तो उसी स्थिति में ऑब्जेक्ट्स को पुन: उत्पन्न करने में सक्षम होना चाहेंगे। उदाहरण के लिए, डेटाटाइम ऑब्जेक्ट __repr__ ( पायथन स्रोत ) को परिभाषित करता है। यह काफी जटिल है, इस तरह की वस्तु को पुन: उत्पन्न करने के लिए आवश्यक सभी विशेषताओं के कारण:

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__ को कार्यान्वित कर सकते हैं। यहां बताया गया है कि डेटाटाइम ऑब्जेक्ट ( पायथन स्रोत ) __str__ लागू करता है, जो आसानी से करता है क्योंकि इसमें पहले से ही इसे आईएसओ प्रारूप में प्रदर्शित करने के लिए एक फ़ंक्शन है:

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

__repr__ = __str__ सेट करें?

यह यहां एक और उत्तर की आलोचना है जो __repr__ = __str__ स्थापित करने का सुझाव देती है।

__repr__ = __str__ को सेट करना मूर्खतापूर्ण है - __repr__ लिए फॉलबैक है और एक __repr__ , जो डिबगिंग में डेवलपर्स के उपयोग के लिए लिखा गया है, आपको __str__ लिखने से पहले लिखा जाना चाहिए।

आपको केवल __str__ की आवश्यकता होती है जब आपको ऑब्जेक्ट का टेक्स्ट प्रस्तुतिकरण की आवश्यकता होती है।

निष्कर्ष

आपके द्वारा लिखे गए ऑब्जेक्ट्स के लिए __repr__ को परिभाषित करें ताकि आप और अन्य डेवलपर्स के पास इसका उपयोग करते समय पुन: उत्पन्न उदाहरण हो। __str__ परिभाषित करें जब आपको इसके मानव पठनीय स्ट्रिंग प्रस्तुति की आवश्यकता होती है।


ध्यान में रखना एक महत्वपूर्ण बात यह है कि कंटेनर का __str__ निहित वस्तुओं का उपयोग करता है ' __repr__

>>> from datetime import datetime
>>> from decimal import Decimal
>>> print (Decimal('52'), datetime.now())
(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 51, 26, 185000))
>>> str((Decimal('52'), datetime.now()))
"(Decimal('52'), datetime.datetime(2015, 11, 16, 10, 52, 22, 176000))"

पायथन पठनीयता पर असंबद्धता का समर्थन करता है , एक tuple कॉल निहित वस्तुओं ' __repr__ , किसी ऑब्जेक्ट का "औपचारिक" प्रतिनिधित्व कहता है। हालांकि औपचारिक प्रतिनिधित्व एक अनौपचारिक से पढ़ने के लिए कठिन है, यह बग के खिलाफ स्पष्ट और अधिक मजबूत है।


Effbot द्वारा http://pyref.infogami.com/__str__ से:

__str__ "किसी ऑब्जेक्ट की" अनौपचारिक "स्ट्रिंग प्रस्तुति की गणना करता है। यह __repr__ से अलग है जिसमें यह एक वैध पायथन अभिव्यक्ति नहीं है: इसके बजाय एक अधिक सुविधाजनक या संक्षिप्त प्रतिनिधित्व का उपयोग किया जा सकता है।"


अंगूठे का मेरा नियम: __repr__ डेवलपर्स के लिए है, __str__ ग्राहकों के लिए है।


उत्कृष्ट उत्तरों में पहले से ही __str__ और __repr__ बीच का अंतर शामिल है, जो मेरे लिए अंतिम उपयोगकर्ता द्वारा भी पढ़ने योग्य पूर्व तक उबलता है, और बाद वाले डेवलपर्स के लिए जितना संभव हो उतना उपयोगी होता है। यह देखते हुए, मुझे लगता है कि __repr__ का डिफ़ॉल्ट कार्यान्वयन अक्सर इस लक्ष्य को प्राप्त करने में विफल रहता है क्योंकि यह डेवलपर्स के लिए उपयोगी जानकारी को छोड़ देता है।

इस कारण से, यदि मेरे पास पर्याप्त सरल __str__ , तो मैं आम तौर पर दोनों दुनिया के सर्वश्रेष्ठ कुछ प्राप्त करने का प्रयास करता हूं जैसे:

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

एक पहलू जो अन्य उत्तरों में गायब है। यह सच है कि सामान्य रूप से पैटर्न है:

  • __Str__ का लक्ष्य: मानव-पठनीय
  • __Repr__ का लक्ष्य: स्पष्ट, संभावित रूप से मशीन-पठनीय eval माध्यम से

दुर्भाग्यवश, यह भेदभाव त्रुटिपूर्ण है, क्योंकि पाइथन आरईपीएल और आईपीथॉन एक आरईपीएल कंसोल में प्रिंटिंग ऑब्जेक्ट्स के लिए __repr__ का उपयोग करते हैं ( Python और IPython के लिए संबंधित प्रश्न देखें)। इस प्रकार, परियोजनाएं जो इंटरैक्टिव कंसोल काम (उदाहरण के लिए, नम्पी या पांडस) के लिए लक्षित हैं, ने नियमों को अनदेखा करना शुरू कर दिया है और इसके बजाय मानव-पठनीय __repr__ कार्यान्वयन प्रदान किया है।


दिए गए सभी उत्तरों के अलावा, मैं कुछ अंक जोड़ना चाहता हूं: -

1) __repr__() तब लागू होता है जब आप इंटरैक्टिव पायथन कंसोल पर ऑब्जेक्ट का नाम लिखते हैं और एंटर दबाते हैं।

2) __str__() जब आप प्रिंट स्टेटमेंट के साथ ऑब्जेक्ट का उपयोग करते हैं तो लागू किया जाता है।

3) यदि, __repr__() गुम है, तो __repr__() str() का उपयोग करके प्रिंट और कोई फ़ंक्शन ऑब्जेक्ट के __repr__() को आमंत्रित करता है।

4) कंटेनर के __str__() , जब लागू किया जाता है तो इसके निहित तत्वों के __repr__() विधि को निष्पादित किया जाएगा।

5) __str__() भीतर बुलाया गया str() आधार आधार के बिना संभावित रूप से __str__() कर सकता है, और अधिकतम रिकर्सन गहराई पर त्रुटि हो सकती है।

6) __repr__() repr() __repr__() को कॉल कर सकता है जो स्वचालित रूप से असीमित रिकर्सन से बचने का प्रयास करेगा, पहले से प्रदर्शित ऑब्जेक्ट को प्रतिस्थापित कर देगा ...


संक्षेप में:

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 पर, यह स्पष्ट रूप से बताता है कि

  • __repr__ उद्देश्य वस्तु के पूर्ण स्ट्रिंग प्रतिनिधित्व पर है;
  • __str__ मुद्रण के लिए एक अच्छी तरह से स्ट्रिंग वापस करने के लिए है।

इसलिए, मैं उन्हें समझना पसंद करता हूं

  • repr = पुनरुत्पादन
  • str = स्ट्रिंग (प्रतिनिधित्व)

उपयोगकर्ता के दृष्टिकोण से हालांकि यह एक गलतफहमी है जिसे मैंने पाइथन सीखते समय बनाया था।

एक ही पृष्ठ पर एक छोटा लेकिन अच्छा उदाहरण भी दिया गया है:

उदाहरण

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'

blog से बहुत स्पष्ट है

str स्ट्रिंग की तरह है। बनाया गया है ताकि आप डेटा repr मुद्रित कर सकते हैं serialize, या अचार की तरह है। अगर मैं 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))

__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

आशा है कि इससे आपको अधिक उत्तरों का पता लगाने के लिए ठोस आधार तैयार करने में मदद मिलेगी।


str - दिए गए ऑब्जेक्ट से एक नई स्ट्रिंग ऑब्जेक्ट बनाता है।

repr - वस्तु के canonical स्ट्रिंग प्रतिनिधित्व देता है।

भिन्नताएं:

str ():

  • ऑब्जेक्ट पठनीय बनाता है
  • एंड-यूजर के लिए आउटपुट उत्पन्न करता है

रेपर ():

  • ऑब्जेक्ट को पुन: उत्पन्न करने वाले कोड की आवश्यकता होती है
  • डेवलपर के लिए आउटपुट उत्पन्न करता है

Alex ने संक्षेप में संक्षेप में बताया, लेकिन आश्चर्यजनक रूप से, बहुत संक्षिप्त था।

सबसे पहले, मुझे एलेक्स के पोस्ट में मुख्य बिंदु दोहराएं :

  • डिफ़ॉल्ट कार्यान्वयन बेकार है (किसी के बारे में सोचना मुश्किल है जो नहीं होगा, लेकिन हाँ)
  • __repr__ लक्ष्य अस्पष्ट होना है
  • __str__ लक्ष्य पठनीय होना है
  • कंटेनर का __str__ निहित वस्तुओं का उपयोग करता है ' __repr__

डिफ़ॉल्ट कार्यान्वयन बेकार है

यह ज्यादातर आश्चर्यचकित है क्योंकि पायथन का डिफ़ॉल्ट काफी उपयोगी होता है। हालांकि, इस मामले में, __repr__ लिए डिफ़ॉल्ट होना जो इस प्रकार कार्य करेगा:

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

बहुत खतरनाक होता (उदाहरण के लिए, यदि वस्तुओं एक-दूसरे को संदर्भित करते हैं तो अनंत रिकर्सन में प्रवेश करना बहुत आसान होता है)। तो पाइथन बाहर निकलता है। ध्यान दें कि एक डिफ़ॉल्ट है जो सत्य है: यदि __repr__ परिभाषित किया गया है, और __str__=__repr__ नहीं है, तो ऑब्जेक्ट व्यवहार करेगा जैसे __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)

लेकिन आपको अंतिम चरण करना है - सुनिश्चित करें कि आपके द्वारा लागू हर ऑब्जेक्ट में एक उपयोगी प्रतिनिधि है, इसलिए ऐसा कोड बस काम कर सकता है। यही कारण है कि "eval" चीज आती है: यदि आपके पास पर्याप्त जानकारी है तो eval(repr(c))==c , इसका मतलब है कि आप c बारे में जानने के लिए सबकुछ जानते हैं। यदि यह कम से कम एक अस्पष्ट तरीके से पर्याप्त है, तो इसे करें। यदि नहीं, तो सुनिश्चित करें कि आपके पास c बारे में पर्याप्त जानकारी है। मैं आमतौर पर एक eval- जैसे प्रारूप का उपयोग करता हूं: "MyClass(this=%r,that=%r)" % (self.this,self.that) । इसका मतलब यह नहीं है कि आप वास्तव में MyClass का निर्माण कर सकते हैं, या वे सही कन्स्ट्रक्टर तर्क हैं - लेकिन यह अभिव्यक्ति करने के लिए एक उपयोगी रूप है "यह सब कुछ है जिसे आपको इस उदाहरण के बारे में जानने की आवश्यकता है"।

नोट: मैंने %s उपयोग किया, %s नहीं। आप हमेशा __repr__ कार्यान्वयन के अंदर repr() [या %r स्वरूपण वर्ण, समकक्ष] का उपयोग करना चाहते हैं, या आप repr के लक्ष्य को हरा रहे हैं। आप MyClass(3) और MyClass("3") को अलग करने में सक्षम होना चाहते हैं।

__str__ का लक्ष्य पठनीय होना है

विशेष रूप से, यह स्पष्ट नहीं है - ध्यान दें कि str(3)==str("3") । इसी प्रकार, यदि आप एक आईपी अबास्ट्रक्शन लागू करते हैं, तो इसका स्ट्रिंग 1 9 2.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__ लागू करें यदि आपको लगता है कि यह एक स्ट्रिंग संस्करण होना उपयोगी होगा जो अधिक अस्पष्टता के पक्ष में अधिक पठनीयता के पक्ष में गलती करता है।


"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."

पुस्तक से: फ्लुएंट पायथन





repr