2015-12-04 6 views
20

मैं सिर्फ निम्नलिखित अजीब स्थिति पर ठोकर खाई:पहचानकर्ता सामान्यीकरण: यूनानी पत्र में परिवर्तित माइक्रो संकेत क्यों है?

>>> class Test: 
     µ = 'foo' 

>>> Test.µ 
'foo' 
>>> getattr(Test, 'µ') 
Traceback (most recent call last): 
    File "<pyshell#4>", line 1, in <module> 
    getattr(Test, 'µ') 
AttributeError: type object 'Test' has no attribute 'µ' 
>>> 'µ'.encode(), dir(Test)[-1].encode() 
(b'\xc2\xb5', b'\xce\xbc') 

चरित्र मेरे द्वारा डाला हमेशा कीबोर्ड पर μ संकेत है, लेकिन किसी कारण से यह परिवर्तित हो जाता है। ऐसा क्यों होता है?

उत्तर

21

यहां दो अलग-अलग वर्ण शामिल हैं। एक MICRO SIGN है, जो कुंजीपटल पर एक है, और दूसरा GREEK SMALL LETTER MU है।

को समझने के लिए क्या हो रहा है, हम कैसे अजगर language reference में पहचानकर्ता को परिभाषित करता है पर एक नज़र रखना चाहिए:

identifier ::= xid_start xid_continue* 
id_start  ::= <all characters in general categories Lu, Ll, Lt, Lm, Lo, Nl, the underscore, and characters with the Other_ID_Start property> 
id_continue ::= <all characters in id_start, plus characters in the categories Mn, Mc, Nd, Pc and others with the Other_ID_Continue property> 
xid_start ::= <all characters in id_start whose NFKC normalization is in "id_start xid_continue*"> 
xid_continue ::= <all characters in id_continue whose NFKC normalization is in "id_continue*"> 

दोनों हमारे वर्ण, कुटीर हस्ताक्षर और ग्रीक छोटा अक्षर एमयू, Ll यूनिकोड समूह का हिस्सा हैं (लोअरकेस अक्षरों), इसलिए उनमें से दोनों पहचानकर्ता में किसी भी स्थिति में इस्तेमाल किया जा सकता है। अब ध्यान दें कि identifier की परिभाषा वास्तव में xid_start और xid_continue को संदर्भित करती है, और उनको संबंधित गैर-एक्स परिभाषा के सभी वर्णों के रूप में परिभाषित किया जाता है जिनके एनएफकेसी सामान्यीकरण के परिणामस्वरूप पहचानकर्ता के लिए एक वैध वर्ण अनुक्रम होता है।

पायथन स्पष्ट रूप से केवल सामान्यीकृत पहचानकर्ताओं के रूप में परवाह करता है। यह नीचे कुछ पुष्टि की गई है:

पार्सिंग के दौरान सभी पहचानकर्ता सामान्य रूप में एनएफकेसी में परिवर्तित हो जाते हैं; पहचानकर्ताओं की तुलना एनएफकेसी पर आधारित है।

एनएफकेसी Unicode normalization है जो अलग-अलग हिस्सों में वर्णों को विघटित करता है। माइक्रो साइन ग्रिक स्मॉल लिटर एमयू में विघटित हो गया है, और यह वही है जो वहां जा रहा है।

ऐसे कई अन्य पात्र हैं जो इस सामान्यीकरण से भी प्रभावित होते हैं। एक अन्य उदाहरण OHM SIGN है जो GREEK CAPITAL LETTER OMEGA में विघटित होता है। का उपयोग करना है कि के रूप में एक पहचानकर्ता एक समान परिणाम देता है, यहाँ स्थानीय लोगों का उपयोग कर दिखाया गया है:

>>> Ω = 'bar' 
>>> locals()['Ω'] 
Traceback (most recent call last): 
    File "<pyshell#1>", line 1, in <module> 
    locals()['Ω'] 
KeyError: 'Ω' 
>>> [k for k, v in locals().items() if v == 'bar'][0].encode() 
b'\xce\xa9' 
>>> 'Ω'.encode() 
b'\xe2\x84\xa6' 

तो अंत में, यह सिर्फ कुछ अजगर करता है। दुर्भाग्यवश, इस व्यवहार का पता लगाने के लिए वास्तव में एक अच्छा तरीका नहीं है, जिससे दिखाए गए त्रुटियों का कारण बनता है। आम तौर पर, जब पहचानकर्ता को केवल पहचानकर्ता के रूप में जाना जाता है, यानी यह वास्तविक चर या विशेषता की तरह प्रयोग किया जाता है, तो सब ठीक हो जाएगा: सामान्यीकरण हर बार चलता है, और पहचानकर्ता पाया जाता है।

एकमात्र समस्या स्ट्रिंग-आधारित पहुंच के साथ है। स्ट्रिंग्स केवल तार हैं, निश्चित रूप से कोई सामान्यीकरण नहीं होता है (यह केवल एक बुरा विचार होगा)। और यहां दिखाए गए दो तरीके, getattr और locals, दोनों शब्दकोशों पर काम करते हैं। getattr() ऑब्जेक्ट के __dict__ के माध्यम से किसी ऑब्जेक्ट की विशेषता का उपयोग करता है, और locals() एक शब्दकोश देता है। और शब्दकोशों में, चाबियाँ कोई स्ट्रिंग हो सकती हैं, इसलिए वहां माइक्रोस साइन या ओएचएम साइन इन करना बिल्कुल ठीक है।

उन मामलों में, आपको खुद को सामान्यीकरण करने के लिए याद रखना होगा।हम इस बात के लिए unicodedata.normalize उपयोग कर सकते हैं, जो तब भी हमें सही ढंग से locals() (या का उपयोग कर getattr) अंदर से हमारे लाभ उठा सकें:

>>> normalized_ohm = unicodedata.normalize('NFKC', 'Ω') 
>>> locals()[normalized_ohm] 
'bar' 
+1

कि बहुत ही स्पष्ट और पूरी तरह से किया गया था। मैं अभी भी स्ट्रिंग अक्षर में गैर-ASCII वर्णों से बचने की कोशिश करता हूं, अकेले परिवर्तनीय नाम दें। सामान्यीकरण केवल एक मुद्दा है, कुछ संपादकों द्वारा चीजों को भी उलझाया जा सकता है, एन्कोडिंग को प्रतिलिपि बनाकर कॉपी और पेस्ट कर सकते हैं। 'कक्षा परीक्षण: mu =' foo'' – Galax

+1

जब तक आप अपनी स्रोत फ़ाइलों के लिए यूटीएफ -8 का उपयोग करते हैं (जो आप वास्तव में चाहिए), आप पाइथन 3 के साथ ज्यादातर मामलों में ठीक हैं, खासकर स्ट्रिंग अक्षर में। यदि आपके पास एक संपादक है जो इसे गड़बड़ कर सकता है, तो आपको एक बेहतर संपादक मिलना चाहिए;) और पहचानकर्ताओं के लिए, आप वहां भी रचनात्मक हो सकते हैं, दिखाए गए मुद्दे को छोड़कर जो कुछ के लिए समस्याएं पैदा कर सकता है या दूसरों के लिए पूरी तरह से अनजान हो सकता है :) – poke

संबंधित मुद्दे