Let’s say I have a class like this:
class Test(object):
prop = property(lambda self: "property")
The descriptor takes priority whenever I try to access Test().prop. So that will return 'property'. If I want to access the object’s instance storage, I can do:
x = Test()
x.__dict__["prop"] = 12
print(x.__dict__["prop"])
However if I change my class to:
class Test(object):
__slots__ = ("prop",)
prop = property(lambda self: "property")
How do I do the same, and access the internal storage of x, to write 12 and read it back, since x.__dict__ no longer exist?
I am fairly new with Python, but I understand the Python philosophy is to give complete control, so why is an implementation detail preventing me from doing that?
Isn’t Python missing a built-in function that could read from an instance internal storage, something like:
instance_vars(x)["prop"] = 12
print(instance_vars(x)["prop"])
which would work like vars, except it also works with __slots__, and with built-in types that don’t have a __dict__?
Short answer, You can’t
The problem is that slots are themselves implemented in terms of descriptors. Given:
the phrase:
Is translated, approximately to:
where
Test.propis a<type 'member_descriptor'>crafted by the run-time specifically to loadpropvalues out ofTestinstances from their reserved space.If you add another descriptor to the class body definition, it masks out the
member_descriptorthat would let you get to the slotted attribute; there’s no way to ask for it, it’s just not there anymore. It’s effectively like saying:You’ve defined it twice. there’s no way to “get at” the first
propdefinition.but:
Long answer, you can’t in a general way. You can
You can still abuse the python type system to get at it using another class definition. You can change the type of a python object, so long as it has the exact same class layout, which roughly means that it has all of the same slots:
But there’s no general way to introspect an instance to work out its class layout; you just have to know from context. You could look at it’s
__slots__class attribute, but that won’t tell you about the slots provided in the superclass (if any) nor will it give you any hint if that attribute has changed for some reason after the class was defined.