2008-11-15 21 views
346

क्या बिल्कुल पाइथन स्कॉइंग नियम हैं?स्कोपिंग नियमों का संक्षिप्त विवरण?

अगर मैं कुछ कोड है:

code1 
class Foo: 
    code2 
    def spam..... 
     code3 
     for code4..: 
     code5 
     x() 

कहाँ एक्स पाया जाता है? पाश के लिए

  1. संलग्नित स्रोत फ़ाइल
  2. वर्ग नाम स्थान
  3. समारोह परिभाषा
  4. पाश सूचकांक चर के लिए
  5. इनसाइड में में: कुछ संभावित विकल्प उपरोक्त सूची में शामिल

निष्पादन के दौरान संदर्भ भी है, जब फ़ंक्शन स्पैम कहीं और पास हो जाता है। और शायद लैम्ब्डा फ़ंक्शन थोड़ा अलग हो जाते हैं?

कहीं भी एक साधारण संदर्भ या एल्गोरिदम होना चाहिए। यह इंटरमीडिएट पायथन प्रोग्रामर के लिए एक भ्रमित दुनिया है।

+2

लोग इस सवाल का थोड़ा "कर्म संपादन" कर कृपया रोक सकते हैं? –

+2

वे सभी "कर्म संपादन" नहीं हैं। कुछ इसलिए हैं क्योंकि लोग समझ में नहीं आता कि चीजें कैसे काम करती हैं। देखें [** _ क्या प्रश्नों में उनके शीर्षक में "टैग" शामिल होना चाहिए? _ **] (https://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles)। – martineau

उत्तर

313

दरअसल, Learning Python, 3rd. Ed. से पाइथन स्कोप रिज़ॉल्यूशन के लिए एक संक्षिप्त नियम। (ये नियम वैरिएबल नामों के लिए विशिष्ट हैं, गुण नहीं। यदि आप इसे बिना किसी अवधि के संदर्भित करते हैं, तो ये नियम लागू होते हैं)

एलईजीबी नियम।

एल, स्थानीय - नाम एक समारोह (def या lambda)) के भीतर किसी भी तरह से सौंपा है, और नहीं है कि समारोह में विश्व की घोषणा की।

, संलग्न-समारोह स्थानीय लोगों - किसी भी और सभी स्थिर enclosing कार्य (def या lambda), भीतर से बाहरी के स्थानीय क्षेत्र में नाम।

जी, ग्लोबल (मॉड्यूल) - नाम एक मॉड्यूल फ़ाइल के शीर्ष-स्तर पर सौंपा, या फ़ाइल के भीतर एक def में एक global बयान को क्रियान्वित करते हुए।

बी, निर्मित (अजगर) - नाम में निर्मित नाम मॉड्यूल में पहले ही असाइन: open, range, SyntaxError, ...

तो,

code1 
class Foo: 
    code2 
    def spam..... 
     code3 
     for code4..: 
     code5 
     x() 
के मामले में

लूप के लिए अपना नामस्थान नहीं है। (code3, code 4, code5 में) स्थानीय, def spam में: LEGB आदेश में, स्कोप होगा

एल।

ई: संलग्न समारोह, किसी भी संलग्न कार्य (अगर पूरी उदाहरण एक और def में थे)

जी: ग्लोबल। क्या मॉड्यूल (code1) में वैश्विक स्तर पर घोषित x था?

बी: पाइथन में कोई भी निर्मित x

