Putting answers to this and related question together, I want to make an accent on a solution to this problem:
You can kind of modify __slots__
by creating a subclass with the same name and then replacing parent class with its child. Note that you can do this for classes declared and used in any module, not just yours!
Consider the following module which declares some classes:
module.py:
class A(object):
# some class a user should import
__slots__ = ('x', 'b')
def __init__(self):
self.b = B()
class B(object):
# let's suppose we can't use it directly,
# it's returned as a part of another class
__slots__ = ('z',)
Here's how you can add attributes to these classes:
>>> import module
>>> from module import A
>>>
>>> # for classes imported into your module:
>>> A = type('A', (A,), {'__slots__': ('foo',)})
>>> # for classes which will be instantiated by the `module` itself:
>>> module.B = type('B', (module.B,), {'__slots__': ('bar',)})
>>>
>>> a = A()
>>> a.x = 1
>>> a.foo = 2
>>>
>>> b = a.b
>>> b.z = 3
>>> b.bar = 4
>>>
But what if you receive class instances from some third-party module using the module
?
module_3rd_party.py:
from module import A
def get_instance():
return A()
No problem, it will also work! The only difference is that you may need to patch them before you import third-party module (in case it imports classes from the module
):
>>> import module
>>>
>>> module.A = type('A', (module.A,), {'__slots__': ('foo',)})
>>> module.B = type('B', (module.B,), {'__slots__': ('bar',)})
>>>
>>> # note that we import `module_3rd_party` AFTER we patch the `module`
>>> from module_3rd_party import get_instance
>>>
>>> a = get_instance()
>>> a.x = 1
>>> a.foo = 2
>>>
>>> b = a.b
>>> b.z = 3
>>> b.bar = 4
>>>
It works because Python imports modules only once and then shares them between all other modules, so the changes you make to modules affect all code running along yours.