2012-03-01 3 views
8

में उदाहरण विधियों में विशेषताओं को जोड़ना मैं अपनी कक्षाओं में से किसी एक में एक विधि विधि में एक विशेषता जोड़ना चाहता हूं। मैंने this question में दिए गए उत्तर की कोशिश की, लेकिन यह उत्तर केवल कार्यों के लिए काम करता है - जहां तक ​​मैं कह सकता हूं।)पायथन

class foo(object): 
    ... 
    def bar(self): 
     self.bar.counter += 1 
     return self.bar.counter 
    bar.counter = 1 
    ... 

लेकिन, जब मैं foo फोन() बार (मैं:

AttributeError: 'instancemethod' object has no attribute 'counter' 

मेरा लक्ष्य।

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

class foo(object): 
    def __init__(self): 
     self.counter = 0 
    def bar(self): 
     self.counter += 1 
     return self.counter 

डेटा मान अटैच किया जा रहा कार्यों के लिए सीधे निश्चित तौर पर गैर-pythonic है:

+0

'counter' श्रेणी स्तर (सभी उदाहरणों वर्तमान गिनती का हिस्सा), या उदाहरण के स्तर (प्रत्येक उदाहरण 1 से शुरू होता है) हो सकता है? –

+0

'counter' उदाहरण स्तर – sbell

+0

होना चाहिए यह संबंधित प्रश्न सहायक हो सकता है (या नहीं) सहायक हो सकता है: http://stackoverflow.com/questions/7034063/adding-attributes-the-instancemethods-in-python –

उत्तर

8

अजगर 3 में अपने कोड काम करेगा, लेकिन अजगर 2 में कुछ रैपिंग कि तब होता है जब तरीकों को देखा जाता है नहीं है।

कक्षा बनाम उदाहरण

  • वर्ग का स्तर: समारोह के साथ counter भंडारण (या तो सीधे, या एक परिवर्तनशील डिफ़ॉल्ट का उपयोग करके) प्रभावी रूप से यह एक वर्ग के स्तर विशेषता बनाता है के रूप में वहाँ केवल कभी है समारोह में से एक, कोई फर्क नहीं पड़ता कि आपके पास कितने उदाहरण हैं (वे सभी एक ही कार्य वस्तु साझा करते हैं)।

  • उदाहरण का स्तर: counter एक उदाहरण के स्तर का बनाने के लिए विशेषता __init__ में समारोह बनाने के लिए है, तो functools.partial साथ लपेट (इसलिए यह एक सामान्य विधि की तरह बर्ताव करता है) और फिर उदाहरण पर संग्रहीत है - अब आप प्रत्येक उदाहरण के लिए एक समारोह वस्तु है।

कक्षा स्तर

एक स्थिर की तरह चर के लिए स्वीकार किए जाते हैं अभ्यास एक परिवर्तनशील डिफ़ॉल्ट तर्क का उपयोग करने के लिए है:

class foo(object): 
    ... 
    def bar(self, _counter=[0]): 
     _counter[0] += 1 
     return _counter[0] 

आप इसे खूबसूरत आप अपने खुद के परिवर्तनशील परिभाषित कर सकते हैं होना चाहते हैं कंटेनर:

class MutableDefault(object): 
    def __init__(self, start=0): 
     self.value = start 
    def __iadd__(self, other): 
     self.value += other 
     return self 
    def value(self): 
     return self.value 

और इतने की तरह अपने कोड बदलने के लिए:

class foo(object): 
    def bar(self, _counter=MutableDefault()): 
     _counter += 1 
     return _counter.value 

उदाहरण स्तर

from functools import partial 

class foo(object): 
    def __init__(self): 
     def bar(self, _counter=MutableDefault(1)): # create new 'bar' each time 
      value = _counter.value 
      _counter += 1 
      return value 
     self.bar = partial(bar, self) 

सारांश

आप देख सकते हैं, पठनीयता जब counter के लिए उदाहरण के स्तर पर स्थानांतरित हो एक गंभीर हिट ले लिया। मैं दृढ़ता से सुझाव देता हूं कि counter पर जोर देने के महत्व का पुनर्मूल्यांकन करें bar का हिस्सा है, और यदि यह वास्तव में महत्वपूर्ण है तो bar अपनी कक्षा बना सकता है जिसका उदाहरण foo के उदाहरणों का हिस्सा बन गया है।

एक पुराने पोस्ट को खुदाई करने के लिए
class foo(object): 
    def __init__(self): 
     self.bar_counter = 0 
    def bar(self): 
     self.bar_counter += 1 
     return self.bar_counter 
+0

ध्यान दें कि 'MutableDefault' कोई पूर्ण कार्यान्वयन होने के नजदीक नहीं है - यह पाठक के लिए एक अभ्यास के रूप में छोड़ा गया है। :) –

+0

डिफ़ॉल्ट तर्क केवल एक बार मूल्यांकन किया जाता है, इसलिए यह कक्षा-स्तर है। ओपी ने इस सवाल पर एक टिप्पणी में स्पष्ट किया कि यह उदाहरण-स्तर होना चाहिए। –

+0

@ सीरीज़ 8217: हाँ, यही कारण है कि मैंने सवाल पूछा - जवाब यह बताता है कि उदाहरण स्तर पर इसे कैसे किया जाए। –

0

आप डेटा सदस्य आरंभ करने के लिए एक __init__ विधि की जरूरत है।

+0

मैं इसकी सराहना करता हूं, लेकिन मेरा लक्ष्य काउंटर वैरिएबल को बार विधि से जोड़ना है (कारणों से मैंने अपने प्रश्न में कहा है)। वर्ग foo (वस्तु): डीईएफ़ __init __ (स्वयं): self.bar.counter = 0 डीईएफ़ बार (स्वयं): self.bar.counter + = 1 वापसी self.bar मैं करने के लिए अपने जवाब संशोधित । काउंटर लेकिन अब मुझे __init__ कॉल – sbell

+0

में वही विशेषताएँ मिलती है, ओपी अनुरोध की तरह 'बार' को 'काउंटर' नहीं जोड़ती है। –

+0

@EthanFurman: ओपी ने ऐसा करने के लिए "अधिक पाइथोनिक" तरीका मांगा। सीधे कार्यों को डेटा संलग्न करना पायथनिक के विपरीत है। –

0

यदि आप चाहते हैं कि काउंटर सभी मामलों में लगातार बने रहें तो आप निम्न कार्य कर सकते हैं, यह अभी भी पाइथोनिक नहीं है।

class foo(object): 
    def bar(self): 
     self.bar.im_func.counter += 1 
     return self.bar.im_func.counter 
    bar.counter = 0 
2

क्षमा करें, लेकिन मुझे अपनी खोजों में यह भर में आया था और वास्तव में एक समाधान के साथ किसी पाया: यदि यह वास्तव में महत्वपूर्ण नहीं है, यह सामान्य तरीके से करते हैं।

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

http://metapython.blogspot.com/2010/11/python-instance-methods-how-are-they.html