xcode2 में कभी नहीं मिल जाएगा (यहां तक ​​कि मामलों आप उम्मीद कर सकते हैं जहां यह, Antti's answer या here देखना होगा में)।

+1

यू ने 'code2' के दायरे को कवर नहीं किया। यह एक चर नहीं है और एक वर्ग/उदाहरण विशेषता है। क्या वह सही है। –

+1

मेरा अंतर्ज्ञान कहता है कि कोड 2 'फू' के वर्ग दायरे के अंदर मौजूद है, और किसी भी स्कोप से 'Foo.c' तक पहुंचने के साथ किसी भी दायरे से या Foo.code2' के साथ या उसी वाक्यविन्यास के साथ 'Foo' के भीतर से पहुंचा जा सकता है। लेकिन मुझे यकीन नहीं है कि यह एलईजीबी निमोनिक के भीतर आता है। –

+30

वैश्विक पहुंच के लिए एक चेतावनी के रूप में - एक वैश्विक चर पढ़ने के बिना स्पष्ट घोषणा के हो सकता है, लेकिन वैश्विक (var_name) घोषित किए बिना इसे लिखना इसके बजाय एक नया स्थानीय उदाहरण बनायेगा। –

8

पायथन आपके चर के साथ हल करता है - आम तौर पर - तीन नामस्थान उपलब्ध हैं।

निष्पादन के दौरान किसी भी समय, वहाँ कम से कम तीन नेस्टेड स्कोप जिसका नामस्थान सीधे जाया जा सकता है कर रहे हैं: अंतरतम गुंजाइश है, जो पहले खोजा गया है, स्थानीय नाम शामिल हैं; किसी भी संलग्न कार्य के नामस्थान, जो निकटतम संलग्न क्षेत्र से शुरू होने वाली खोज की जाती हैं; मध्य गुंजाइश, अगली खोज में, वर्तमान मॉड्यूल के वैश्विक नाम शामिल हैं; और बाहरीतम दायरा (पिछली बार खोजा गया) नामस्थान युक्त अंतर्निहित नाम है। globals और locals जो आप सामग्री इन नामस्थान के दो दिखाने:

दो कार्य कर रहे हैं।

नामस्थान पैकेज, मॉड्यूल, कक्षाएं, ऑब्जेक्ट निर्माण और कार्यों द्वारा बनाए जाते हैं। नामस्थानों के कोई अन्य स्वाद नहीं हैं।

इस मामले में, x नामक फ़ंक्शन पर कॉल को स्थानीय नाम स्थान या वैश्विक नामस्थान में हल किया जाना है।

इस मामले में स्थानीय, विधि फ़ंक्शन Foo.spam का शरीर है।

वैश्विक - अच्छी तरह से वैश्विक है।

नियम विधि कार्यों (और नेस्टेड फ़ंक्शन परिभाषाओं) द्वारा बनाए गए नेस्टेड स्थानीय रिक्त स्थानों को खोजना है, फिर वैश्विक खोजें। बस।

कोई अन्य स्कॉप्स नहीं हैं। for कथन (और अन्य यौगिक बयान जैसे if और try) नए नेस्टेड स्कॉप्स न बनाएं। केवल परिभाषाएं (संकुल, मॉड्यूल, फ़ंक्शंस, कक्षाएं और ऑब्जेक्ट इंस्टेंस।)

कक्षा परिभाषा के अंदर, नाम कक्षा नामस्थान का हिस्सा हैं। उदाहरण के लिए, code2, कक्षा के नाम से योग्यता प्राप्त की जानी चाहिए। आम तौर पर Foo.code2। हालांकि, self.code2 भी काम करेगा क्योंकि पायथन ऑब्जेक्ट्स युक्त श्रेणी को फॉल-बैक के रूप में देखते हैं।

एक ऑब्जेक्ट (कक्षा का एक उदाहरण) में आवृत्ति चर है। ये नाम वस्तु के नामस्थान में हैं। उन्हें वस्तु द्वारा योग्यता प्राप्त की जानी चाहिए। (variable.instance।)

कक्षा विधि के भीतर से, आपके पास स्थानीय और ग्लोबल्स हैं। नामस्थान के रूप में उदाहरण लेने के लिए आप self.variable कहते हैं। आप ध्यान दें कि self प्रत्येक वर्ग सदस्य फ़ंक्शन के लिए एक तर्क है, जो इसे स्थानीय नामस्थान का हिस्सा बना देता है।

Python Scope Rules, Python Scope, Variable Scope देखें।

+4

यह पुराना है। चूंकि 2.1 (7 साल पहले) दो से अधिक स्कॉप्स हैं, क्योंकि नेस्टेड फ़ंक्शंस नए स्कोप पेश करते हैं, इसलिए फ़ंक्शन के भीतर एक फ़ंक्शन के पास स्थानीय दायरे, संलग्न कार्यक्षेत्र, और वैश्विक दायरे (भी अंतर्निहित) तक पहुंच होगी। – Brian

+0

मुझे खेद है, यह अब मामला नहीं है। 'पायथन के पास दो नामस्थान उपलब्ध हैं। वैश्विक और स्थानीय-से-कुछ। –

5

एक्स कहाँ मिला है?

x नहीं मिला है क्योंकि आपने इसे परिभाषित नहीं किया है। :-) यदि आप इसे वहां डालते हैं तो यह कोड 1 (वैश्विक) या कोड 3 (स्थानीय) में पाया जा सकता है।

