Question about accessing class-attributes.
Bjorn Pettersen
BPettersen at NAREX.com
Thu May 1 19:41:03 EDT 2003
> From: Michele Simionato [mailto:mis6 at pitt.edu]
>
> Alex Martelli <aleax at aleax.it> wrote in message
> news:<joYra.44343$K35.1283700 at news2.tin.it>...
> > Michele Simionato wrote:
>
[...]
> > > """
> > > super(type[object-or-type])
> > >
> > > Return the superclass of type. If the second [...]
[...]
> > >
> > > But it DOES not return the superclass! I admit I myself at the
> > > beginning was confused.
> >
> > The documentation is surely imperfect (e.g. by making no reference
to
> > the mro, which is crucial in the case in which the 2nd argument is
> > there and is an instance of the first one). But doesn't the second
> > sentence say explicitly that e.g. super(C) returns a "super object"
> > that is unbound?
Yes. But I'd like it better if it said "bindable super object", as in an
object implementing a set of methods automatically belonging to a
category. (Similarly to e.g. file-like objects, the only thing special
here is that there's an explicit __get__). Or if that doesn't go over
well, at least add the definition of "unbound object" to LangRef 3.2,
close to "User defined methods", and make a link to it (making the
headings in 3.2 html targets(?) would be a good idea too). I'll go file
a doc bug.
> Yes, but the first sentence says it returns the superclass, therefore
> from the second sentence one could infer that a super object is a
> class (??). It is confusing, at least.
True. It's using terminology that means different things in different
languages, without defining it...
> > Maybe by "superclass" you mean "base", a common
> > usage, but then the singular "the superclass" would be absurd.
>
> Given a class C and a subclass S, there is ONLY ONE superclass of C
> with respect to the MRO of S. I have a routine returning the list of
> the ancestors of A with respect to the MRO of S:
Well, let's see if I know Python well enough to explain what it's doing
or perhaps what it should be doing...
Given an algorithm for instantiating a class, and creating a class
object (i.e. at runtime when you see "class X(object): ..." the
following things happen, similarly with "X(..)":
evaluate("class_declaration"):
- create an empty class C with C::__dict__ set to an
object of mapping type.
- if there exists a metaclass declaration, set the
attribute C::__class__, and C::__dict__['__metaclass__]
to the metaclass otherwise set C::__class__ to type.
...
- perform a C3 linearization on all the base classes
and assign the result as a tuple to C::__dict__[__mro__].
...
evaluate("instantiate(class_object)"):
- create an empty object obj with obj::__dict__ set to an
object of mapping type, and obj::__class__ to class_object.
...
are you saying simply:
definition("super class of C with respect to S") ::=
S.__mro__[index(C)+1]
would you entertain dividing it up:
linearized(C) ::=
C.__mro__
super_context(A1, A2) ::=
remaining = A2.__mro__[index(A1)+1 : ]
return remaining
linear_bases(C) ::= # more descriptive than ancestor?
C.__mro__[1:]
superclass(A1, A2) ::= # don't have a use case for this one
super_context(A1, A2)[0]
then super could be defined easily (and I can't see any obvious problems
with it, although that might not mean much right now... :-):
# Convenient shorthand, mainly to make them notationally
# separate from classes and objects (to prevent recursive
# deifnitions, can either be implemented as classes/objects
# or C structs, etc.
RECORD{class_tag}(v1,.., vn)
super(C, obj) ::=
context = super_context(C, obj)
return RECORD{super_object}(context, obj)
with __class__ := obj::__class__
super(C) ::=
r = RECORD{unbound_super}(C)
r.__get__(obj, _):
return super(C, obj)
return r
obj.attr ::=
if obj matches RECORD[super_object](context, obj)
return _get__attribute(obj, context, attr)
else:
return _get_attribute(obj, linearized(obj::__class__), x)
# len(), hash(), int(), ...
special(obj) ::=
# look it up using regular mechanism
hookFn = _get_attribute(obj, linearized(obj::__class__),
'__special__')
# tell imlementation how to call the hook
call_special_function(hookFn)
_compute_attribute(x, cls, attr) ::=
returns cls::__dict__['__getattr__'](x, attr) if it has a value
or raises AttributeError
_atomic_get_attribute(x, cls, attr) ::=
# how I think it should work (btw., type(x) is a red-herring).
Return the first expression that has a value (or raise from
compute_attribute):
if attr is normal:
x::__dict__[attr]
cls::__dict__[attr].__get__(x, cls)
cls::__dict__[attr]
compute_attribute(x, attr)
if attr is special:
cls::__dict__[attr]
cls.__metaclass__::__dict__[attr].__get__(cls,
cls.__metaclass__) ##??
cls.__metaclass__::__dict__[attr]
compute_attribute(cls, attr)
_get_attribute(x, linearization, attr):
for cls in linearization:
try:
return _atomic_get_attribute(x, cls, attr)
except AttributeError:
pass
raise AttributeError, attr
I'm not sure I got the descriptors right, so feel free to criticize...
-- bjorn
More information about the Python-list
mailing list