On 2/28/2020 2:21 AM, Adam Preble wrote:
I have been making some progress on my custom interpreter project but I found I
have totally blown implementing proper subclassing in the data model. What I
have right now is PyClass defining what a PyObject is. When I make a PyObject
from a PyClass, the PyObject sets up a __dict__ that is used for attribute
lookup. When I realized I needed to worry about looking up parent namespace
stuff, this fell apart because my PyClass had no real notion of a namespace.
I'm looking at the Python data model for inspiration. While I don't have to
implement the full specifications, it helps me where I don't have an
alternative. However, the data model is definitely a programmer document; it's
one of those things where the prose is being very precise in what it's saying
and that can foil a casual reading.
Here's what I think is supposed to exist:
1. PyObject is the base.
2. It has an "internal dictionary." This isn't exposed as __dict__
The internal mapping *is* visible.
>>> object.__dict__
mappingproxy({'__repr__': <slot wrapper '__repr__' of 'object' objects>,
'__hash__': <slot wrapper '__hash__' of 'object' objects>, '__str__':
<slot wrapper '__str__' of 'object' objects>, '__getattribute__': <slot
wrapper '__getattribute__' of 'object' objects>, '__setattr__': <slot
wrapper '__setattr__' of 'object' objects>, '__delattr__': <slot wrapper
'__delattr__' of 'object' objects>, '__lt__': <slot wrapper '__lt__' of
'object' objects>, '__le__': <slot wrapper '__le__' of 'object'
objects>, '__eq__': <slot wrapper '__eq__' of 'object' objects>,
'__ne__': <slot wrapper '__ne__' of 'object' objects>, '__gt__': <slot
wrapper '__gt__' of 'object' objects>, '__ge__': <slot wrapper '__ge__'
of 'object' objects>, '__init__': <slot wrapper '__init__' of 'object'
objects>, '__new__': <built-in method __new__ of type object at
0x00007FFBEFE989A0>, '__reduce_ex__': <method '__reduce_ex__' of
'object' objects>, '__reduce__': <method '__reduce__' of 'object'
objects>, '__subclasshook__': <method '__subclasshook__' of 'object'
objects>, '__init_subclass__': <method '__init_subclass__' of 'object'
objects>, '__format__': <method '__format__' of 'object' objects>,
'__sizeof__': <method '__sizeof__' of 'object' objects>, '__dir__':
<method '__dir__' of 'object' objects>, '__class__': <attribute
'__class__' of 'object' objects>, '__doc__': 'The base class of the
class hierarchy.\n\nWhen called, it accepts no arguments and returns a
new featureless\ninstance that has no instance attributes and cannot be
given any.\n'})
The internal mapping is not an instance of dict, and need/should not be
as it is frozen.
>>> o = object()
>>> o.a = 3
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
o.a = 3
AttributeError: 'object' object has no attribute 'a'
When classes and objects do have a dict __dict__, __dict__ is not in
__dict__, to avoid recursion. gettattribute or __getattribute__ must
special case '__dict__'. I am guessing this as what must be from the
evidence, without seeing the actual code.
3. PyClass subclasses PyObject.
4. PyClass has a __dict__
Is there a term for PyObject's internal dictionary. It wasn't called __dict__
and I think that's for good reasons. I guess the idea is a PyObject doesn't
have a namespace, but a PyClass does (?).
Now to look something up. I assume that __getattribute__ is supposed to do
something like:
1. The PyClass __dict__ for the given PyObject is consulted.
2. The implementation for __getattribute__ for the PyObject will default to looking into
the "internal dictionary."
3. Assuming the attribute is not found, the subclasses are then consulted using
the subclass' __getattribute__ calls. We might recurse on this. There's
probably some trivia here regarding multiple inheritance; I'm not entirely
concerned (yet).
For non-reserved names Attribute lookup starts with the object dict,
then object class, then superclasses. Dunder names usually start with
the object class.
4. Assuming it's never found, then the user sees an AttributeError
Would each of these failed lookups result in an AttributeError?
I presume so. They are caught and only re-raised only if there is no
where else to look.
--
Terry Jan Reedy
--
https://mail.python.org/mailman/listinfo/python-list