Python Language
कक्षा के उदाहरणों के स्ट्रिंग निरूपण: __str__ और __repr__ विधियाँ
खोज…
टिप्पणियों
दोनों तरीकों को लागू करने के बारे में एक नोट
जब दोनों विधियों को लागू किया जाता है, तो यह एक __str__
विधि के लिए कुछ सामान्य है जो मानव-अनुकूल प्रतिनिधित्व लौटाता है (जैसे "Ace of Spaces") और __repr__
एक eval
-friendly प्रतिनिधित्व लौटाते हैं।
वास्तव में, repr()
लिए पाइथन डॉक्स repr()
ध्यान दें:
कई प्रकारों के लिए, यह फ़ंक्शन एक स्ट्रिंग को वापस करने का प्रयास करता है जो किसी वस्तु को उसी मान के साथ प्राप्त करेगा जब eval () में पास हो, अन्यथा प्रतिनिधित्व कोण कोष्ठक में संलग्न स्ट्रिंग है जिसमें ऑब्जेक्ट के प्रकार का नाम एक साथ होता है ऑब्जेक्ट के नाम और पते सहित अक्सर अतिरिक्त जानकारी के साथ।
इसका मतलब यह है कि __str__
को "ऐस ऑफ़ स्पेसेस" की तरह कुछ वापस करने के लिए लागू किया जा सकता है जैसा कि पहले दिखाया गया है, __repr__
को बदले में Card('Spades', 1)
लागू किया जा सकता है
इस स्ट्रिंग में सीधे वापस भेजी जा सकती है eval
एक "राउंड ट्रिप" के कुछ में:
object -> string -> object
ऐसी विधि के कार्यान्वयन का एक उदाहरण हो सकता है:
def __repr__(self):
return "Card(%s, %d)" % (self.suit, self.pips)
टिप्पणियाँ
[१] यह आउटपुट विशिष्ट कार्यान्वयन है। प्रदर्शित स्ट्रिंग cpython से है।
[२] आपने पहले ही इस str()
/ repr()
विभाजित करने और इसे न repr()
का परिणाम देखा होगा। जब बैकस्लैश जैसे विशेष वर्ण वाले तार स्ट्रिंग्स के माध्यम से स्ट्रिंग्स में बदल जाते हैं str()
बैकस्लैश के रूप में प्रकट होते हैं (वे एक बार दिखाई देते हैं)। जब वे repr()
माध्यम से स्ट्रिंग्स में परिवर्तित हो जाते हैं (उदाहरण के लिए, सूची के तत्वों को प्रदर्शित किया जा रहा है), बैकस्लैश बच जाते हैं और इस प्रकार दो बार दिखाई देते हैं।
प्रेरणा
तो आपने अभी-अभी पायथन में अपनी पहली कक्षा बनाई है, एक साफ सुथरी छोटी कक्षा जो एक प्लेइंग कार्ड को एनकैप्सुलेट करती है:
class Card:
def __init__(self, suit, pips):
self.suit = suit
self.pips = pips
आपके कोड में कहीं और, आप इस वर्ग के कुछ उदाहरण बनाते हैं:
ace_of_spades = Card('Spades', 1)
four_of_clubs = Card('Clubs', 4)
six_of_hearts = Card('Hearts', 6)
आपने "हाथ" का प्रतिनिधित्व करने के लिए कार्ड की एक सूची भी बनाई है:
my_hand = [ace_of_spades, four_of_clubs, six_of_hearts]
अब, डिबगिंग के दौरान, आप यह देखना चाहते हैं कि आपका हाथ कैसा दिखता है, इसलिए आप वह करें जो स्वाभाविक रूप से आता है और लिखें:
print(my_hand)
लेकिन जो आपको वापस मिल जाता है वह है जिबरिश का एक गुच्छा:
[<__main__.Card instance at 0x0000000002533788>,
<__main__.Card instance at 0x00000000025B95C8>,
<__main__.Card instance at 0x00000000025FF508>]
भ्रमित, आप केवल एक कार्ड प्रिंट करने का प्रयास करते हैं:
print(ace_of_spades)
और फिर, आपको यह अजीब आउटपुट मिलता है:
<__main__.Card instance at 0x0000000002533788>
कोई डर नहीं है। हम इसे ठीक करने वाले हैं।
हालाँकि, यह समझना महत्वपूर्ण है कि यहाँ क्या हो रहा है। जब आपने print(ace_of_spades)
लिखा था, तो आपने पायथन से कहा था कि आप चाहते थे कि Card
उदाहरण के बारे में जानकारी आपके कोड ace_of_spades
को कॉल ace_of_spades
। और निष्पक्ष होने के लिए, यह किया।
यह आउटपुट दो महत्वपूर्ण बिट्स से मिलकर बनता है: ऑब्जेक्ट का type
और ऑब्जेक्ट का id
। अकेले दूसरा भाग (हेक्सिडेसिमल संख्या) विशिष्ट रूप से print
कॉल के समय वस्तु को पहचानने के लिए पर्याप्त है। [१]
वास्तव में क्या हुआ था कि आपने पायथन को उस वस्तु के सार को "शब्दों में ढालने" के लिए कहा और फिर उसे आपको प्रदर्शित किया। एक ही मशीनरी का अधिक स्पष्ट संस्करण हो सकता है:
string_of_card = str(ace_of_spades)
print(string_of_card)
पहली पंक्ति में, आप अपने Card
उदाहरण को एक स्ट्रिंग में बदलने की कोशिश करते हैं, और दूसरी में आप इसे प्रदर्शित करते हैं।
समस्या
जिस समस्या का आप सामना कर रहे हैं, वह इस तथ्य के कारण उत्पन्न होती है कि, जब आपने पायथन को Card
बनाने के लिए आपके बारे में जानने के लिए Card
क्लास के बारे में जानने के लिए आवश्यक सब कुछ बताया था , तो आपने यह नहीं बताया कि आप कैसे Card
उदाहरणों को स्ट्रिंग्स में बदलना चाहते हैं।
और चूंकि यह नहीं पता था, जब आपने ( str(ace_of_spades)
लिखा था, इसने आपको वह दिया जो आपने देखा, Card
उदाहरण का एक सामान्य प्रतिनिधित्व।
समाधान (भाग 1)
लेकिन हम पायथन को बता सकते हैं कि हम कैसे चाहते हैं कि हमारे कस्टम वर्ग के उदाहरण तार में परिवर्तित हो जाएं। और जिस तरह से हम ऐसा करते हैं वह __str__
"डंडर" (डबल-अंडरस्कोर के लिए) या "जादू" विधि के साथ है।
जब भी आप पायथन को एक वर्ग उदाहरण से एक स्ट्रिंग बनाने के लिए कहते हैं, तो वह कक्षा में एक __str__
विधि की तलाश करेगा, और उसे कॉल करेगा।
हमारे Card
वर्ग के निम्नलिखित, अद्यतन संस्करण पर विचार करें:
class Card:
def __init__(self, suit, pips):
self.suit = suit
self.pips = pips
def __str__(self):
special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}
card_name = special_names.get(self.pips, str(self.pips))
return "%s of %s" % (card_name, self.suit)
यहाँ, हम अब परिभाषित किया है __str__
हमारे पर विधि Card
वर्ग जो, चेहरा कार्ड के लिए एक सरल शब्दकोश देखने के बाद, एक स्ट्रिंग स्वरूपित लेकिन हम तय देता है।
(ध्यान दें कि "रिटर्न" यहां बोल्ड में है, एक स्ट्रिंग को वापस करने के महत्व पर जोर देने के लिए, और न केवल इसे प्रिंट करने के लिए। प्रिंटिंग यह काम करने के लिए लग सकता है, लेकिन तब आपके पास कार्ड मुद्रित होगा जब आपने str(ace_of_spades)
जैसा कुछ किया होगा str(ace_of_spades)
, अपने मुख्य कार्यक्रम में प्रिंट फ़ंक्शन कॉल किए बिना भी। तो स्पष्ट होने के लिए, सुनिश्चित करें कि __str__
एक स्ट्रिंग लौटाता है।)
__str__
विधि एक विधि है, इसलिए पहला तर्क self
होगा और इसे न तो स्वीकार करना चाहिए, न ही एडिटोनल तर्क पारित किए जाने चाहिए।
यदि हम फिर से चलते हैं, तो कार्ड को अधिक उपयोगकर्ता-अनुकूल तरीके से प्रदर्शित करने की हमारी समस्या पर लौटते हुए:
ace_of_spades = Card('Spades', 1)
print(ace_of_spades)
हम देखेंगे कि हमारा आउटपुट बहुत बेहतर है:
Ace of Spades
इतना बढ़िया, हम कर रहे हैं, है ना?
अच्छी तरह से सिर्फ हमारे ठिकानों को कवर करने के लिए, आइए दोहराते हैं कि हमने जो पहला मुद्दा हल किया है, वह Card
इंस्टेंस की सूची, hand
प्रिंट करना है।
इसलिए हम निम्नलिखित कोड की फिर से जाँच करते हैं:
my_hand = [ace_of_spades, four_of_clubs, six_of_hearts]
print(my_hand)
और, हमारे आश्चर्य के लिए, हम उन अजीब हेक्स कोड को फिर से प्राप्त करते हैं:
[<__main__.Card instance at 0x00000000026F95C8>,
<__main__.Card instance at 0x000000000273F4C8>,
<__main__.Card instance at 0x0000000002732E08>]
क्या चल रहा है? हमने पायथन को बताया कि हम कैसे चाहते थे कि हमारे Card
उदाहरण प्रदर्शित हों, यह स्पष्ट रूप से क्यों भूल गए?
समाधान (भाग 2)
ठीक है, जब पाइथन एक सूची में वस्तुओं का स्ट्रिंग प्रतिनिधित्व प्राप्त करना चाहता है तो पीछे-पीछे की मशीनरी थोड़ी अलग है। यह पता चला, पायथन इस उद्देश्य के लिए __str__
के बारे में परवाह नहीं करता है।
इसके बजाय, यह एक अलग विधि की तलाश करता है, __repr__
, और यदि यह नहीं मिला, तो यह "हेक्सिडेसिमल चीज़" पर वापस आता है। [२]
तो आप कह रहे हैं कि मुझे एक ही काम करने के लिए दो तरीके बनाने होंगे? एक जब मैं अपने कार्ड को स्वयं print
करना चाहता हूं और दूसरा जब यह किसी प्रकार के कंटेनर में होता है?
नहीं, लेकिन पहले यह देखें कि अगर हमारी कक्षा __str__
और __repr__
विधियों को लागू करने के लिए हमारी कक्षा की तरह होगी तो क्या होगा :
class Card:
special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}
def __init__(self, suit, pips):
self.suit = suit
self.pips = pips
def __str__(self):
card_name = Card.special_names.get(self.pips, str(self.pips))
return "%s of %s (S)" % (card_name, self.suit)
def __repr__(self):
card_name = Card.special_names.get(self.pips, str(self.pips))
return "%s of %s (R)" % (card_name, self.suit)
यहां, दो विधियों __str__
और __repr__
का कार्यान्वयन बिल्कुल समान है, सिवाय इसके कि, दो विधियों के बीच अंतर करने के लिए, (S)
को __str__
द्वारा लौटाए गए तार में जोड़ा जाता है और (R)
को __repr__
द्वारा लौटाए गए तार में जोड़ा जाता है।
ध्यान दें कि हमारी __str__
विधि की तरह, __repr__
कोई तर्क स्वीकार नहीं करता है और एक स्ट्रिंग लौटाता है।
अब हम देख सकते हैं कि प्रत्येक मामले के लिए कौन सी विधि जिम्मेदार है:
ace_of_spades = Card('Spades', 1)
four_of_clubs = Card('Clubs', 4)
six_of_hearts = Card('Hearts', 6)
my_hand = [ace_of_spades, four_of_clubs, six_of_hearts]
print(my_hand) # [Ace of Spades (R), 4 of Clubs (R), 6 of Hearts (R)]
print(ace_of_spades) # Ace of Spades (S)
जैसा कि कवर किया गया था, __str__
पद्धति को तब बुलाया गया था जब हमने print
करने के लिए अपना Card
उदाहरण पास किया था और __repr__
विधि को कॉल किया गया था जब हमने print
करने के लिए अपने उदाहरणों की एक सूची पारित की थी।
इस बिंदु पर यह इंगित करने योग्य है कि जैसे हम स्पष्ट रूप से str()
का उपयोग करते हुए कस्टम वर्ग उदाहरण से एक स्ट्रिंग बना सकते हैं जैसा कि हमने पहले किया था, हम स्पष्ट रूप से एक अंतर्निहित फ़ंक्शन के साथ हमारी कक्षा का एक स्ट्रिंग प्रतिनिधित्व बना सकते हैं जिसे repr()
कहा जाता है repr()
।
उदाहरण के लिए:
str_card = str(four_of_clubs)
print(str_card) # 4 of Clubs (S)
repr_card = repr(four_of_clubs)
print(repr_card) # 4 of Clubs (R)
और इसके अतिरिक्त, अगर परिभाषित किया गया है, तो हम सीधे तरीकों को कॉल कर सकते हैं (हालांकि यह थोड़ा अस्पष्ट और अनावश्यक लगता है):
print(four_of_clubs.__str__()) # 4 of Clubs (S)
print(four_of_clubs.__repr__()) # 4 of Clubs (R)
दोहराए गए कार्यों के बारे में ...
पायथन डेवलपर्स ने महसूस किया, इस मामले में जब आप चाहते थे कि समान स्ट्रिंग्स को str()
और repr()
से लौटाया जाए तो आपके पास कार्यात्मक रूप से डुप्लिकेट तरीके हो सकते हैं - ऐसा कुछ जिसे कोई पसंद नहीं करता है।
इसके बजाय, इसके लिए आवश्यकता को समाप्त करने के लिए एक तंत्र है। एक मैं तुम्हें इस बिंदु पर पिछले snuck। ऐसा लगता है कि अगर एक वर्ग औजार __repr__
विधि नहीं बल्कि __str__
विधि है, और आप को उस वर्ग का एक उदाहरण पारित str()
(चाहे परोक्ष या स्पष्ट), अजगर अपने पर वापस आने जाएगा __repr__
कार्यान्वयन और उस का उपयोग करें।
तो, स्पष्ट होने के लिए, Card
वर्ग के निम्नलिखित संस्करण पर विचार करें:
class Card:
special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}
def __init__(self, suit, pips):
self.suit = suit
self.pips = pips
def __repr__(self):
card_name = Card.special_names.get(self.pips, str(self.pips))
return "%s of %s" % (card_name, self.suit)
इस संस्करण पर ध्यान दें केवल __repr__
विधि को लागू करता है। फिर भी, उपयोगकर्ता के अनुकूल संस्करण में str()
परिणाम के लिए कॉल:
print(six_of_hearts) # 6 of Hearts (implicit conversion)
print(str(six_of_hearts)) # 6 of Hearts (explicit conversion)
जैसा कि repr()
:
print([six_of_hearts]) #[6 of Hearts] (implicit conversion)
print(repr(six_of_hearts)) # 6 of Hearts (explicit conversion)
सारांश
उपयोगकर्ता-अनुकूल तरीकों से "खुद को दिखाने" के लिए अपने वर्ग के उदाहरणों को सशक्त बनाने के लिए, आप कम से कम अपनी कक्षा की __repr__
पद्धति को लागू करने पर विचार करना चाहेंगे। यदि स्मृति कार्य करती है, तो एक बात के दौरान रेमंड हेटिंगर ने कहा कि सुनिश्चित करना कि __repr__
पायथन कोड की समीक्षा करते समय वह पहली चीजों में से एक है, जिसे वह देख रहा है और अब तक यह स्पष्ट होना चाहिए कि क्यों। जानकारी की मात्रा जो आप डिबगिंग स्टेटमेंट्स, क्रैश रिपोर्ट्स में जोड़ सकते हैं, या एक साधारण विधि के साथ लॉग फाइल तालिकाओं की तुलना में भारी होती है, और अक्सर कम-से-मददगार (प्रकार, आईडी) जानकारी जो डिफ़ॉल्ट रूप से दी जाती है।
यदि आप उदाहरण के लिए, कंटेनर के अंदर के लिए अलग-अलग अभ्यावेदन चाहते हैं, तो आप __repr__
और __str__
दोनों तरीकों को लागू करना चाहेंगे। (आप नीचे दिए गए इन दो तरीकों का उपयोग कैसे कर सकते हैं, इस पर अधिक)।
दोनों तरीकों को लागू किया, eval-round-trip style __repr __ ()
class Card:
special_names = {1:'Ace', 11:'Jack', 12:'Queen', 13:'King'}
def __init__(self, suit, pips):
self.suit = suit
self.pips = pips
# Called when instance is converted to a string via str()
# Examples:
# print(card1)
# print(str(card1)
def __str__(self):
card_name = Card.special_names.get(self.pips, str(self.pips))
return "%s of %s" % (card_name, self.suit)
# Called when instance is converted to a string via repr()
# Examples:
# print([card1, card2, card3])
# print(repr(card1))
def __repr__(self):
return "Card(%s, %d)" % (self.suit, self.pips)