2012-04-12 10 views
25

मैं गतिशील रूप से पाइथन कक्षाएं बना रहा हूं, और मुझे नहीं पता कि सभी वर्ण इस संदर्भ में मान्य नहीं हैं।एक पायथन वर्ग नाम में वैध वर्ण

क्या कक्षा पुस्तकालय में कहीं भी कोई तरीका है जिसका उपयोग मैं यादृच्छिक पाठ स्ट्रिंग को स्वच्छ करने के लिए कर सकता हूं, ताकि मैं इसे कक्षा के नाम के रूप में उपयोग कर सकूं? या तो अनुमति दी गई पात्रों की एक सूची एक अच्छी मदद होगी।


पहचानकर्ता नाम के साथ हुई मुठभेड़ के बारे में अतिरिक्त: @Ignacio की तरह नीचे जवाब में बताया, किसी भी चरित्र है कि है valid as an identifier एक वर्ग के नाम में मान्य वर्ण नहीं है। और आप बिना किसी परेशानी के कक्षा नाम के रूप में reserved word का भी उपयोग कर सकते हैं। लेकिन एक पकड़ है। यदि आप आरक्षित शब्द का उपयोग करते हैं, तो आप कक्षा को अन्य (गैर-गतिशील रूप से निर्मित) कक्षाओं (उदाहरण के लिए, globals()[my_class.__name__] = my_class करके) तक पहुंचने में सक्षम नहीं होंगे। इस तरह के मामले में आरक्षित शब्द हमेशा प्राथमिकता लेगा।

+3

और नीचे वोट का कारण है ...? यह एक मूल प्रश्न है, लेकिन फिर भी वैध है: +1। – EOL

+0

नाम 'कोई नहीं' या '__debug__' नाम से कक्षा बनाने का प्रयास क्या करता है? निम्नलिखित दस्तावेज़ों के मुताबिक, मैं इसे 'सिंटेक्स त्रुटि' बढ़ाने की अपेक्षा करता हूं: https://docs.python.org/2/library/constants.html – ArtOfWarfare

उत्तर

33

Python Language Reference, §2.3, "Identifiers and keywords"

पहचानकर्ता (जिसे नाम कहा जाता है) निम्नलिखित शाब्दिक परिभाषाओं से वर्णित हैं:

identifier ::= (letter|"_") (letter | digit | "_")* 
letter  ::= lowercase | uppercase 
lowercase ::= "a"..."z" 
uppercase ::= "A"..."Z" 
digit  ::= "0"..."9" 

पहचानकर्ता लंबाई में असीमित हैं। मामला महत्वपूर्ण है।

+0

बिल्कुल सही, धन्यवाद –

+2

वैध पहचानकर्ता परिभाषित करने के लिए नियमित अभिव्यक्ति का उपयोग किया जाता है: 'पहचानकर्ता :: = (पत्र |" _ ") (अक्षर | अंक |" _ ") *'। (शायद आप इस जवाब में अपने उत्तर में कुछ जोड़ना चाहते हैं ताकि उपयोगकर्ताओं को वेबपृष्ठ खोजना पड़े?) –

+0

पेडेंटिक होने के लिए, यह एक regex @ शून्य-सूचक नहीं है - यह एक व्याकरण है। – Qix

5

यह बात यह है कि यह दिलचस्प बनाता है कि पहचानकर्ता का पहला चरित्र विशेष है। पहले चरित्र के बाद, '9' के माध्यम से संख्या '0' पहचानकर्ताओं के लिए मान्य हैं, लेकिन वे पहले अक्षर नहीं होने चाहिए।

यहां एक ऐसा फ़ंक्शन है जो किसी मान्य पहचानकर्ता को वर्णों की यादृच्छिक स्ट्रिंग प्रदान करेगा। यहां बताया गया है कि यह कैसे काम करता है:

सबसे पहले, हम इनपुट पर एक स्पष्ट इटरेटर प्राप्त करने के लिए itr = iter(seq) का उपयोग करते हैं। फिर एक पहला लूप होता है, जो अक्षरों को देखने के लिए इटरेटर itr का उपयोग करता है जब तक कि यह पहचानकर्ता के लिए मान्य पहले वर्ण नहीं मिलता है। फिर यह उस लूप से बाहर हो जाता है और दूसरा लूप, दूसरे लूप के लिए उसी इटरेटर (जिसे हमने itr नाम दिया) का उपयोग करके चलाया। इटेटर itr हमारे लिए हमारी जगह रखता है; दूसरे लूप रन होने पर पात्रों को पहले लूप को इटरेटर से बाहर खींच लिया जाता है।

def gen_valid_identifier(seq): 
    # get an iterator 
    itr = iter(seq) 
    # pull characters until we get a legal one for first in identifer 
    for ch in itr: 
     if ch == '_' or ch.isalpha(): 
      yield ch 
      break 
    # pull remaining characters and yield legal ones for identifier 
    for ch in itr: 
     if ch == '_' or ch.isalpha() or ch.isdigit(): 
      yield ch 

def sanitize_identifier(name): 
    return ''.join(gen_valid_identifier(name)) 

