Dynamically replacing an objects __class__; is it safe?

Peter Otten __peter__ at web.de
Wed Mar 15 06:33:26 EDT 2017


marco.nawijn at colosso.nl wrote:

> Dear All,
> 
> Summary of the question:
> Is it generally safe to dynamically change an objects class; if not
> under which conditions can it be considered safe.
> 
> Context:
> Given the code below, I have no direct control over Base and M1. M1
> is a instantiated by 'calling' the read-only property of Base.
> I would like to transparently switch behaviour from M1 to M2. I have
> tried several things, but finally settled on the code below. Although
> it works really well, I am not sure whether I am about to shoot myself
> in the foot. In short, what I do is derive from Base, shadow the read-only
> property 'my_prop' so it returns M2 and finally replace an objects
> __class__ attribute with my derived class.
> 
> Any thoughts or comments?

Saying that something is "safe" is always problematic. I'd rather look for 
ways to break the code and then decide if you can live with these potential 
problems. I'll start with

- If Base is reimplemented in C __class__ may become read-only
- my_prop may be accessed by Base methods and expect an M1 instance

> (code below is Python 3)
> 
> class M1(object):
> 
>     def __init__(self):
>         print('Initializing M1')
> 
> 
> class M2(object):
>                                                                                      
>     def __init__(self):
>         print('Initializing M2')
>                                                                                      
>                                                                                      
> class Base(object):
>                                                                                      
>     @property
>     def my_prop(self):
>         return M1()
> 
> 
> class ShadowBase(Base):
> 
>     @property
>     def my_prop(self):
>         return M2()
> 
> if __name__ == '__main__':
> 
>     o = Base()
>     o.my_prop
>     # Prints 'Initializing M1'
> 
>     o = Base()
>     o.__class__ = ShadowBase
>     o.my_prop
>     # Prints 'Initializing M2'





More information about the Python-list mailing list