कोड 2 (कक्षा के सदस्य) एक ही कक्षा के तरीकों के अंदर कोड के लिए दृश्यमान नहीं हैं - आप आमतौर पर स्वयं का उपयोग करके उन्हें एक्सेस करेंगे। कोड 4/कोड 5 (लूप) कोड 3 के समान दायरे में रहते हैं, इसलिए यदि आपने वहां एक्स को लिखा है तो आप कोड 3 में परिभाषित एक्स इंस्टेंस को बदल देंगे, न कि नया एक्स बनाये।

पायथन स्थिर रूप से स्कॉप्ड है, इसलिए यदि आप किसी अन्य फ़ंक्शन पर 'स्पैम' पास करते हैं तो स्पैम के पास अभी भी मॉड्यूल में (कोड 1 में परिभाषित), और किसी अन्य युक्त स्कॉप्स (नीचे देखें) से ग्लोबल्स तक पहुंच होगी। कोड 2 सदस्यों को फिर से स्वयं के माध्यम से पहुंचाया जाएगा।

लैम्ब्डा डीफ़ के लिए अलग नहीं है। यदि आपके पास एक फ़ंक्शन के अंदर प्रयोग किया जाने वाला लैम्ब्डा है, तो यह एक नेस्टेड फ़ंक्शन को परिभाषित करने जैसा ही है। पायथन 2.2 के बाद, नेस्टेड स्कॉप्स उपलब्ध हैं। इस मामले में आप समारोह घोंसले के किसी भी स्तर पर एक्स बाध्य कर सकते हैं और अजगर अंतरतम उदाहरण लेने देगा:

x= 0 
def fun1(): 
    x= 1 
    def fun2(): 
     x= 2 
     def fun3(): 
      return x 
     return fun3() 
    return fun2() 
print fun1(), x 

2 0 

fun3 निकटतम युक्त गुंजाइश है, जो fun2 के साथ जुड़े समारोह गुंजाइश है से उदाहरण एक्स देखता है। लेकिन मजेदार 1 और वैश्विक स्तर पर परिभाषित अन्य एक्स उदाहरण प्रभावित नहीं हैं।

nested_scopes से पहले - पायथन प्री-2.1 में, और 2.1 में जब तक कि आप विशेष रूप से एक भविष्य-आयात-fun1 और fun2 के scopes का उपयोग करके सुविधा के लिए पूछें, fun3 के लिए दृश्यमान नहीं हैं, इसलिए एसएलॉट का जवाब है और आप करेंगे वैश्विक एक्स प्राप्त करें:

0 0 
20

पायथन 2.x के लिए स्कॉइंग नियम पहले से ही अन्य उत्तरों में उल्लिखित हैं। केवल एक चीज जो मैं जोड़ूंगा वह है कि पायथन 3.0 में, एक गैर-स्थानीय क्षेत्र की अवधारणा भी है ('nonlocal' कीवर्ड द्वारा इंगित)। यह आपको सीधे बाहरी क्षेत्रों तक पहुंचने की अनुमति देता है, और कुछ साफ चाल करने की क्षमता को खोलता है, जिसमें लेक्सिकल क्लोजर (म्यूटेबल ऑब्जेक्ट्स सहित बदसूरत हैक के बिना) शामिल हैं।

संपादित करें: इस पर अधिक जानकारी के साथ PEP है।

128

अनिवार्य रूप से, पाइथन में एकमात्र चीज जो एक नया दायरा पेश करती है वह एक कार्य परिभाषा है। कक्षाएं एक विशेष मामले का एक मामला है जिसमें शरीर में सीधे परिभाषित कुछ भी कक्षा के नामस्थान में रखा जाता है, लेकिन वे उन विधियों (या घोंसला वाले वर्गों) में सीधे पहुंच नहीं पाते हैं।

