Sie können dies tatsächlich lösen, indem Sie für jeden Typ eine neue Klasse erstellen. Wenn Sie möchten, dass dies transparent funktioniert, ist __new__
der richtige Ort dafür.
import weakref
class BigWrap(object):
def __new__(cls, wrapped):
wrapped_type = type(wrapped)
print('Wrapping %s (%s)' % (wrapped, wrapped_type))
# creates a new class, aka a new type
wrapper_class = type( # new_class = type(class name, base classes, class dict)
'%s_%s_%d' % (cls.__name__, wrapped_type.__name__, id(wrapped)), # dynamic class name
(
cls, # inherit from wrap to have all new methods
wrapped_type, # inherit from wrap_type to have all its old methods
),
{
'__getitem__': wrapped.__getitem__, # overwrite __getitem__ based on wrapped *instance*
'__new__': wrapped_type.__new__, # need to use wrapped_type.__new__ as cls.__new__ is this function
})
cls._wrappers[wrapped_type] = wrapper_class # store wrapper for repeated use
return cls._wrappers[wrapped_type](wrapped)
# self is already an instance of wrap_<type(wrapped)>
def __init__(self, wrapped):
self.__wrapped__ = wrapped
Initiale "Lösung":
import weakref
class wrap(object):
_wrappers = weakref.WeakValueDictionary() # cache wrapper classes so we don't recreate them
def __new__(cls, wrapped):
wrapped_type = type(wrapped)
print('Wrapping %s (%s)' % (wrapped, wrapped_type))
try:
return object.__new__(cls._wrappers[wrapped_type]) # need to use object.__new__ as cls.__new__ is this function
except KeyError:
print('Creating Wrapper %s (%s)' % (wrapped, wrapped_type))
# creates a new class, aka a new type
wrapper_class = type( # class name, base classes, class dict
'%s_%s' % (cls.__name__, wrapped_type.__name__), # dynamic class name
(cls,), # inherit from wrap to have all its method
{'__getitem__': wrapped_type.__getitem__}) # overwrite __getitem__ based on wrapped class
cls._wrappers[wrapped_type] = wrapper_class # store wrapper for repeated use
return cls._wrappers[wrapped_type](wrapped)
# self is already an instance of wrap_<type(wrapped)>
def __init__(self, wrapped):
self._data = wrapped
aber Vorsicht! Dies wird tun, was Sie wollen - verwenden Sie die umschlossene Klasse '__getitem__
. Dies macht jedoch nicht immer Sinn! Zum Beispiel ist list.__getitem__
tatsächlich in CPythons CAPI integriert und nicht auf andere Typen anwendbar.
foo = wrap([1,2,3])
print(type(foo)) # __main__.wrap_list
foo[2]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-31-82791be7104b> in <module>()
----> 1 foo[2]
TypeError: descriptor '__getitem__' for 'list' objects doesn't apply to 'wrap_list' object
Pro-Tipp: Wenn Sie nicht wüssten, warum das funktioniert, sollten Sie nicht versuchen, es zu optimieren. Ihr Overhead ist wahrscheinlich nicht so signifikant, wie Sie denken. – MisterMiyagi
Aber wenn ich es nicht versucht hätte, hätte ich nicht gelernt wie es funktioniert, was mir nicht erlaubt hätte es zu tun. OTOH, wenn ich gewusst hätte, dass es kaputt ist, hätte ich es nicht ausprobiert ... Außerdem weißt du wahrscheinlich nicht, wie wichtig es für mich war. – NichtJens
Beachten Sie, dass Sie das * tatsächlich lösen können, indem Sie für jeden Typ eine neue Klasse erstellen. Grundsätzlich benötigen Sie dafür eine Factory-Funktion. Dies kann transparent über '__new__' realisiert werden. Es ist jedoch etwas schwarze Magie ... Natürlich kann ich nur spekulieren, wie wichtig du denkst, dass es so ist; Als Referenz können Sie ungefähr 0,1 usec pro Anruf sichern. – MisterMiyagi