[Python-Dev] Meta-reflections
john coppola
john_coppola_r_s@yahoo.com
Mon, 18 Feb 2002 08:46:55 -0800 (PST)
I haven't even finished reading this yet.
This is good stuff!
--- Kevin Jacobs <jacobs@penguin.theopalgroup.com>
wrote:
> Hello all,
>
> I've been meta-reflecting a lot lately: reflecting
> on reflection.
>
> My recent post on __slots__ not being picklable (and
> the resounding lack of
> response to it) inspired me to try my hand at
> channeling Guido and reverse-
> engineer some of the design decisions that went into
> the new-style class
> system. Unfortunately, the more I dug into the
> code, the more philosophical
> my questions became. So, I've written up some
> questions that help lay bare
> some of basic design questions that I've been asking
> myself and that you
> should be aware of.
>
> While there are several subtle issues I could raise,
> I do want some feedback
> on some simple and fundamental ones first. Please
> don't disqualify yourself
> from commenting because you haven't read the code or
> used the new features
> yet. I've written my examples assuming only a basic
> and cursor
> understanding of the new Python 2.2 features.
>
> [In this discussion I am only going to talk about
> native Python classes,
> not C-extension or native Python types (e.g.,
> ints, lists, tuples,
> strings, cStringIO, etc.)]
>
> 1) Should class instances explicitly/directly know
> all of their attributes?
>
> Before Python 2.2, all object instances
> contained a __dict__ attribute
> that mapped attribute names to their values.
> This made pickling and
> some other reflection tasks fairly easy.
>
> e.g.:
>
> class Foo:
> def __init__(self):
> self.a = 1
> self.b = 2
>
> class Bar(Foo):
> def __init__(self):
> Foo.__init__(self)
> self.c = 3
>
> bar = Bar()
> print bar.__dict__
> > {'a': 1, 'c': 3, 'b': 2}
>
> I am aware that there are situations where this
> simple case does not
> hold (e.g., when implementing __setattr__ or
> __getattr__), but let's
> ignore those for now. Rather, I will
> concentrate on how this classical
> Python idiom interacts with the new slots
> mechanism. Here is the above
> example using slots:
>
> e.g.:
>
> class Foo(object):
> __slots__ = ['a','b']
> def __init__(self):
> self.a = 1
> self.b = 2
>
> class Bar(Foo):
> __slots__ = ['c']
> def __init__(self):
> Foo.__init__(self)
> self.c = 3
>
> bar = Bar()
> print bar.__dict__
> > AttributeError: 'Bar' object has no
> attribute '__dict__'
>
> We can see that the class instance 'bar' has no
> __dict__ attribute.
> This is because the slots mechanism allocates
> space for attribute
> storage directly inside the object, and thus
> does not use (or need) a
> per-object instance dictionary to store
> attributes. Of course, it is
> possible to request that a per-instance
> dictionary by inheriting from a
> new-style class that does not list any slots.
> e.g. continuing from
> above:
>
> class Baz(Bar):
> def __init__(self):
> Bar.__init__(self)
> self.d = 4
> self.e = 5
>
> baz = Baz()
> print baz.__dict__
> > {'e': 5, 'd': 4}
>
> We have now created a class that has __dict__,
> but it only contains the
> attributes not stored in slots! So, should
> class instances explicitly
> know their attributes? Or more precisely,
> should class instances
> always have a __dict__ attribute that contains
> their attributes? Don't
> worry, this does not mean that we cannot also
> have slots, though it
> does have some other implications. Keep
> reading...
>
>
> 2) Should attribute access follow the same
> resolution order rules as
> methods?
>
> class Foo(object):
> __slots__ = ['a']
> self.a
> def __init__(self):
> self.a = 1
>
> class Bar(Foo):
> __slots__ = ('a',)
> def __init__(self):
> Foo.__init__(self)
> self.a = 2
>
> bar = Bar()
> print bar.a
> > 2
> print super(Bar,bar).a # this doesn't
> actually work
> > 2 or 1?
>
> Don't worry -- this isn't a proposal and no,
> this doesn't actually work.
> However, the current implementation only
> narrowly escapes this trap:
>
> print bar.__class__.a.__get__(bar)
> > 2
> print bar.__class__.__base__.a.__get__(bar)
> > AttributeError: a
>
> Ok, let me explain what just happened. Slots
> are implemented via the
> new descriptor interface. In short, descriptor
> objects are properties
> and support __get__ and __set__ methods. The
> slot descriptors are told
> the offset within an object instance the
> PyObject* lives and proxy
> operations for them. So getting and setting
> slots involves:
>
> # print bar.a
> a_descr = bar.__class__.a
> print a_descr.__set__(bar)
>
> # bar.a = 1
> a_descr = bar.__class__.a
> a_descr.__set__(bar, 1)
>
> So, above we get an attribute error when trying
> to access the 'a' slot
> from Bar since it was never initialized.
> However, with a little
> ugliness you can do the following:
>
> # Get the descriptors for Foo.a and Bar.a
> a_foo_descr = bar.__class__.__base__.a
> a_bar_descr = bar.__class__.a
> a_foo_descr.__set__(bar,1)
> a_bar_descr.__set__(bar,2)
>
> print bar.a
> > 2
> print a_foo_descr.__get__(bar)
> > 1
> print a_bar_descr.__get__(bar)
> > 2
>
> In other words, the namespace for slots is not
> really flat, although
> there is no simple way to access these hidden
> attributes
=== message truncated ===
__________________________________________________
Do You Yahoo!?
Yahoo! Sports - Coverage of the 2002 Olympic Games
http://sports.yahoo.com