अपने उदाहरण में केवल 3 स्कोप जहां एक्स में खोज की जाएगी देखते हैं:

  • स्पैम की गुंजाइश - सब कुछ code3 और code5 में परिभाषित (और साथ ही code4, अपने पाश चर)

  • युक्त

    वैश्विक दायरा - जिसमें कोड 1 में परिभाषित सब कुछ शामिल है, साथ ही साथ फू (और उसके बाद जो भी परिवर्तन)

  • बिल्टिन नेमस्पेस। एक विशेष मामला - इसमें विभिन्न पायथन निर्मित कार्य और प्रकार जैसे लेन() और str() शामिल हैं।आम तौर पर इसे किसी भी उपयोगकर्ता कोड द्वारा संशोधित नहीं किया जाना चाहिए, इसलिए मानक कार्यों को शामिल करने की अपेक्षा करें और कुछ भी नहीं।

अधिक स्कॉप्स केवल तब दिखाई देते हैं जब आप तस्वीर में नेस्टेड फ़ंक्शन (या लैम्ब्डा) पेश करते हैं। हालांकि आप अपेक्षा करेंगे कि ये बहुत अधिक व्यवहार करेंगे। नेस्टेड फ़ंक्शन स्थानीय दायरे में, साथ ही साथ संलग्न कार्य के दायरे में कुछ भी एक्सेस कर सकता है। जैसे।

def foo(): 
    x=4 
    def bar(): 
     print x # Accesses x from foo's scope 
    bar() # Prints 4 
    x=5 
    bar() # Prints 5 

प्रतिबंध: से स्थानीय समारोह के चर पहुँचा जा सकता है अन्य कार्यक्षेत्रों में

चर, लेकिन आगे वाक्य रचना के बिना नई मापदंडों के पलटाव नहीं हो सकता। इसके बजाए, असाइनमेंट माता-पिता के दायरे में चर को प्रभावित करने के बजाय एक नया स्थानीय वैरिएबल बनाएगा। उदाहरण के लिए:

global_var1 = [] 
global_var2 = 1 

def func(): 
    # This is OK: It's just accessing, not rebinding 
    global_var1.append(4) 

    # This won't affect global_var2. Instead it creates a new variable 
    global_var2 = 2 

    local1 = 4 
    def embedded_func(): 
     # Again, this doen't affect func's local1 variable. It creates a 
     # new local variable also called local1 instead. 
     local1 = 5 
     print local1 

    embedded_func() # Prints 5 
    print local1 # Prints 4 

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

global_var = 4 
def change_global(): 
    global global_var 
    global_var = global_var + 1 

इस समय वहाँ समारोह स्कोप enclosing में चर के लिए भी ऐसा ही करने का कोई तरीका नहीं है जो वैश्विक करने के लिए एक समान तरीके से कार्य करेगा है, लेकिन अजगर 3 एक नया कीवर्ड का परिचय है, "nonlocal", लेकिन के लिए नेस्टेड फ़ंक्शन स्कोप्स।

78

पायथन 3 समय से संबंधित कोई गहन जवाब नहीं था, इसलिए मैंने यहां एक जवाब दिया।

जैसा कि अन्य उत्तरों में प्रदान किया गया है, स्थानीय, संलग्न, वैश्विक और बिल्टिन के लिए 4 मूलभूत क्षेत्र, एलईजीबी हैं। उनके अलावा, एक विशेष दायरा है, कक्षा निकाय, जिसमें कक्षा के भीतर परिभाषित विधियों के लिए एक संलग्न क्षेत्र शामिल नहीं है; कक्षा निकाय के भीतर कोई असाइनमेंट क्लास बॉडी में बाध्य होने पर चर से बना देता है।

विशेष रूप से, कोई ब्लॉक स्टेटमेंट, def और class के अलावा, एक चरणीय दायरा बनाएं। पायथन 2 में सूची समझ एक चरणीय दायरा नहीं बनाती है, हालांकि पायथन 3 में लूप वैरिएबल एक नए दायरे में बनाया गया है।

x = 0 
class X(object): 
    y = x 
    x = x + 1 # x is now a variable 
    z = x 

    def method(self): 
     print(self.x) # -> 1 
     print(x)  # -> 0, the global x 
     print(y)  # -> NameError: global name 'y' is not defined 

