TL; DR : यदि आप Python 4.0 का उपयोग कर रहे हैं तो यह काम करता है। 3.7+ में आज (2019) तक आपको भविष्य कथन ( from __future__ import annotations
) - पायथन 3.6 के लिए या नीचे दिए गए स्ट्रिंग का उपयोग करके इस सुविधा को चालू करना होगा ।
मुझे लगता है कि आपको यह अपवाद मिला है:
NameError: name 'Position' is not defined
ऐसा इसलिए है क्योंकि Position
जब तक आप पायथन 4 का उपयोग नहीं कर रहे हैं, तब तक इसे एनोटेशन में उपयोग करने से पहले इसे परिभाषित किया जाना चाहिए।
अजगर 3.7+: from __future__ import annotations
पायथॉन 3.7 पीईपी 563 का परिचय देता है : एनोटेशन का स्थगित मूल्यांकन । एक मॉड्यूल जो भविष्य कथन का उपयोग करता है, from __future__ import annotations
एनोटेशन को स्ट्रिंग्स के रूप में स्वचालित रूप से संग्रहीत करेगा:
from __future__ import annotations
class Position:
def __add__(self, other: Position) -> Position:
...
यह पायथन 4.0 में डिफ़ॉल्ट बनने के लिए निर्धारित है। चूंकि पायथन अभी भी एक गतिशील रूप से टाइप की गई भाषा है, इसलिए रनटाइम पर किसी भी प्रकार की जाँच नहीं की जाती है, टाइपिंग एनोटेशन का कोई प्रदर्शन प्रभाव नहीं होना चाहिए, है ना? गलत! अजगर 3.7 से पहले टाइपिंग मॉड्यूल कोर में सबसे धीमे अजगर मॉड्यूल में से एक हुआ करता था, इसलिए यदि आप 3.7 में अपग्रेड करते हैं तो आप प्रदर्शन में 7 गुना वृद्धिimport typing
देखेंगे ।
पायथन <3.7: एक स्ट्रिंग का उपयोग करें
PEP 484 के अनुसार , आपको कक्षा के बजाय एक स्ट्रिंग का उपयोग करना चाहिए:
class Position:
...
def __add__(self, other: 'Position') -> 'Position':
...
यदि आप Django ढांचे का उपयोग करते हैं तो यह परिचित हो सकता है क्योंकि Django मॉडल भी आगे के संदर्भों के लिए तार का उपयोग करते हैं (विदेशी प्रमुख परिभाषाएं जहां विदेशी मॉडल है self
या अभी घोषित नहीं है)। यह Pycharm और अन्य उपकरणों के साथ काम करना चाहिए।
सूत्रों का कहना है
पीईपी 484 और पीईपी 563 के प्रासंगिक हिस्से , आपको यात्रा को खाली करने के लिए:
आगे के संदर्भ
जब एक प्रकार के संकेत में ऐसे नाम होते हैं जिन्हें अभी तक परिभाषित नहीं किया गया है, तो उस परिभाषा को एक स्ट्रिंग शाब्दिक के रूप में व्यक्त किया जा सकता है, जिसे बाद में हल किया जा सकता है।
ऐसी स्थिति जहां यह आमतौर पर होता है, एक कंटेनर वर्ग की परिभाषा है, जहां परिभाषित की जा रही कक्षा कुछ विधियों के हस्ताक्षर में होती है। उदाहरण के लिए, निम्न कोड (एक सरल बाइनरी ट्री कार्यान्वयन की शुरुआत) काम नहीं करता है:
class Tree:
def __init__(self, left: Tree, right: Tree):
self.left = left
self.right = right
इसे संबोधित करने के लिए, हम लिखते हैं:
class Tree:
def __init__(self, left: 'Tree', right: 'Tree'):
self.left = left
self.right = right
स्ट्रिंग शाब्दिक में एक मान्य पायथन अभिव्यक्ति होनी चाहिए (जैसे, संकलन (प्रकाशित, '', 'eval') एक वैध कोड ऑब्जेक्ट होना चाहिए) और मॉड्यूल पूरी तरह से लोड होने के बाद त्रुटियों के बिना इसका मूल्यांकन करना चाहिए। जिस स्थानीय और वैश्विक नामस्थान का मूल्यांकन किया गया है, वह वही नामस्थान होना चाहिए जिसमें एक ही कार्य के लिए डिफ़ॉल्ट तर्क का मूल्यांकन किया जाएगा।
और पीईपी 563:
पायथन 4.0 में, फ़ंक्शन और वेरिएबल एनोटेशन का अब परिभाषा के समय पर मूल्यांकन नहीं किया जाएगा। इसके बजाय, संबंधित __annotations__
शब्दकोश में एक स्ट्रिंग फॉर्म संरक्षित किया जाएगा । स्टेटिक टाइप चेकर्स के व्यवहार में कोई अंतर नहीं दिखेगा, जबकि रनटाइम पर एनोटेशन का उपयोग करने वाले टूल को स्थगित मूल्यांकन करना होगा।
...
ऊपर वर्णित कार्यक्षमता को निम्न विशेष आयात का उपयोग करके पायथन 3.7 से शुरू किया जा सकता है:
from __future__ import annotations
चीजें जो आप के बजाय करने के लिए परीक्षा हो सकती है
A. एक डमी को परिभाषित करें Position
कक्षा की परिभाषा से पहले, एक डमी परिभाषा रखें:
class Position(object):
pass
class Position(object):
...
इससे छुटकारा मिलेगा NameError
और ठीक भी लग सकता है:
>>> Position.__add__.__annotations__
{'other': __main__.Position, 'return': __main__.Position}
पर है क्या?
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: False
other is Position: False
एन बंदर-पैच एनोटेशन जोड़ने के लिए:
आप कुछ पायथन मेटा प्रोग्रामिंग जादू को आज़माना चाहते हैं और मतदाता को जोड़ने के लिए कक्षा परिभाषा को बंदर-पैच करने के लिए डेकोरेटर लिख सकते हैं:
class Position:
...
def __add__(self, other):
return self.__class__(self.x + other.x, self.y + other.y)
डेकोरेटर इसके बराबर के लिए जिम्मेदार होना चाहिए:
Position.__add__.__annotations__['return'] = Position
Position.__add__.__annotations__['other'] = Position
कम से कम यह सही लगता है:
>>> for k, v in Position.__add__.__annotations__.items():
... print(k, 'is Position:', v is Position)
return is Position: True
other is Position: True
शायद बहुत अधिक परेशानी।
निष्कर्ष
यदि आप 3.6 या नीचे का उपयोग कर रहे हैं, तो स्ट्रिंग नाम शाब्दिक है जिसमें 3.7 का उपयोग किया गया है, 3.7 उपयोग में है from __future__ import annotations
और यह सिर्फ काम करेगा।