Используя это, вы можете почти скопировать все с одного объекта на другой:
import sys
_target_object = sys.stderr
_target_object_class_type = type( _target_object )
class TargetCopiedObject(_target_object_class_type):
"""
Which special methods bypasses __getattribute__ in Python?
https://stackoverflow.com/questions/12872695/which-special-methods-bypasses
"""
if hasattr( _target_object, "__abstractmethods__" ):
__abstractmethods__ = _target_object.__abstractmethods__
if hasattr( _target_object, "__base__" ):
__base__ = _target_object.__base__
if hasattr( _target_object, "__bases__" ):
__bases__ = _target_object.__bases__
if hasattr( _target_object, "__basicsize__" ):
__basicsize__ = _target_object.__basicsize__
if hasattr( _target_object, "__call__" ):
__call__ = _target_object.__call__
if hasattr( _target_object, "__class__" ):
__class__ = _target_object.__class__
if hasattr( _target_object, "__delattr__" ):
__delattr__ = _target_object.__delattr__
if hasattr( _target_object, "__dict__" ):
__dict__ = _target_object.__dict__
if hasattr( _target_object, "__dictoffset__" ):
__dictoffset__ = _target_object.__dictoffset__
if hasattr( _target_object, "__dir__" ):
__dir__ = _target_object.__dir__
if hasattr( _target_object, "__doc__" ):
__doc__ = _target_object.__doc__
if hasattr( _target_object, "__eq__" ):
__eq__ = _target_object.__eq__
if hasattr( _target_object, "__flags__" ):
__flags__ = _target_object.__flags__
if hasattr( _target_object, "__format__" ):
__format__ = _target_object.__format__
if hasattr( _target_object, "__ge__" ):
__ge__ = _target_object.__ge__
if hasattr( _target_object, "__getattribute__" ):
__getattribute__ = _target_object.__getattribute__
if hasattr( _target_object, "__gt__" ):
__gt__ = _target_object.__gt__
if hasattr( _target_object, "__hash__" ):
__hash__ = _target_object.__hash__
if hasattr( _target_object, "__init__" ):
__init__ = _target_object.__init__
if hasattr( _target_object, "__init_subclass__" ):
__init_subclass__ = _target_object.__init_subclass__
if hasattr( _target_object, "__instancecheck__" ):
__instancecheck__ = _target_object.__instancecheck__
if hasattr( _target_object, "__itemsize__" ):
__itemsize__ = _target_object.__itemsize__
if hasattr( _target_object, "__le__" ):
__le__ = _target_object.__le__
if hasattr( _target_object, "__lt__" ):
__lt__ = _target_object.__lt__
if hasattr( _target_object, "__module__" ):
__module__ = _target_object.__module__
if hasattr( _target_object, "__mro__" ):
__mro__ = _target_object.__mro__
if hasattr( _target_object, "__name__" ):
__name__ = _target_object.__name__
if hasattr( _target_object, "__ne__" ):
__ne__ = _target_object.__ne__
if hasattr( _target_object, "__new__" ):
__new__ = _target_object.__new__
if hasattr( _target_object, "__prepare__" ):
__prepare__ = _target_object.__prepare__
if hasattr( _target_object, "__qualname__" ):
__qualname__ = _target_object.__qualname__
if hasattr( _target_object, "__reduce__" ):
__reduce__ = _target_object.__reduce__
if hasattr( _target_object, "__reduce_ex__" ):
__reduce_ex__ = _target_object.__reduce_ex__
if hasattr( _target_object, "__repr__" ):
__repr__ = _target_object.__repr__
if hasattr( _target_object, "__setattr__" ):
__setattr__ = _target_object.__setattr__
if hasattr( _target_object, "__sizeof__" ):
__sizeof__ = _target_object.__sizeof__
if hasattr( _target_object, "__str__" ):
__str__ = _target_object.__str__
if hasattr( _target_object, "__subclasscheck__" ):
__subclasscheck__ = _target_object.__subclasscheck__
if hasattr( _target_object, "__subclasses__" ):
__subclasses__ = _target_object.__subclasses__
if hasattr( _target_object, "__subclasshook__" ):
__subclasshook__ = _target_object.__subclasshook__
if hasattr( _target_object, "__text_signature__" ):
__text_signature__ = _target_object.__text_signature__
if hasattr( _target_object, "__weakrefoffset__" ):
__weakrefoffset__ = _target_object.__weakrefoffset__
if hasattr( _target_object, "mro" ):
mro = _target_object.mro
def __init__(self):
"""
Override any super class `type( _target_object )` constructor,
so we can instantiate any kind of replacement object.
Assures all properties were statically replaced just above. This
should happen in case some new attribute is added to the python
language.
This also ignores the only two methods which are not equal,
`__init__()` and `__getattribute__()`.
How do you programmatically set an attribute?
https://stackoverflow.com/questions/285061/how-do-you-programmatically
"""
different_methods = set(["__init__", "__getattribute__"])
attributes_to_check = set( dir( object ) + dir( type ) )
attributes_to_copy = dir( _target_object )
# Check for missing magic built-ins methods on the class static initialization
for attribute in attributes_to_check:
if attribute not in different_methods \
and hasattr( _target_object, attribute ):
base_class_attribute = self.__getattribute__( attribute )
target_class_attribute = _target_object.__getattribute__( attribute )
if base_class_attribute != target_class_attribute:
sys.stdout.write(
" The base class attribute `%s` is different from the "
"target class:\n%s\n%s\n\n" % ( attribute,
base_class_attribute,
target_class_attribute ) )
# Finally copy everything it can
different_methods.update( attributes_to_check )
for attribute in attributes_to_copy:
if attribute not in different_methods:
print( "Setting:", attribute )
try:
target_class_attribute = _target_object.__getattribute__(attribute)
setattr( self, attribute, target_class_attribute )
except AttributeError as error:
print( "Error coping the attribute `%s`: %s" % (attribute, error) )
o = TargetCopiedObject()
print( "TargetCopiedObject:", o )
Однако, если вы запустите приведенный выше код, вы увидите следующие ошибки:
python test.py
Setting: _CHUNK_SIZE
Setting: __del__
Setting: __enter__
Setting: __exit__
Setting: __getstate__
Setting: __iter__
Setting: __next__
Setting: _checkClosed
Setting: _checkReadable
Setting: _checkSeekable
Setting: _checkWritable
Setting: _finalizing
Setting: buffer
Error coping the attribute `buffer`: readonly attribute
Setting: close
Setting: closed
Error coping the attribute `closed`: attribute 'closed' of '_io.TextIOWrapper' objects is not writable
Setting: detach
Setting: encoding
Error coping the attribute `encoding`: readonly attribute
Setting: errors
Error coping the attribute `errors`: attribute 'errors' of '_io.TextIOWrapper' objects is not writable
Setting: fileno
Setting: flush
Setting: isatty
Setting: line_buffering
Error coping the attribute `line_buffering`: readonly attribute
Setting: mode
Setting: name
Error coping the attribute `name`: attribute 'name' of '_io.TextIOWrapper' objects is not writable
Setting: newlines
Error coping the attribute `newlines`: attribute 'newlines' of '_io.TextIOWrapper' objects is not writable
Setting: read
Setting: readable
Setting: readline
Setting: readlines
Setting: seek
Setting: seekable
Setting: tell
Setting: truncate
Setting: writable
Setting: write
Setting: writelines
TargetCopiedObject: <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>
Вы можете скопировать эти свойства только для чтения, выполнив их при статической инициализации класса, как и другие встроенные магические методы python, как __str__
чуть выше:
import sys
_target_object = sys.stderr
_target_object_class_type = type( _target_object )
class TargetCopiedObject(_target_object_class_type):
"""
Which special methods bypasses __getattribute__ in Python?
https://stackoverflow.com/questions/12872695/which-special-methods-bypasses
"""
if hasattr( _target_object, "__abstractmethods__" ):
__abstractmethods__ = _target_object.__abstractmethods__
if hasattr( _target_object, "__base__" ):
__base__ = _target_object.__base__
if hasattr( _target_object, "__bases__" ):
__bases__ = _target_object.__bases__
if hasattr( _target_object, "__basicsize__" ):
__basicsize__ = _target_object.__basicsize__
if hasattr( _target_object, "__call__" ):
__call__ = _target_object.__call__
if hasattr( _target_object, "__class__" ):
__class__ = _target_object.__class__
if hasattr( _target_object, "__delattr__" ):
__delattr__ = _target_object.__delattr__
if hasattr( _target_object, "__dict__" ):
__dict__ = _target_object.__dict__
if hasattr( _target_object, "__dictoffset__" ):
__dictoffset__ = _target_object.__dictoffset__
if hasattr( _target_object, "__dir__" ):
__dir__ = _target_object.__dir__
if hasattr( _target_object, "__doc__" ):
__doc__ = _target_object.__doc__
if hasattr( _target_object, "__eq__" ):
__eq__ = _target_object.__eq__
if hasattr( _target_object, "__flags__" ):
__flags__ = _target_object.__flags__
if hasattr( _target_object, "__format__" ):
__format__ = _target_object.__format__
if hasattr( _target_object, "__ge__" ):
__ge__ = _target_object.__ge__
if hasattr( _target_object, "__getattribute__" ):
__getattribute__ = _target_object.__getattribute__
if hasattr( _target_object, "__gt__" ):
__gt__ = _target_object.__gt__
if hasattr( _target_object, "__hash__" ):
__hash__ = _target_object.__hash__
if hasattr( _target_object, "__init__" ):
__init__ = _target_object.__init__
if hasattr( _target_object, "__init_subclass__" ):
__init_subclass__ = _target_object.__init_subclass__
if hasattr( _target_object, "__instancecheck__" ):
__instancecheck__ = _target_object.__instancecheck__
if hasattr( _target_object, "__itemsize__" ):
__itemsize__ = _target_object.__itemsize__
if hasattr( _target_object, "__le__" ):
__le__ = _target_object.__le__
if hasattr( _target_object, "__lt__" ):
__lt__ = _target_object.__lt__
if hasattr( _target_object, "__module__" ):
__module__ = _target_object.__module__
if hasattr( _target_object, "__mro__" ):
__mro__ = _target_object.__mro__
if hasattr( _target_object, "__name__" ):
__name__ = _target_object.__name__
if hasattr( _target_object, "__ne__" ):
__ne__ = _target_object.__ne__
if hasattr( _target_object, "__new__" ):
__new__ = _target_object.__new__
if hasattr( _target_object, "__prepare__" ):
__prepare__ = _target_object.__prepare__
if hasattr( _target_object, "__qualname__" ):
__qualname__ = _target_object.__qualname__
if hasattr( _target_object, "__reduce__" ):
__reduce__ = _target_object.__reduce__
if hasattr( _target_object, "__reduce_ex__" ):
__reduce_ex__ = _target_object.__reduce_ex__
if hasattr( _target_object, "__repr__" ):
__repr__ = _target_object.__repr__
if hasattr( _target_object, "__setattr__" ):
__setattr__ = _target_object.__setattr__
if hasattr( _target_object, "__sizeof__" ):
__sizeof__ = _target_object.__sizeof__
if hasattr( _target_object, "__str__" ):
__str__ = _target_object.__str__
if hasattr( _target_object, "__subclasscheck__" ):
__subclasscheck__ = _target_object.__subclasscheck__
if hasattr( _target_object, "__subclasses__" ):
__subclasses__ = _target_object.__subclasses__
if hasattr( _target_object, "__subclasshook__" ):
__subclasshook__ = _target_object.__subclasshook__
if hasattr( _target_object, "__text_signature__" ):
__text_signature__ = _target_object.__text_signature__
if hasattr( _target_object, "__weakrefoffset__" ):
__weakrefoffset__ = _target_object.__weakrefoffset__
if hasattr( _target_object, "mro" ):
mro = _target_object.mro
# Copy all the other read only attributes
if hasattr( _target_object, "buffer" ):
buffer = _target_object.buffer
if hasattr( _target_object, "closed" ):
closed = _target_object.closed
if hasattr( _target_object, "encoding" ):
encoding = _target_object.encoding
if hasattr( _target_object, "errors" ):
errors = _target_object.errors
if hasattr( _target_object, "line_buffering" ):
line_buffering = _target_object.line_buffering
if hasattr( _target_object, "name" ):
name = _target_object.name
if hasattr( _target_object, "newlines" ):
newlines = _target_object.newlines
def __init__(self):
"""
Override any super class `type( _target_object )` constructor,
so we can instantiate any kind of replacement object.
Assures all properties were statically replaced just above. This
should happen in case some new attribute is added to the python
language.
This also ignores the only two methods which are not equal,
`__init__()` and `__getattribute__()`.
How do you programmatically set an attribute?
https://stackoverflow.com/questions/285061/how-do-you-programmatically
"""
# Add the copied read only atribute to the ignored list, so they
# do not throw new errors while trying copy they dynamically
different_methods = set\
([
"__init__",
"__getattribute__",
"buffer",
"closed",
"encoding",
"errors",
"line_buffering",
"name",
"newlines",
])
attributes_to_check = set( dir( object ) + dir( type ) )
attributes_to_copy = dir( _target_object )
# Check for missing magic built-ins methods on the class static initialization
for attribute in attributes_to_check:
if attribute not in different_methods \
and hasattr( _target_object, attribute ):
base_class_attribute = self.__getattribute__( attribute )
target_class_attribute = _target_object.__getattribute__( attribute )
if base_class_attribute != target_class_attribute:
sys.stdout.write(
" The base class attribute `%s` is different from the "
"target class:\n%s\n%s\n\n" % ( attribute,
base_class_attribute,
target_class_attribute ) )
# Finally copy everything it can
different_methods.update( attributes_to_check )
for attribute in attributes_to_copy:
if attribute not in different_methods:
print( "Setting:", attribute )
try:
target_class_attribute = _target_object.__getattribute__(attribute)
setattr( self, attribute, target_class_attribute )
except AttributeError as error:
print( "Error coping the attribute `%s`: %s" % (attribute, error) )
o = TargetCopiedObject()
print( "TargetCopiedObject:", o )
Теперь эта новая версия полностью работает, справляясь со всем:
python test.py
Setting: _CHUNK_SIZE
Setting: __del__
Setting: __enter__
Setting: __exit__
Setting: __getstate__
Setting: __iter__
Setting: __next__
Setting: _checkClosed
Setting: _checkReadable
Setting: _checkSeekable
Setting: _checkWritable
Setting: _finalizing
Setting: close
Setting: detach
Setting: fileno
Setting: flush
Setting: isatty
Setting: mode
Setting: read
Setting: readable
Setting: readline
Setting: readlines
Setting: seek
Setting: seekable
Setting: tell
Setting: truncate
Setting: writable
Setting: write
Setting: writelines
TargetCopiedObject: <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>
Недостатком является то, что вам нужно писать код Python вручную, чтобы преодолеть атрибуты только для чтения. Тем не менее, вы можете написать код Python на лету с помощью метапрограммирования:
- Python: Как сгенерировать код на лету?
- https://en.wikipedia.org/wiki/Metaprogramming
Итак, если вы работаете над этим исходным кодом чуть выше, вы можете написать скрипт, который сгенерирует необходимый код. Следовательно, вы можете динамически полностью копировать любой объект Python.