inst = X() 
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0) 

इस प्रकार वर्ग शरीर के peculiarities प्रदर्शित करने के लिए विपरीत समारोह शरीर में, आप चर एक ही नाम के लिए कक्षा शरीर में पुन: असाइन कर सकते हैं, एक ही नाम के साथ एक वर्ग चर प्राप्त करने के लिए; इस नाम पर आगे लुकअप के बजाय कक्षा चर के लिए हल करें।


पायथन के लिए कई नए लोगों के लिए अधिक से अधिक आश्चर्य में से एक है कि एक for पाश एक चर गुंजाइश नहीं बना होता है। पायथन 2 में सूची की समझ या तो एक गुंजाइश नहीं बनाती है (जबकि जनरेटर और dict समझें करते हैं!) इसके बजाय वे या समारोह में मूल्य वैश्विक क्षेत्र रिसाव:

>>> [ i for i in range(5) ] 
>>> i 
4 

comprehensions या यदि आप होगा एक चालाक के रूप में इस्तेमाल किया जा सकता (भयंकर) जिस तरह से अजगर 2 में लैम्ब्डा भाव भीतर परिवर्तनीय चर बनाने के लिए - एक लैम्ब्डा अभिव्यक्ति एक चरणीय दायरा बनाती है, जैसे def कथन, लेकिन लैम्ब्डा के भीतर कोई बयान नहीं है। पाइथन में एक कथन होने का मतलब है कि लैम्ब्डा में कोई वैरिएबल असाइनमेंट नहीं है, लेकिन एक सूची समझ एक अभिव्यक्ति है ...

यह व्यवहार पायथन 3 में तय किया गया है - कोई समझ अभिव्यक्ति या जनरेटर लीक चर नहीं।


वैश्विक वास्तव में मॉड्यूल का दायरा है; मुख्य पायथन मॉड्यूल __main__ है; सभी आयातित मॉड्यूल sys.modules चर के माध्यम से सुलभ हैं; __main__ तक पहुंच प्राप्त करने के लिए कोई sys.modules['__main__'], या import __main__ का उपयोग कर सकता है; यह वहां पहुंचने और असाइन करने के लिए पूरी तरह से स्वीकार्य है; वे मुख्य मॉड्यूल के वैश्विक दायरे में चर के रूप में दिखाई देंगे।


एक नाम कभी (वर्ग दायरे को छोड़कर) वर्तमान क्षेत्र में करने के लिए सौंपा गया है, तो यह है कि गुंजाइश से संबंधित विचार किया जाएगा, अन्यथा यह किसी भी संलग्न गुंजाइश है कि करने के लिए प्रदान करती है से संबंधित करने के लिए विचार किया जाएगा चर (यह अभी तक असाइन नहीं किया जा सकता है, या बिल्कुल नहीं), या अंत में वैश्विक दायरा। यदि चर को स्थानीय माना जाता है, लेकिन यह अभी तक सेट नहीं है, या हटा दिया गया है, तो वैरिएबल मान पढ़ने से UnboundLocalError होगा, जो NameError का उप-वर्ग है।

x = 5 
def foobar() 
    print(x) # UnboundLocalError! 
    x += 1 # assignment here makes x a local variable! 

गुंजाइश घोषणा कर सकते हैं यह स्पष्ट रूप से वैश्विक कीवर्ड के साथ वैश्विक (मॉड्यूल गुंजाइश) अलग-अलग संशोधित करने के लिए चाहता है:

x = 5 
def foobar(): 
    global x 
    print(x) # -> 5 
    x += 1 

foobar() 
print(x) # -> 6 

यह भी संभव है, भले ही यह गुंजाइश enclosing में छायांकित किया गया था:

x = 5 
y = 13 
def make_closure(): 
    x = 42 
    y = 911 
    def func(): 
     global x # sees the global value 
     print(x, y) 
     x += 1 

    return func 

func = make_closure() 
func()  # -> print 5 911 
print(x, y) # -> 6 13 

पायथन 2 में संलग्न क्षेत्र में मूल्य को संशोधित करने का कोई आसान तरीका नहीं है;

def make_closure(): 
    value = [0] 
    def get_next_value(): 
     value[0] += 1 
     return value[0] 

    return get_next_value 

