2009-09-05 16 views
8

मैं एक पायथन कक्षा के साथ काम कर रहा हूं, और मेरे पास इसकी घोषणा के लिए लेखन पहुंच नहीं है। कक्षा घोषणा के संशोधन के बिना उस वर्ग से बनाए गए ऑब्जेक्ट्स में मैं एक कस्टम विधि (जैसे __str__) कैसे संलग्न कर सकता हूं?स्विग के साथ उत्पन्न मौजूदा पायथन ऑब्जेक्ट को गतिशील रूप से एक विधि संलग्न करना?

संपादित करें: आपके सभी उत्तरों के लिए धन्यवाद। मैंने उन सभी की कोशिश की लेकिन उन्होंने मेरी समस्या का समाधान नहीं किया है। यहां एक न्यूनतम उदाहरण दिया गया है कि मुझे आशा है कि इस मुद्दे को स्पष्ट किया जाएगा। मैं एक सी ++ वर्ग को लपेटने के लिए स्विग का उपयोग कर रहा हूं, और इसका उद्देश्य का एक ऑब्जेक्ट स्विग मॉड्यूल द्वारा लौटाया गया है। मैं cmake का उपयोग उदाहरण के निर्माण करने के लिए:

test.py

import example 

ex = example.generate_example(2) 

def prnt(self): 
    return str(self.x) 

#How can I replace the __str__ function of object ex with prnt? 
print ex 
print prnt(ex) 

example.hpp

struct example 
{ 
    int x; 
}; 

example generate_example(int x); 

example.cpp

#include "example.hpp" 
#include <iostream> 

example generate_example(int x) 
{ 
    example ex; 
    ex.x = x; 
    return ex; 
} 

int main() 
{ 
    example ex = generate_example(2); 
    std::cout << ex.x << "\n"; 
    return 1; 
} 

example.i

%module example 

%{ 
#include "example.hpp" 
%} 

%include "example.hpp" 

CMakeLists.txt

cmake_minimum_required(VERSION 2.6) 

find_package(SWIG REQUIRED) 
include(${SWIG_USE_FILE}) 

find_package(PythonLibs) 
include_directories(${PYTHON_INCLUDE_PATH}) 
include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 

set_source_files_properties(example.i PROPERTIES CPLUSPLUS ON) 
swig_add_module(example python example.i example) 
swig_link_libraries(example ${PYTHON_LIBRARIES}) 

if(APPLE) 
    set(CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS "${CMAKE_SHARED_MODULE_CREATE_CXX_FLAGS} -flat_namespace") 
endif(APPLE) 

का निर्माण और test.py चलाने के लिए, एक निर्देशिका में सभी फ़ाइलों की प्रतिलिपि, और कहा कि निर्देशिका रन

cmake . 
make 
python test.py 
में

परिणामस्वरूप निम्न आउटपुट में परिणाम:

<example.example; proxy of <Swig Object of type 'example *' at 0x10021cc40> > 
2 

जैसा कि आप देख सकते हैं कि स्विग ऑब्जेक्ट का अपना str फ़ंक्शन है, और यही वह है जिसे मैं ओवरराइड करने की कोशिश कर रहा हूं।

+0

अन्य StackOverflow सवाल: http://stackoverflow.com/questions/972/adding-a-method-to-an-existing-object –

उत्तर

20

यदि आप एक रैपर वर्ग बनाते हैं, तो यह किसी भी अन्य वर्ग के साथ काम करेगा, या तो अंतर्निहित या नहीं। यह "रोकथाम और प्रतिनिधिमंडल" कहा जाता है, और यह विरासत के एक आम विकल्प है:

class SuperDuperWrapper(object): 
    def __init__(self, origobj): 
     self.myobj = origobj 
    def __str__(self): 
     return "SUPER DUPER " + str(self.myobj) 
    def __getattr__(self,attr): 
     return getattr(self.myobj, attr) 

__getattr__ विधि निहित myobj वस्तु को अपने SuperDuperWrapper वस्तु पर सभी अपरिभाषित विशेषता अनुरोध प्रतिनिधि होगा। वास्तव में, पायथन के गतिशील टाइपिंग दिया, तो आप इस वर्ग इस्तेमाल कर सकते हैं SuperDuper'ly सिर्फ कुछ के बारे में रैप करने के लिए:

s = "hey ho!" 
sds = SuperDuperWrapper(s) 
print sds 

i = 100 
sdi = SuperDuperWrapper(i) 
print sdi 

प्रिंटों:

SUPER DUPER hey ho! 
SUPER DUPER 100 

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

print sds.split() 
['hey', 'ho!'] 
+0

मैंने अपने पाइथन कैरियर में बहुत जल्दी इस तकनीक का उपयोग रिमोट कोर्बो ऑब्जेक्ट को प्रॉक्सी के लिए एक इंटरसेप्टर लिखने के लिए किया - क्लाइंट चाहता था कि एक विशेष रिमोट विधि थोड़ा बढ़ाया जाए, लेकिन अन्यथा बाकी सब कुछ व्यवहार करना था। हाल ही में सी ++ से स्विच करने के बाद, मैं इस बात से परेशान था कि सी ++ ने मुझे क्या किया होगा, इसके विरोध में यह कितना कम कोड लिखने के लिए लिया गया था। – PaulMcG

+0

धन्यवाद पॉल! यह वहीं है जिसे मैं ढूंढ रहा था। – dzhelil

+0

इस दृष्टिकोण के साथ समस्या यह है कि परिणामस्वरूप लपेटा हुआ वस्तु पिकनीय नहीं है, जो कभी-कभी –

3
>>> class C(object): 
...  pass 
... 
>>> def spam(self): 
...  return 'spam' 
... 
>>> C.__str__ = spam 
>>> print C() 
spam 

यह __slots__ का उपयोग करने वाले वर्गों पर काम नहीं करेगा।

+0

दुर्भाग्य से यह मेरे मामले में काम नहीं कर रहा। जिस वर्ग को मैं ओवरराइड करने की कोशिश कर रहा हूं उसे सी ++ हेडर फाइलों से स्विग का उपयोग करके स्वत: उत्पन्न किया गया था। – dzhelil

3

एक उप-वर्ग बनाएँ। उदाहरण:

>>> import datetime 
>>> t = datetime.datetime.now() 
>>> datetime.datetime.__str__ = lambda self: 'spam' 
... 
TypeError: cant set attributes of built-in/extension type 'datetime.datetime' 
>>> t.__str__ = lambda self: 'spam' 
... 
AttributeError: 'datetime.datetime' object attribute '__str__' is read-only 
>>> class mydate(datetime.datetime): 
    def __str__(self): 
     return 'spam' 

>>> myt = mydate.now() 
>>> print t 
2009-09-05 13:11:34.600000 
>>> print myt 
spam 
+1

+1: यह मौलिक कारण है कि विरासत क्यों मौजूद है। –

+0

सुझाव एलेक्स के लिए धन्यवाद। यह सच है कि मैं आसानी से सबक्लास बना सकता हूं, लेकिन इससे मुझे बहुत मदद नहीं मिलेगी क्योंकि जिस ऑब्जेक्ट के साथ मैं काम कर रहा हूं उसे उस फ़ंक्शन द्वारा वापस कर दिया गया है जिसे मैं संशोधित नहीं कर सकता। आपके उदाहरण के संदर्भ में कि ऑब्जेक्ट प्रकार डेटाटाइम है। मैं अपने '__str__' फ़ंक्शन को ओवरराइड करना चाहता हूं, इसलिए इसके लिए उपयोगी होने के लिए मुझे डेटटाइम ऑब्जेक्ट को माईडेट में डालने का एक तरीका चाहिए। – dzhelil

2

यह another question से मेरा जवाब है:

import types 
class someclass(object): 
    val = "Value" 
    def some_method(self): 
     print self.val 

def some_method_upper(self): 
    print self.val.upper() 

obj = someclass() 
obj.some_method() 

obj.some_method = types.MethodType(some_method_upper, obj) 
obj.some_method() 
1

ध्यान दें कि एलेक्स के उपवर्ग विचार का उपयोग कर, आप अपने आप को मदद कर सकते हैं थोड़ा और अधिक का उपयोग करते हुए "from ... import ... as" :

from datetime import datetime as datetime_original 

class datetime(datetime_original): 
    def __str__(self): 
     return 'spam' 

इसलिए अब कक्षा का मानक नाम है, लेकिन अलग-अलग व्यवहार है।

>>> print datetime.now() 
    'spam' 

बेशक, यह खतरनाक हो सकता है ...

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