2011-07-18 14 views
29

क्या पाइथन निर्मित प्रकारों में एक्सटेंशन विधि जोड़ना संभव है? मुझे पता है कि मैं केवल नई विधि जोड़कर परिभाषित प्रकार में एक्सटेंशन विधि जोड़ सकता हूं। के रूप में निम्नलिखित:पाइथन निर्मित प्रकार के लिए एक्सटेंशन विधि!

class myClass: 
    pass 

myClass.myExtensionMethod = lambda self,x:x * 2 
z = myClass() 
print z.myExtensionMethod(10) 

लेकिन सूची, dict, जैसे प्रकार built'in अजगर को विस्तार विधि जोड़ने के लिए किसी भी तरह से ...

list.myExtension = lambda self,x:x * 2 
list.myExtension(10) 
+1

sidenote: रूबी इसे अनुमति देता है। वहां कोई अन्य भाषाएं जो इसका समर्थन करती हैं? –

+0

करॉली: स्पष्ट रूप से स्मॉलटाक :) – Wrameerez

+1

संभावित डुप्लिकेट [क्या आप पाइथन में कोर प्रकारों पर पैच विधियों को बंद कर सकते हैं?] (Http://stackoverflow.com/questions/192649/can-you-monkey-patch-methods-on-core -types-in-python) – jfs

उत्तर

54

यह इस अविश्वसनीय रूप से चतुर मॉड्यूल के साथ शुद्ध पायथन में किया जा सकता:

https://pypi.python.org/pypi/forbiddenfruit

उदाहरण के लिए:

import functools 
import ctypes 
import __builtin__ 
import operator 

class PyObject(ctypes.Structure): 
    pass 

Py_ssize_t = hasattr(ctypes.pythonapi, 'Py_InitModule4_64') and ctypes.c_int64 or ctypes.c_int 

PyObject._fields_ = [ 
    ('ob_refcnt', Py_ssize_t), 
    ('ob_type', ctypes.POINTER(PyObject)), 
] 

class SlotsPointer(PyObject): 
    _fields_ = [('dict', ctypes.POINTER(PyObject))] 

def proxy_builtin(klass): 
    name = klass.__name__ 
    slots = getattr(klass, '__dict__', name) 

    pointer = SlotsPointer.from_address(id(slots)) 
    namespace = {} 

    ctypes.pythonapi.PyDict_SetItem(
     ctypes.py_object(namespace), 
     ctypes.py_object(name), 
     pointer.dict, 
    ) 

    return namespace[name] 

def die(message, cls=Exception): 
    """ 
     Raise an exception, allows you to use logical shortcut operators to test for object existence succinctly. 

     User.by_name('username') or die('Failed to find user') 
    """ 
    raise cls(message) 

def unguido(self, key): 
    """ 
     Attempt to find methods which should really exist on the object instance. 
    """ 
    return functools.partial((getattr(__builtin__, key, None) if hasattr(__builtin__, key) else getattr(operator, key, None)) or die(key, KeyError), self) 

class mapper(object): 
    def __init__(self, iterator, key): 
     self.iterator = iterator 
     self.key = key 
     self.fn = lambda o: getattr(o, key) 

    def __getattribute__(self, key): 
     if key in ('iterator', 'fn', 'key'): return object.__getattribute__(self, key) 
     return mapper(self, key) 

    def __call__(self, *args, **kwargs): 
     self.fn = lambda o: (getattr(o, self.key, None) or unguido(o, self.key))(*args, **kwargs) 
     return self 

    def __iter__(self): 
     for value in self.iterator: 
      yield self.fn(value) 

class foreach(object): 
    """ 
     Creates an output iterator which will apply any functions called on it to every element 
     in the input iterator. A kind of chainable version of filter(). 

     E.g: 

     foreach([1, 2, 3]).__add__(2).__str__().replace('3', 'a').upper() 

     is equivalent to: 

     (str(o + 2).replace('3', 'a').upper() for o in iterator) 

     Obviously this is not 'Pythonic'. 
    """ 
    def __init__(self, iterator): 
     self.iterator = iterator 

    def __getattribute__(self, key): 
     if key in ('iterator',): return object.__getattribute__(self, key) 
     return mapper(self.iterator, key) 

    def __iter__(self): 
     for value in self.iterator: 
      yield value 

proxy_builtin(list)['foreach'] = property(foreach) 

import string 

print string.join([1, 2, 3].foreach.add(2).str().add(' cookies').upper(), ', ') 

>>> 3 COOKIES, 4 COOKIES, 5 COOKIES 

वहां, क्या यह अच्छा नहीं लगता?

+3

यह साम्राज्य स्ट्राइक्स बैक में [उस दृश्य] (http://imgur.com/lVEdIXO) में से एक को याद दिलाता है .... – n611x007

+15

इस उत्तर में धरती पर क्या कोड है? बस 'पाइप इंस्टॉल वर्जितफ्रूट' करें, फिर 'वर्जित फूट इंस्टॉल शाप' से और ब्रह्मांड को नष्ट करने के बारे में सेट करें। – ArtOfWarfare

+0

@ArtOfWarfare उन्होंने कुकीज़ को जोड़ा ताकि मुझे लगता है कि यह इसके लायक था – MaLiN2223

3

नहीं है, क्योंकि मैं बहुत यकीन है कि सभी का निर्माण किया -इन प्रकार अनुकूलित सी में लिखे गए हैं और इस प्रकार पायथन के साथ संशोधित नहीं किया जा सकता है। जब मैंने इसे कोशिश, मैं सिर्फ मिलती है:

TypeError: can't set attributes of built-in/extension type 'list' 
16

सं प्रकार सी में परिभाषित monkeypatched नहीं किया जा सकता।

+1

यह दुखद लेकिन सच है। मैं आमतौर पर बिल्टिन और बंदर से विरासत को समाप्त करता हूं, यदि आवश्यक हो तो बच्चे वर्ग को पकड़ें। – Ishpeck

+4

@Ishpeck: यह सामान्य subclassing की तरह लगता है, बंदर पैचिंग बिल्कुल नहीं। –

+2

यह आमतौर पर बंदरगाह की बात है, बस उपclass के उदाहरण के लिए किया जाता है। और यह क्रूर और बुरा है। इसे कभी मत करो, बच्चे। – Ishpeck

2

सबसे अच्छा आप ऐसा कर सकते हैं अंतर्निहित प्रकार से कक्षा प्राप्त करना प्रतीत होता है। उदाहरण के लिए:

class mylist(list): 
    def myfunc(self, x): 
     self.append(x) 

test = mylist([1,2,3,4]) 
test.myfunc(99) 

(। तुम भी यह "सूची" का नाम इतनी के रूप में एक ही निर्माता प्राप्त करने के लिए, यदि आप चाहते थे सकता है) लेकिन, आप सीधे संशोधित नहीं कर सकते एक अंतर्निहित अपने प्रश्न में उदाहरण की तरह टाइप।

12

नहीं, आपको उप-वर्ग होना चाहिए!

>>> import string 
>>> class MyString(str): 
...  def disemvowel(self): 
...   return MyString(string.translate(self, None, "aeiou")) 
... 
>>> s = MyString("this is only a test") 
>>> s.disemvowel() 
'ths s nly tst' 

या अपने उदाहरण से अधिक संबंधित

>>> class MyList(list): 
...  pass 
... 
>>> MyList.myExtension = lambda self,x:x * 2 
>>> l = MyList() 
>>> l.myExtension(10) 
20 
संबंधित मुद्दे