अनुक्रम दो अलग-अलग तरीकों को संभालने के लिए यह एक साफ और पायथनिक तरीका है।

def gen_valid_identifier(seq): 
    saw_first_char = False 
    for ch in seq: 
     if not saw_first_char and (ch == '_' or ch.isalpha()): 
      saw_first_char = True 
      yield ch 
     elif saw_first_char and (ch == '_' or ch.isalpha() or ch.isdigit()): 
      yield ch 

मैं इस संस्करण पहले संस्करण के रूप में लगभग उतना ही पसंद नहीं है: एक समस्या इस सरल के लिए, हम सिर्फ एक बूलियन चर इंगित करता है कि क्या हम अभी तक या नहीं पहले वर्ण देखा है हो सकता था। एक चरित्र के लिए विशेष हैंडलिंग अब नियंत्रण के पूरे प्रवाह में उलझी हुई है, और यह पहले संस्करण की तुलना में धीमी हो जाएगी क्योंकि इसे saw_first_char के मूल्य की जांच करना जारी रखना है। लेकिन इस तरह से आपको अधिकांश भाषाओं में नियंत्रण के प्रवाह को संभालना होगा! पायथन का स्पष्ट इटरेटर एक निफ्टी फीचर है, और मुझे लगता है कि यह इस कोड को बहुत बेहतर बनाता है।

एक स्पष्ट पुनरावर्तक पर लूपिंग के रूप में तेजी से दे अजगर परोक्ष आप के लिए एक इटरेटर मिल के रूप में बस है, और स्पष्ट इटरेटर हमें छोरों कि पहचानकर्ता के विभिन्न भागों के लिए अलग नियम संभाल विभाजित करने देता है। तो स्पष्ट इटरेटर हमें क्लीनर कोड देता है जो तेजी से चलता है। जीत/जीत।regex में

(letter|"_") (letter | digit | "_")* 

या,:

+0

आपके पास 'itr = iter (seq)' line क्यों है ... सी में सीक के लिए नहीं होगा: 'सटीक समान परिणाम हैं, वही बेहतर प्रदर्शन नहीं करते हैं, और बेहतर पठनीयता? – ArtOfWarfare

+0

@ArtOfWarfare मैंने व्याख्या करने के लिए उत्तर संपादित किया है। – steveha

+0

हू। मैंने पहले कभी नहीं देखा है। मैं अगली बार उस डिजाइन को दिमाग में रखूंगा, इसी तरह मुझे पुनरावृत्ति के पहले और बाद में संभालने की ज़रूरत है। – ArtOfWarfare

1

यह अब तक एक पुराने सवाल है, लेकिन मैं चाहता हूँ पाइथन 3 में ऐसा करने के तरीके पर एक उत्तर जोड़ने के लिए मैंने एक कार्यान्वयन किया है।

अनुमत वर्ण यहां दस्तावेज़ित हैं: https://docs.python.org/3/reference/lexical_analysis.html#identifiers। उनमें विराम चिह्न, अंडरस्कोर, और पूरी तरह से विदेशी पात्रों सहित कई विशेष पात्र शामिल हैं। सौभाग्य से unicodedata मॉड्यूल मदद कर सकता है।

import unicodedata 

def is_valid_name(name): 
    if not _is_id_start(name[0]): 
     return False 
    for character in name[1:]: 
     if not _is_id_continue(character): 
      return False 
    return True #All characters are allowed. 

_allowed_id_continue_categories = {"Ll", "Lm", "Lo", "Lt", "Lu", "Mc", "Mn", "Nd", "Nl", "Pc"} 
_allowed_id_continue_characters = {"_", "\u00B7", "\u0387", "\u1369", "\u136A", "\u136B", "\u136C", "\u136D", "\u136E", "\u136F", "\u1370", "\u1371", "\u19DA", "\u2118", "\u212E", "\u309B", "\u309C"} 
_allowed_id_start_categories = {"Ll", "Lm", "Lo", "Lt", "Lu", "Nl"} 
_allowed_id_start_characters = {"_", "\u2118", "\u212E", "\u309B", "\u309C"} 

def _is_id_start(character): 
    return unicodedata.category(character) in _allowed_id_start_categories or character in _allowed_id_start_categories or unicodedata.category(unicodedata.normalize("NFKC", character)) in _allowed_id_start_categories or unicodedata.normalize("NFKC", character) in _allowed_id_start_characters 

def _is_id_continue(character): 
    return unicodedata.category(character) in _allowed_id_continue_categories or character in _allowed_id_continue_characters or unicodedata.category(unicodedata.normalize("NFKC", character)) in _allowed_id_continue_categories or unicodedata.normalize("NFKC", character) in _allowed_id_continue_characters 

इस कोड CC0 के तहत यहां से अनुकूलित है: https://github.com/Ghostkeeper/Luna/blob/d69624cd0dd5648aec2139054fae4d45b634da7e/plugins/data/enumerated/enumerated_type.py#L91 यहाँ मेरी कार्यान्वयन सीधे लागू करने क्या अजगर प्रलेखन कहते है। यह अच्छी तरह से परीक्षण किया गया है।