2013-12-13 11 views
11

क्या अजगर में साइड इफेक्ट्स को रोकने के लिए कोई तरीका है? उदाहरण के लिए, निम्न फ़ंक्शन का दुष्प्रभाव होता है, क्या कोई कीवर्ड या कोई अन्य तरीका है जिसके बारे में पाइथन शिकायत करते हैं?पाइथन में दुष्प्रभावों को रोकने के लिए कोई रास्ता है?

def func_with_side_affect(a): 
    a.append('foo') 
+1

मुझे नहीं लगता कि आप यह कर सकते हैं। कुछ हद तक संबंधित पोस्ट: http://stackoverflow.com/a/17292194/1967396 – Floris

+0

आप संभवतः साइड-इफेक्ट का पता कैसे लगाएंगे? साइड इफेक्ट और सिर्फ एक प्रभाव के बीच का अंतर काफी शुद्ध रूप से प्रासंगिक है। आप एक ऐसी प्रणाली तैयार करने के लिए भी शुरू कैसे करेंगे जो स्वचालित रूप से ऐसी चीज़ निर्धारित करेगी? –

+2

@ सिलास: सीएस में साइड इफेक्ट का एक बहुत सटीक अर्थ है: वास्तव में वापसी मूल्य के अलावा कुछ भी, http://en.wikipedia.org/wiki/Side_effect_%28computer_science%29 – Junuxx

उत्तर

10

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

पायथन में एक कार्यात्मक शैली का उपयोग करना आम तौर पर प्रोग्रामर को अपने कार्यों को कार्यात्मक बनाने के लिए डिजाइन करता है। दूसरे शब्दों में, जब भी आप एक फ़ंक्शन लिखें, आप इसे इस तरह लिखते हैं कि यह तर्कों को म्यूट नहीं करता है।

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

+1

धन्यवाद, अब मुझे पता है कि यह असंभव है, मैं इसे काम करने की कोशिश करना बंद कर सकता हूं और बस इसके साथ रह सकता हूं। – yigal

+0

@yigalirani पायथन आपको सभी कोड, बंदर-पैच अपमानजनक फ़ंक्शन तक पहुंच प्रदान करता है और आप सब तैयार हैं! –

2

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

यूपीडी: लेकिन फिर भी, आपका कार्य उन वस्तुओं को बदल सकता है जो आपके अपरिवर्तनीय वस्तु (जैसा कि टिप्पणियों में बताया गया था) द्वारा संदर्भित किया गया है, फाइलों को लिखें और कुछ अन्य आईओ करें।

+3

हालांकि ट्यूबल में किसी भी म्यूटेबल ऑब्जेक्ट्स को म्यूट करने में सक्षम नहीं है ... –

+0

@ जोनक्लेमेंट्स हां, यह निर्दिष्ट करना बेहतर है कि ट्यूपल में अपरिवर्तनीय प्रकार की वस्तुएं होनी चाहिए। – Bunyk

1

लागू करने का एकमात्र तरीका यह है कि फ़ंक्शन विनिर्देश को deepcopy पर मूल फ़ंक्शन पर जाने से पहले किसी भी तर्क को ओवरराइट करना होगा। आप function decorator के साथ ऐसा कर सकते हैं।

इस तरह, फ़ंक्शन का मूल रूप से मूल रूप से उत्तीर्ण तर्कों को बदलने का कोई तरीका नहीं है। हालांकि इसमें काफी मंदी का "साइडफैक्ट" है क्योंकि गहरी कॉपी ऑपरेशन मेमोरी (और कचरा-संग्रह) उपयोग के साथ-साथ सीपीयू खपत के मामले में महंगा है।

मैं आपको यह सुनिश्चित करने के लिए अपने कोड का सही परीक्षण करने की सलाह दूंगा कि कोई आकस्मिक परिवर्तन न हो या पूर्ण भाषा-दर-मूल्य अर्थशास्त्र (या केवल अपरिवर्तनीय चर) का उपयोग करने वाली भाषा का उपयोग करें।

एक और समाधान के रूप में आप अपनी कक्षाओं को यह जोड़कर अपने पारित कर दिया वस्तुओं मूल रूप से अपरिवर्तनीय बना सकता है:

"""An immutable class with a single attribute 'value'.""" 
def __setattr__(self, *args): 
    raise TypeError("can't modify immutable instance") 
__delattr__ = __setattr__ 
def __init__(self, value): 
    # we can no longer use self.value = value to store the instance data 
    # so we must explicitly call the superclass 
    super(Immutable, self).__setattr__('value', value) 

(कोड Wikipedia article about Immutable object से नकल)

1

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

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

+0

वें .. whh .... क्या? यदि यह आईसीबीएम लॉन्च कर सकता है तो यह स्काईनेट मानव दुश्मन से छुटकारा पाने की कोशिश कर रहा है ... * पाइथन कोड बेस के साथ * टर्मिनेटर * कुछ हद तक कम डरावना प्रतीत होता है - तो यह एक प्लस है :) –

+1

यह सबसे यथार्थवादी विस्तार है "नहीं"। 'आयात antigravity'। – Floris

1

आपको पहले सूची की एक प्रति बनाना होगा।कुछ इस तरह:

def func_without_side_affect(a): 
    b = a[:] 
    b.append('foo') 
    return b 

यह छोटा संस्करण आप के लिए भी काम कर सकते हैं:

def func_without_side_affect(a): 
    return a[:] + ['foo'] 

आप सूचियों या ऐसा अन्य बातों नेस्ट है, तो आप शायद copy.deepcopy को देखने के लिए सुनिश्चित करना होगा [:] स्लाइस ऑपरेटर की बजाय प्रतिलिपि बनाएँ।

