आपको पायथन पद्धति में स्पष्ट रूप से "स्व" तर्क की आवश्यकता क्यों है?


197

पायथन में एक वर्ग पर एक विधि को परिभाषित करते समय, यह कुछ इस तरह दिखता है:

class MyClass(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

लेकिन कुछ अन्य भाषाओं में, जैसे कि C #, आपके पास ऑब्जेक्ट का एक संदर्भ है कि विधि "इस" कीवर्ड के साथ विधि प्रोटोटाइप में एक तर्क के रूप में घोषित किए बिना बाध्य है।

क्या यह पायथन में एक जानबूझकर भाषा डिजाइन निर्णय था या क्या कुछ कार्यान्वयन विवरण हैं जिन्हें तर्क के रूप में "स्वयं" के पारित होने की आवश्यकता है?


15
मुझे यकीन है कि आपको यह जानने में भी दिलचस्पी होगी कि आपको selfसदस्यों तक पहुंचने के लिए स्पष्ट रूप से लिखने की आवश्यकता क्यों है - stackoverflow.com/questions/910020/…
Piotr Dobrogost

1
लेकिन यह एक बॉयलर प्लेट की तरह दिखता है
रघुवीर

भ्रामक थोड़ा लेकिन लायक समझ stackoverflow.com/a/31367197/1815624
CrandellWS

जवाबों:


91

मुझे पीटरसन के ज़ेन को उद्धृत करना पसंद है। "निहितार्थ की तुलना में स्पष्ट है।"

जावा और C ++ में, ' this.' को घटाया जा सकता है, सिवाय इसके कि जब आपके पास परिवर्तनशील नाम हैं जो कटौती करना असंभव बनाते हैं। तो आपको कभी-कभी इसकी आवश्यकता होती है और कभी-कभी नहीं।

पायथन एक नियम के आधार पर इस तरह की चीजों को स्पष्ट करने के लिए चुनाव करता है।

इसके अतिरिक्त, चूंकि कुछ भी निहित या ग्रहण नहीं किया गया है, कार्यान्वयन के कुछ हिस्सों को उजागर किया गया है। self.__class__, self.__dict__और अन्य "आंतरिक" संरचनाएं एक स्पष्ट तरीके से उपलब्ध हैं।


53
हालांकि जब आप इसे भूल जाते हैं तो कम गुप्त त्रुटि संदेश होना अच्छा होगा।
मार्टिन बेकेट 23

9
हालाँकि जब आप किसी विधि को कॉल करते हैं तो आपको ऑब्जेक्ट वैरिएबल पास नहीं करना पड़ता है, क्या यह खोजकर्ता के नियम को नहीं तोड़ता है? अगर इस ज़ेन को रखना है, तो इसे कुछ इस तरह होना चाहिए: object.method (ऑब्जेक्ट, param1, param2)। किसी तरह असंगत लग रहा है ...
वेदांत

10
"स्पष्ट रूप से निहित से बेहतर है" - अंतर्निहित होने वाली चीजों के आसपास निर्मित अजगर की "शैली" नहीं है? जैसे अंतर्निहित डेटा प्रकार, अंतर्निहित फ़ंक्शन सीमाएँ (कोई {} 's), अंतर्निहित चर गुंजाइश ... यदि मॉड्यूल में वैश्विक चर कार्यों में उपलब्ध हैं ... तो वही तर्क / तर्क कक्षाओं में क्यों नहीं लागू किए जाने चाहिए? क्या सरलीकृत नियम सिर्फ "उच्च स्तर पर घोषित कुछ भी निचले स्तर पर उपलब्ध नहीं है" जैसा कि इंडेंटेशन द्वारा निर्धारित किया जाएगा?
सिमोन

13
"स्पष्ट रूप से निहित से बेहतर है" बकवास का पता चला
वाहिद अमीरी

10
चलो इसका सामना करते हैं, यह सिर्फ बुरा है। इसके लिए कोई माफी नहीं है। यह सिर्फ एक बदसूरत अवशेष है लेकिन यह ठीक है।
17

63

यह तरीकों और कार्यों के बीच अंतर को कम करने के लिए है। यह आपको मेटाक्लेज़ में आसानी से तरीके उत्पन्न करने, या पूर्व-मौजूदा कक्षाओं के लिए रनटाइम में विधियाँ जोड़ने की अनुमति देता है।

जैसे

>>> class C(object):
...     def foo(self):
...         print "Hi!"
...
>>>
>>> def bar(self):
...     print "Bork bork bork!"
...
>>>
>>> c = C()
>>> C.bar = bar
>>> c.bar()
Bork bork bork!
>>> c.foo()
Hi!
>>>

यह भी (जहाँ तक मुझे पता है) अजगर क्रम के कार्यान्वयन को आसान बनाता है।


10
+1 के लिए यह तरीकों और कार्यों के बीच अंतर को कम करने के लिए है। इसका उत्तर स्वीकार किया जाना चाहिए
उपयोगकर्ता

यह भी दिशानिर्देशों की बहुत जुड़ी व्याख्या के मूल में है।
मार्सिन

1
इससे यह भी पता चलता है कि पायथन में, जब आप c.bar करते हैं () पहले यह विशेषताओं के लिए उदाहरण की जाँच करता है, तब यह वर्ग विशेषताओं की जाँच करता है। इसलिए आप किसी भी कक्षा में किसी डेटा या फ़ंक्शन (ऑब्जेक्ट) को 'अटैच' कर सकते हैं और इसके उदाहरण (यानी डीआईआर) का उपयोग करने की उम्मीद करेंगे। सिर्फ तब नहीं जब आपने "c" बनाया है। यह बहुत गतिशील है।
निशांत

10
मैं वास्तव में इसे नहीं खरीदता। यहां तक ​​कि उन मामलों में जहां आपको मूल वर्ग की आवश्यकता होती है, तब भी आप इसे निष्पादित कर सकते हैं। और उदाहरण के तरीकों और वर्ग कार्यों के बीच समानता है उदाहरणों मूर्खतापूर्ण है; रूबी उनके बिना ही ठीक करती है।
17

2
जावास्क्रिप्ट आपको रन-टाइम में किसी ऑब्जेक्ट में विधियाँ जोड़ने की अनुमति देता है, और इसके selfलिए फ़ंक्शन डिक्लेरेशन की आवश्यकता नहीं होती है (माइंड यू, शायद यह कांच के घर से पत्थर फेंक रहा है, क्योंकि जावास्क्रिप्ट में कुछ पेचीदा thisबाध्यकारी शब्दार्थ हैं)
जोनाथन बेन

55

मेरा सुझाव है कि किसी को इस विषय पर गुइडो वैन रोसुम के ब्लॉग को पढ़ना चाहिए - क्यों स्पष्ट स्व को रहना है

जब एक विधि परिभाषा सजाई जाती है, तो हम यह नहीं जानते कि क्या यह स्वचालित रूप से 'स्व' पैरामीटर देता है या नहीं: सज्जाकार कार्य को स्थैतिक विधि में बदल सकता है (जिसमें कोई 'स्व' नहीं है), या एक वर्ग विधि (जो एक मज़ेदार तरह का स्व है जो एक उदाहरण के बजाय एक वर्ग को संदर्भित करता है), या यह पूरी तरह से अलग कुछ कर सकता है (यह एक सजावट लिखने के लिए तुच्छ है जो शुद्ध पायथन में '@classmethod' या '@staticmethod') को लागू करता है)। यह जानने का कोई तरीका नहीं है कि डेकोरेटर एक निहित 'स्व ’तर्क के साथ परिभाषित की जा रही विधि को समाप्त करने के लिए क्या करता है या नहीं।

मैं विशेष-आवरण '@classmethod' और '@staticmethod' जैसे हैक को अस्वीकार करता हूं।


16

अजगर "आत्म" का उपयोग करने पर आपको मजबूर नहीं करता है। आप जो चाहे नाम दे सकते हैं। आपको बस यह याद रखना है कि विधि परिभाषा हेडर में पहला तर्क ऑब्जेक्ट का संदर्भ है।


अधिवेशन के अनुसार, उदाहरण के लिए यह 'स्व' होना चाहिए या 'cls' जहाँ प्रकार शामिल हैं (mmmm
metaclasses

1
यह हर विधि में पहले परम के रूप में स्वयं को डालने के लिए मजबूर करता है, बस अतिरिक्त पाठ जो मेरे लिए बहुत मायने नहीं रखता है। अन्य भाषाएँ इसके साथ ठीक काम करती हैं।
वेदांत

क्या मैं सही हू ? हमेशा पहला पैरामीटर ऑब्जेक्ट का संदर्भ होता है।
मोहम्मद महदी कौचायजादी

@MMKY नहीं, उदाहरण के लिए @staticmethodयह नहीं है।
मार्क

1
"आपको बस याद रखना होगा कि एक विधि परिभाषा में पहला तर्क ..." मैंने "आत्म" शब्द को "क्वेजिबो" में बदलने के साथ प्रयोग किया और यह अभी भी काम कर रहा है। इसलिए जैसा कि अक्सर समझाया जाता है, यह "आत्म" शब्द नहीं है जो महत्वपूर्ण है लेकिन उस स्थान पर (जो?) में से जो कुछ भी होता है , उसकी स्थिति
RBV

7

आपको यह करने की अनुमति भी देता है: (संक्षेप में, इनवोकिंग Outer(3).create_inner_class(4)().weird_sum_with_closure_scope(5)12 पर वापस आ जाएगी, लेकिन ऐसा पागलपन के तरीकों से होगा।

class Outer(object):
    def __init__(self, outer_num):
        self.outer_num = outer_num

    def create_inner_class(outer_self, inner_arg):
        class Inner(object):
            inner_arg = inner_arg
            def weird_sum_with_closure_scope(inner_self, num)
                return num + outer_self.outer_num + inner_arg
        return Inner

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

इसके अलावा, इसकी कल्पना करें: हम तरीकों के व्यवहार (प्रोफाइलिंग या कुछ पागल काले जादू के लिए) को अनुकूलित करना चाहते हैं। यह हमें सोचने के लिए प्रेरित कर सकता है: क्या होगा यदि हमारे पास एक वर्ग है Methodजिसका व्यवहार हम ओवरराइड या नियंत्रण कर सकते हैं?

यहाँ यह है:

from functools import partial

class MagicMethod(object):
    """Does black magic when called"""
    def __get__(self, obj, obj_type):
        # This binds the <other> class instance to the <innocent_self> parameter
        # of the method MagicMethod.invoke
        return partial(self.invoke, obj)


    def invoke(magic_self, innocent_self, *args, **kwargs):
        # do black magic here
        ...
        print magic_self, innocent_self, args, kwargs

class InnocentClass(object):
    magic_method = MagicMethod()

और अब: InnocentClass().magic_method()उम्मीद की तरह काम करेंगे। विधि innocent_selfपैरामीटर के InnocentClassसाथ और magic_selfMagicMethod उदाहरण के लिए बाध्य होगी । अजीब हुह? यह 2 खोजशब्दों this1और this2जावा और C # जैसी भाषाओं में है। इस तरह से जादू फ्रेमवर्क को सामान करने की अनुमति देता है जो अन्यथा बहुत अधिक क्रिया होगी।

फिर, मैं इस सामग्री की नैतिकता पर टिप्पणी नहीं करना चाहता। मैं सिर्फ उन चीजों को दिखाना चाहता था जो एक स्पष्ट आत्म संदर्भ के बिना करना मुश्किल होगा।


4
जब मैं आपके पहले उदाहरण पर विचार करता हूं, तो मैं जावा में भी ऐसा कर सकता हूं: आंतरिक वर्ग OuterClass.thisको बाहरी वर्ग से 'स्वयं' प्राप्त करने के लिए कॉल करने की आवश्यकता होती है , लेकिन आप अभी भी thisखुद के संदर्भ के रूप में उपयोग कर सकते हैं ; आप पायथन में यहाँ क्या करते हैं, इसके समान है। मेरे लिए यह कल्पना करना कठिन नहीं था। शायद यह सवाल में भाषा में किसी की प्रवीणता पर निर्भर करता है?
कलार

लेकिन क्या आप अभी भी किसी भी स्कोप का उल्लेख कर सकते हैं, जब आप किसी अनाम वर्ग की एक विधि के अंदर हों, जिसे एक अनाम वर्ग के अंदर परिभाषित किया गया हो Something, जिसे इंटरफ़ेस के एक अनाम कार्यान्वयन के अंदर परिभाषित किया गया हो , जो कि अभी तक किसी अन्य अनाम कार्यान्वयन के अंदर परिभाषित है Something? अजगर में आप किसी भी स्कोप का उल्लेख कर सकते हैं।
vlad-ardelean

आप सही हैं, जावा में आप केवल बाहरी वर्ग को उसके स्पष्ट वर्गनाम को कॉल करके और उपसर्ग का उपयोग करके संदर्भित कर सकते हैं this। जावा में निहित संदर्भ असंभव हैं।
कलार

मुझे आश्चर्य है कि अगर यह काम करेगा: प्रत्येक दायरे में (प्रत्येक विधि) एक स्थानीय चर है, जो thisपरिणाम का संदर्भ देता है । उदाहरण के लिए Object self1 = this;(या तो ऑब्जेक्ट का उपयोग करें, या कुछ कम सामान्य)। फिर, यदि आपके पास उच्च स्कोप में चर तक पहुंच है, तो आप , ... self1, तक पहुंच प्राप्त कर सकते हैं । मुझे लगता है कि इन्हें अंतिम या कुछ घोषित किया जाना चाहिए, लेकिन यह काम कर सकता है। self2selfn
vlad-ardelean

3

मुझे लगता है कि "द ज़ेन ऑफ पाइथन" के अलावा असली कारण यह है कि फंक्शन पायथन में प्रथम श्रेणी के नागरिक हैं।

जो अनिवार्य रूप से उन्हें एक वस्तु बनाता है। अब मूल मुद्दा यह है कि यदि आपके कार्य ऑब्जेक्ट के साथ-साथ ऑब्जेक्ट ओरिएंटेड हैं, तो आप ऑब्जेक्ट्स को संदेश कैसे भेजेंगे जब संदेश स्वयं ऑब्जेक्ट हैं?

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

इसका मतलब एकमात्र संभव समाधान स्पष्ट रूप से 'स्वयं' (निष्पादन का संदर्भ) है।

इसलिए मेरा मानना ​​है कि यह एक कार्यान्वयन समस्या है कि ज़ेन बहुत बाद में आया।


नमस्ते, मैं अजगर (जावा बैकग्राउंड से) के लिए नया हूं और आपने जो कहा था, वह बिल्कुल प्रवाह नहीं था "आप कैसे वस्तुओं को संदेश भेजेंगे जब संदेश स्वयं वस्तु हैं"। वह समस्या क्यों है, क्या आप विस्तृत कर सकते हैं?
किउलंग

1
@Qiulang आह, ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग कॉलिंग ऑब्जेक्ट्स में ऑब्जेक्ट्स पर पेलोड या आपके फ़ंक्शन के पैरामीटर के बिना ऑब्जेक्ट को संदेश भेजने के बराबर है। आंतरिक रूप से एक वर्ग / वस्तु के साथ जुड़े कोड के एक ब्लॉक के रूप में प्रतिनिधित्व किया जाएगा और इसके द्वारा प्राप्त वस्तु के माध्यम से इसके लिए उपलब्ध निहित वातावरण का उपयोग करता है। लेकिन अगर आपके तरीके ऑब्जेक्ट हैं तो वे एक वर्ग / वस्तु से जुड़े होने से स्वतंत्र हो सकते हैं जो इस सवाल का जवाब देता है कि क्या आप इस पद्धति को लागू करते हैं तो यह किस पर्यावरण के खिलाफ चलेगा?
पंकजदोहरे

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

2

मुझे लगता है कि इसे पीईपी 227 के साथ करना होगा:

वर्ग दायरे में नाम सुलभ नहीं हैं। फ़ंक्शन के दायरे को घेरने वाले अंतरतम में नामों को हल किया जाता है। यदि नेस्टेड स्कोप की एक श्रृंखला में एक वर्ग परिभाषा होती है, तो रिज़ॉल्यूशन प्रक्रिया कक्षा की परिभाषा को छोड़ देती है। यह नियम वर्ग विशेषताओं और स्थानीय चर पहुंच के बीच विषम बातचीत को रोकता है। यदि किसी वर्ग परिभाषा में नाम बाइंडिंग ऑपरेशन होता है, तो यह परिणामी वर्ग ऑब्जेक्ट पर एक विशेषता बनाता है। इस चर को किसी विधि में, या किसी विधि के भीतर निहित फ़ंक्शन में प्रवेश करने के लिए, एक विशेषता संदर्भ का उपयोग किया जाना चाहिए, या तो स्वयं के माध्यम से या वर्ग नाम के माध्यम से।


1

जैसा कि पायथन में स्वयं में समझाया गया है , डीमिस्टीफाइड

obj.meth (args) की तरह कुछ भी Class.meth (obj, args) बन जाता है। कॉलिंग प्रक्रिया स्वचालित है जबकि प्राप्त करने की प्रक्रिया (इसकी स्पष्ट) नहीं है। यही कारण है कि कक्षा में किसी फ़ंक्शन का पहला पैरामीटर ऑब्जेक्ट ही होना चाहिए।

class Point(object):
    def __init__(self,x = 0,y = 0):
        self.x = x
        self.y = y

    def distance(self):
        """Find distance from origin"""
        return (self.x**2 + self.y**2) ** 0.5

अनुरोध:

>>> p1 = Point(6,8)
>>> p1.distance()
10.0

init () तीन मापदंडों को परिभाषित करता है लेकिन हमने सिर्फ दो (6 और 8) पास किए हैं। इसी तरह दूरी () के लिए एक की आवश्यकता होती है लेकिन शून्य तर्क पारित किए गए।

पायथन इस तर्क संख्या बेमेल के बारे में शिकायत क्यों नहीं कर रहा है ?

आमतौर पर, जब हम कुछ तर्कों के साथ एक विधि कहते हैं, तो पहले तर्क के पहले विधि के ऑब्जेक्ट को रखकर संबंधित वर्ग फ़ंक्शन को कहा जाता है। तो, obj.meth (args) की तरह कुछ भी Class.meth (obj, args) बन जाता है। कॉलिंग प्रक्रिया स्वचालित है जबकि प्राप्त करने की प्रक्रिया (इसकी स्पष्ट) नहीं है।

यही कारण है कि कक्षा में किसी फ़ंक्शन का पहला पैरामीटर ऑब्जेक्ट ही होना चाहिए। इस पैरामीटर को स्वयं के रूप में लिखना केवल एक सम्मेलन है । यह एक कीवर्ड नहीं है और इसका पायथन में कोई विशेष अर्थ नहीं है। हम अन्य नामों (जैसे) का उपयोग कर सकते हैं, लेकिन मैं दृढ़ता से आपको सुझाव देता हूं कि आप ऐसा न करें। अधिकांश डेवलपर्स द्वारा स्वयं के अलावा अन्य नामों का उपयोग करना कोड की पठनीयता ("पठनीयता मायने रखता है") को कम करता है।
...
में, पहला उदाहरण self.x एक उदाहरण विशेषता है जबकि x एक स्थानीय चर है। वे समान नहीं हैं और विभिन्न नामस्थानों में स्थित हैं।

स्व यहाँ रहने के लिए है

कई लोगों ने स्वयं को पायथन में एक कीवर्ड बनाने का प्रस्ताव दिया है , जैसे C ++ और जावा में। यह विधियों में औपचारिक पैरामीटर सूची से स्पष्ट स्व के अनावश्यक उपयोग को समाप्त करेगा। जबकि यह विचार आशाजनक है, ऐसा होने वाला नहीं है। कम से कम निकट भविष्य में तो नहीं। मुख्य कारण पिछड़ी अनुकूलता है । यहां पाइथन के निर्माता का एक ब्लॉग है जिसमें स्पष्ट किया गया है कि स्पष्ट स्व को क्यों रहना है।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.