get_next = make_closure() 
print(get_next()) # -> 1 
print(get_next()) # -> 2 
अजगर 3 में

हालांकि, nonlocal बचाव के लिए आता: आम तौर पर इस तरह के 1 की लंबाई के साथ एक सूची के रूप में एक परिवर्तनशील मूल्य, होने से नकली है

def make_closure(): 
    value = 0 
    def get_next_value(): 
     nonlocal value 
     value += 1 
     return value 
    return get_next_value 

get_next = make_closure() # identical behavior to the previous example. 

किसी भी चर वर्तमान दायरे, या किसी भी संलग्न क्षेत्र के लिए स्थानीय माना जाता है, एक वैश्विक चर है। मॉड्यूल वैश्विक शब्दकोश में वैश्विक नाम देखा गया है; यदि नहीं मिला, तो ग्लोबल को बिल्टिन मॉड्यूल से देखा जाता है; मॉड्यूल का नाम पायथन 2 से पायथन 3 में बदल दिया गया था; पायथन 2 में यह __builtin__ था और पायथन 3 में इसे अब builtins कहा जाता है। यदि आप बिल्टिन मॉड्यूल की विशेषता को असाइन करते हैं, तो इसके बाद किसी भी मॉड्यूल को पठनीय वैश्विक चर के रूप में दिखाई देगा, जब तक कि मॉड्यूल उन्हें उसी नाम से अपने वैश्विक चर के साथ छाया न करे।


बिल्टिन मॉड्यूल पढ़ना भी उपयोगी हो सकता है; मान लीजिए कि आप फ़ाइल के कुछ हिस्सों में पाइथन 3 स्टाइल प्रिंट फ़ंक्शन चाहते हैं, लेकिन फ़ाइल के अन्य भाग अभी भी print कथन का उपयोग करते हैं, यदि आपका पायथन संस्करण> = 2 है।6, आप नई शैली समारोह प्राप्त कर सकते हैं के रूप में:

import __builtin__ 

print3 = __builtin__.__dict__['print'] 

from __future__ import print_function वास्तव में print समारोह आयात नहीं करता है अजगर 2 में कहीं भी - के बजाय यह सिर्फ, वर्तमान मॉड्यूल में print बयान के लिए पार्स नियम को निष्क्रिय तरह print से निपटने कोई अन्य परिवर्तनीय पहचानकर्ता, और इस प्रकार print फ़ंक्शन को बिल्टिन में देखा जा सकता है।

18

एक दायरे से थोड़ा अधिक पूर्ण उदाहरण:

from __future__ import print_function # for python 2 support 

x = 100 
print("1. Global x:", x) 
class Test(object): 
    y = x 
    print("2. Enclosed y:", y) 
    x = x + 1 
    print("3. Enclosed x:", x) 

    def method(self): 
     print("4. Enclosed self.x", self.x) 
     print("5. Global x", x) 
     try: 
      print(y) 
     except NameError as e: 
      print("6.", e) 

    def method_local_ref(self): 
     try: 
      print(x) 
     except UnboundLocalError as e: 
      print("7.", e) 
     x = 200 # causing 7 because has same name 
     print("8. Local x", x) 

inst = Test() 
inst.method() 
inst.method_local_ref() 

उत्पादन:

1. Global x: 100 
2. Enclosed y: 100 
3. Enclosed x: 101 
4. Enclosed self.x 101 
5. Global x 100 
6. global name 'y' is not defined 
7. local variable 'x' referenced before assignment 
8. Local x 200 
+3

यह बहुत अच्छा जवाब है। हालांकि, मुझे लगता है कि 'विधि' और' method_local_ref' के बीच अंतर को हाइलाइट किया जाना चाहिए। 'विधि' वैश्विक चर तक पहुंचने में सक्षम है और इसे' 5 में प्रिंट करें। वैश्विक एक्स'। लेकिन 'method_local_ref' ऐसा नहीं कर सकता क्योंकि बाद में यह उसी नाम के साथ एक स्थानीय चर परिभाषित करता है। आप 'x = 200' लाइन को हटाकर इसका परीक्षण कर सकते हैं और अंतर – kiril

+0

@brianray देखें: z के बारे में क्या? –

+0

@kiril मैंने उस – brianray

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