0

यह सामान्य स्थिति के लिए क्या करने के लिए बहुत मुश्किल होगा, लेकिन कुछ व्यावहारिक मामलों के लिए आप कुछ इस तरह कर सकता है:

def call_function_checking_for_modification(f, *args, **kwargs): 
    myargs = [deepcopy(x) for x in args] 
    mykwargs = dict((x, deepcopy(kwargs[x])) for x in kwargs) 

    retval = f(*args, **kwargs) 

    for arg, myarg in izip(args, myargs): 
     if arg != myarg: 
      raise ValueError, 'Argument was modified during function call!' 
    for kwkey in kwargs: 
     if kwargs[kwkey] != mykwargs[kwkey]: 
      raise ValueError, 'Argument was modified during function call!' 

    return retval 

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

जटिल प्रकारों के लिए, deepcopy महंगा होगा, और कोई गारंटी नहीं है कि == ऑपरेटर वास्तव में सही तरीके से काम करेगा। (और सरल प्रति पर्याप्त नहीं है ... एक सूची की कल्पना करें, जहां एक तत्व मूल्य बदलता है ... एक साधारण प्रति केवल एक संदर्भ संग्रहीत करेगी, और इसलिए मूल मूल्य भी बदल जाएगा)।

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

उपरोक्त की तरह कुछ सजावट में लपेटा जा सकता है; एक वैश्विक परिवर्तनीय (if _debug == True:, कुछ ऐसा) द्वारा गठित महंगे हिस्सों के साथ, यह शायद उन परियोजनाओं में उपयोगी हो सकता है जहां बहुत से लोग एक ही कोड को संपादित कर रहे हैं, हालांकि, मुझे लगता है ...

संपादित करें: यह केवल काम करता है उन वातावरणों के लिए जहां 'साइड इफेक्ट्स' का एक और 'सख्त' रूप अपेक्षित है। कई प्रोग्रामिंग भाषाओं में, आप साइड इफेक्ट्स को और अधिक स्पष्ट कर सकते हैं - उदाहरण के लिए सी ++ में, सबकुछ स्पष्ट रूप से एक सूचक या संदर्भ तक मूल्य से होता है, और फिर भी आप इनकमिंग संदर्भों को const के रूप में घोषित कर सकते हैं ताकि यह नहीं हो सके संशोधित। वहां, 'दुष्प्रभाव' संकलन समय पर त्रुटियों को फेंक सकते हैं। (बेशक कुछ वैसे भी पाने का तरीका है)।

उपरोक्त लागू करता है कि किसी भी संशोधित मान रिटर्न मूल्य/ट्यूपल में हैं। यदि आप अजगर 3 में हैं (मैं अभी तक नहीं हूं) मुझे लगता है कि आप फंक्शन घोषणाओं में विशेषताओं को निर्दिष्ट करने के लिए फ़ंक्शन घोषणाओं में सजावट निर्दिष्ट कर सकते हैं, भले ही उन्हें संशोधित करने की अनुमति दी जाए, और उपरोक्त फ़ंक्शन में अनुमति दें कुछ तर्क स्पष्ट रूप से उत्परिवर्तनीय होने के लिए।

नोट मुझे लगता है कि आप शायद भी कुछ इस तरह कर सकता है:

class ImmutableObject(object): 
    def __init__(self, inobj): 
     self._inited = False 
     self._inobj = inobj 
     self._inited = True 

    def __repr__(self): 
     return self._inobj.__repr__() 

    def __str__(self): 
     return self._inobj.__str__() 

    def __getitem__(self, key): 
     return ImmutableObject(self._inobj.__getitem__(key)) 

    def __iter__(self): 
     return self.__iter__() 

    def __setitem__(self, key, value): 
     raise AttributeError, 'Object is read-only' 

    def __getattr__(self, key): 
     x = getattr(self._inobj, key) 
     if callable(x): 
       return x 
     else: 
       return ImmutableObject(x) 

    def __setattr__(self, attr, value): 
     if attr not in ['_inobj', '_inited'] and self._inited == True: 
      raise AttributeError, 'Object is read-only' 
     object.__setattr__(self, attr, value) 

(शायद नहीं एक पूर्ण कार्यान्वयन, बहुत परीक्षण नहीं किया है, लेकिन एक शुरुआत)। इस तरह काम करता है:

a = [1,2,3] 
b = [a,3,4,5] 
print c 
[[1, 2, 3], 3, 4, 5] 
c[0][1:] = [7,8] 
AttributeError: Object is read-only 

यह आप संशोधन से एक विशिष्ट वस्तु की रक्षा करता है, तो आप, नीचे की ओर समारोह पर भरोसा नहीं था, जबकि अभी भी अपेक्षाकृत हल्के जा रहा है दिया जाएगा। हालांकि वस्तु के स्पष्ट लपेटने की आवश्यकता है। सभी तर्कों के लिए आप संभवत: अर्द्ध स्वचालित रूप से ऐसा करने के लिए एक सजावटी बना सकते हैं। कॉल करने योग्य लोगों को छोड़ना सुनिश्चित करें।

3

पार्टी के लिए वास्तव में देर से खेद है। आप अपने पायथन कोड में साइड इफेक्ट्स को अलग करने के लिए effect लाइब्रेरी का उपयोग कर सकते हैं। जैसा कि अन्य ने पाइथन में कहा है, आपको स्पष्ट रूप से कार्यात्मक शैली कोड लिखना होगा, लेकिन यह लाइब्रेरी वास्तव में इसके प्रति प्रोत्साहित करती है।

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