2009-11-05 11 views
5

मेरे पास कुछ विधियों के साथ एक कक्षा है, जिनमें से कुछ केवल तभी वैध हैं जब वस्तु किसी विशेष स्थिति में होती है। मैं, विधियों, जब वे एक उपयुक्त राज्य में नहीं कर रहे हैं बस वस्तुओं के लिए बाध्य नहीं किया जा करना चाहते हैं ताकि मैं की तरह कुछ मिलता है:क्या पाइथन में ऑब्जेक्ट (कक्षा नहीं) से कोई विधि हटाना संभव है?

>>> wiz=Wizard() 
>>> dir(wiz) 
['__doc__', '__module__', 'addmana'] 
>>> wiz.addmana() 
>>> dir(wiz) 
['__doc__', '__module__', 'addmana', 'domagic'] 
>>> wiz.domagic() 
>>> dir(wiz) 
['__doc__', '__module__', 'addmana'] 
>>> wiz.domagic() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: Wizard instance has no attribute 'domagic' 

मैं पद्धतियां जोड़ने का तरीका (types.MethodType (देख सकते हैं विधि, वस्तु)), लेकिन मैं सिर्फ एक वस्तु के लिए एक विधि को हटाने के लिए किसी भी तरह से नहीं देख सकते हैं:

>>> wiz.domagic 
<bound method Wizard.domagic of <__main__.Wizard instance at 0x7f0390d06950>> 
>>> del wiz.domagic 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: Wizard instance has no attribute 'domagic' 

अधिभावी __dir__ (और एक InvalidState या संदर्भ पर AttributeError के बजाय मंगलाचरण पर NotEnoughMana अपवाद हो रही) हो सकता है ठीक है, लेकिन मैं नहीं देख सकता कि डीआईआर() के अंतर्निहित व्यवहार की नकल कैसे करें। (आदर्श रूप में मैं एक तरीका पसंद करता हूं जो पाइथन 2.5 में भी काम करता है)

विचार?

उत्तर

2

रास्ता dir करने के लिए (ऐसा लगता है) डिफ़ॉल्ट रूप से काम करता है:

dir(obj) == sorted(obj.__dict__.keys() + dir(obj.__class__)) 

(अच्छी तरह से, वैसे भी डुप्लिकेट हटाने)

तो एक दृष्टिकोण होगा:

class Wizard(object): 
    def __init__(self): 
     self.mana = 0 

    def __dir__(self): 
     natdir = set(self.__dict__.keys() + dir(self.__class__)) 
     if self.mana <= 0: 
      natdir.remove("domagic") 
     return list(natdir) 

    def addmana(self): 
     self.mana += 1 

    def domagic(self): 
     if self.mana <= 0: 
      raise NotEnoughMana() 
     print "Abracadabra!" 
     self.mana -= 1 
साथ

Py2.6 में व्यवहार:

>>> wiz = Wizard() 

>>> [x for x in dir(wiz) if not x.startswith("_")] 
['addmana', 'mana'] 

>>> wiz.addmana() 

>>> [x for x in dir(wiz) if not x.startswith("_")] 
['addmana', 'domagic', 'mana'] 

>>> wiz.domagic() 
Abracadabra! 

>>> [x for x in dir(wiz) if not x.startswith("_")] 
['addmana', 'mana'] 

>>> wiz.domagic() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 13, in domagic 
__main__.NotEnoughMana 
9

यह सीधे अपने सवाल का जवाब नहीं है, लेकिन मुझे लगता है कि इस समस्या को हल करने के लिए एक बेहतर दृष्टिकोण/नहीं जोड़ने के लिए होगा अपने wiz वस्तु पर सदस्य विधि domagic निकालें:

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

def domagic(): 
    if (state != desired_state): 
     print "You cannot do any magic now!" 
     return 
    print "Doing some magic" 
    [some more commands] 
+3

वैकल्पिक रूप से, विधि को हटाने का प्रयास करने के बजाय, एक विधि जोड़ें जो केवल 'पास' है। जब आप जादू चाहते हैं तो नोप विधि हटाएं। – outis

6

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

आप समारोह उपसर्गों कि इस तरह दिखेगा के एक समूह के होने के बारे में चिंतित हैं:

if self.StateNotValid(): 
    raise NotEnoughMana() 

... तो आप एक डेकोरेटर प्रत्येक कार्य पर इस्तेमाल कर सकते हैं। यह छोटा है, और आपको सभी विशेष-राज्य-आवश्यक कार्यों के लिए grep का आसान तरीका देता है।

+5

पूरी तरह से 'आवश्यकताMoreVespeneGas() 'उठाया जाना चाहिए। किसी को? किसी को? –

+0

@ क्रिस मैं इसे भुगतान करूंगा – harto

2

आपको लगता है कि जैसे एक हैक का उपयोग कर सकते हैं:

>>> class A(object): 
...  def test(self): 
...   print 'test' 
... 
>>> a = A() 
>>> def noattr(name): 
...  raise AttributeError('no attribute %s' % name) 
... 
>>> a.test = lambda *a, **k: noattr('test') 
>>> a.test() 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 

/Users/piranha/<ipython console> in <module>() 

/Users/piranha/<ipython console> in <lambda>(*a, **k) 

/Users/piranha/<ipython console> in noattr(name) 

AttributeError: no attribute test 
बेशक

, इस तुम गलत ट्रैस बैक देता है, लेकिन अपवाद ही है। ;-)

एक और (IMHO - बेहतर) तरीका __getattr__ ओवरराइड और फिर डाल प्रेषण तर्क है, तो आप ऐसा कर सकते हैं:

>>> class A(object): 
...  def __getattr__(self, name): 
...   def inner(*args, **kwargs): 
...    print args, kwargs 
...   return inner 
... 
>>> a = A() 
>>> a.test 
    <function inner at 0x1006c36e0> 
>>> a.test('q') 
('q',) {} 
10

आप एक से एक वर्ग विधि को नहीं हटा सकते उस वर्ग का उदाहरण क्योंकि उदाहरण में विधि है। प्रोटोकॉल है: यदि o कक्षा Foo का एक उदाहरण है, और मैं o.bar() पर कॉल करता हूं, तो पहले o को यह देखने के लिए जांच की जाती है कि क्या इसका नाम bar है। यदि ऐसा नहीं होता है, तो Foo की जांच की जाती है। विधियों को उदाहरण के लिए बाध्य नहीं किया जाता है जब तक कि वे अपनी कक्षा को ओवरराइड नहीं करते हैं।

मुझे कोई भी अच्छा दिखाई नहीं देता है जो आप यहां जा रहे सड़क से आ सकते हैं।

1

एक पाइथन ऑब्जेक्ट से किसी विधि को छिपाने/निकालने के स्पष्ट प्रश्न को संबोधित करने के लिए कुछ अच्छे विचार हैं, इसलिए मैं उच्च स्तर के प्रश्न को संबोधित करना चाहता हूं।

विशेष रूप से, मूल प्रश्न से समस्या बयान:

मैं कुछ तरीकों, जिनमें से कुछ के साथ एक वर्ग है ही मान्य जब वस्तु एक विशेष स्थिति में है।

यह पैटर्न एक वस्तु का राज्य का प्रतिनिधित्व करने के लिए कंप्यूटर प्रोग्रामिंग में प्रयोग किया जाता है:

यह स्थिति State Design Pattern के माध्यम से हल समस्या का एक उत्कृष्ट उदाहरण है। यह ऑब्जेक्ट के आंशिक रूप से रनटाइम पर आंशिक रूप से बदलने के लिए एक साफ तरीका है। ।

  1. है कि एक जादूगर वस्तु में हो सकता है यह पैटर्न कर सकते हैं अच्छी तरह से परिभाषित राज्यों की एक छोटी संख्या हैं:

मैं इस पद्धति का उपयोग कर यदि आपके जादूगर निम्नलिखित गुण है पर विचार करेंगे अगर स्थिति में तेजी से बढ़ रहे/बदलते सेट हैं, तो समस्याग्रस्त हो। ऑब्जेक्ट की संख्या के मुकाबले कोई कठोर संख्या नहीं है, लेकिन मैं सुझाव दूंगा कि यदि आप इसका उपयोग करने के लिए अनिश्चित हैं पैटर्न और फिर रखरखाव बहुत अधिक हो जाता है तो एक विकल्प का पीछा करें।

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

    एक अतिरिक्त संभावना के रूप में (सवाल थोड़ा घुमा), इसे और अधिक समझ में ही कुछ मामलों पर कुछ तरीकों वाला राज्य बन गया, तो आप हमेशा ऐसे मामलों के लिए वर्ग के __init__ में उन तरीकों में जोड़ सकते हैं, तो जिसके लिए यह समझ में आता है। पूर्व: कहें कि हमारे पास आपकी Wizard कक्षा है, और केवल Wizard उदाहरण में domagic() विधि होनी चाहिए यदि magic पैरामीटर __init__()True पर पारित किया गया हो। हम तो कुछ कर सकते हैं की तरह:

    class Wizard(object): 
        def __init__(self, magic = False): 
         if magic: 
          def _domagic(): 
           print "DOING MAGIC!" 
          self.domagic = _domagic 
    
    def main(): 
        mage = Wizard(magic = True) 
        nomage = Wizard(magic = False) 
    
        mage.domagic()  # prints "DOING MAGIC!" 
        nomage.domagic() # throws an AttributeError 
    

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

    0

    जबकि मैं मानता हूं कि यह गलत समाधान है, एक विधि को "निकालने" का मेरा तरीका उस संपत्ति के साथ फ़ंक्शन को ओवरराइट करना होगा जो AttributeError उठाता है। इस तरह hasattr सही परिणाम देता है, लेकिन dir का उपयोग करने के रूप में यह उतना ही परेशानी नहीं है।

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