[Python-Dev] Meta-reflections (original) (raw)
john coppola john_coppola_r_s@yahoo.com
Mon, 18 Feb 2002 08:46:55 -0800 (PST)
- Previous message: [Python-Dev] Meta-reflections
- Next message: [Python-Dev] Meta-reflections
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
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 adescr = bar.class.a print adescr.set(bar) # bar.a = 1 adescr = bar.class.a adescr.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 afoodescr = bar.class.base.a abardescr = bar.class.a afoodescr.set(bar,1) abardescr.set(bar,2) print bar.a > 2 print afoodescr.get(bar) > 1 print abardescr.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
- Previous message: [Python-Dev] Meta-reflections
- Next message: [Python-Dev] Meta-reflections
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]