It's not that - you normally inherit metaclasses, so both Actor and
Store would nornally both have the same metaclass - eg, given this:
---demo.py---
class BasicMetaclass(type):
    def __new__(meta, name, bases, Dict):
        print "called for", name
        newdict = dict(Dict)
        klass = type.__new__(meta, name, bases, newdict)
        return klass

class Actor(object):
    __metaclass__ = BasicMetaclass
    def __init__(self, **defaults):
        self.__dict__.update(defaults)

class Store(Actor):
    pass
------------------
When run does this: (as you'd expect)
$ python demo.py
called for Actor
called for Store
$

That's all normal. That's what's bust here. However I've had a thought
which I might try.

Incidentally some of the points you made are red-herrings:

On Nov 7, 11:03 pm, "[email protected]"
<[email protected]> wrote:
> > Then normally I've be able to do this sort of this - replace this:
>
> > class Store(object):
> >    __metaclass__ = AttributeHiding
>
> >    def __init__(self, **defaults):
> >        self.__dict__.update(defaults)
>
> > with:
>
> > class Actor(object):
> >    __metaclass__ = AttributeHiding
>
> > class Store(Actor):
> >    def __init__(self, **defaults):
> >        self.__dict__.update(defaults)
>
> > ... and Store would have the same __metaclass__ as Actor and it'd Just
> > Work. This also then means people would just subclass Actor for things
> > to work like this.
>
> > However, I've done something that breaks this, and I'm not sure
> > what :-)
>
> 1. The Actor class (by virtue of its Metaclass) is actually the Proxy class.

Yep.

> 2. The Store class is still the plain old Store class.

Yep. *However* it should have the same metaclass as the Proxy class,
and use the Proxy class as a parent.
Note that before the

  - class Store(Actor):

line executes, inside mydec:
    Proxy.__metaclass__ = klass.__metaclass__

ie it explicitly adds the metaclass to the Proxy class for subclasses
to inherit. Which they then don't :-)

> 3. Proxy defines an __init__ method which *must* be called in order for the
> proxied object (i.e. either an instance of Actor or Store) to be created.

That's then a red herring, since the lack of execution of the
metaclass means that the subclasses
methods are also bust. eg, by not having the parent class you get:

called for Store
the x.greet line causes the greet method to be called. That calls
x.display directly, from within the class
BOUNCED THROUGH THE PROXY CALLABLE
INTERNAL CALL TO DISPLAY
self.display <__main__.Store object at 0xb730758c>
self <__main__.Store object at 0xb730758c>
INTERNAL CALL TO DISPLAY
self.display <__main__.Store object at 0xb730758c>
hello world
The next x.display line bounces though a proxy object
BOUNCED THROUGH THE PROXY CALLABLE
self.display <__main__.Store object at 0xb730758c>
Expect next display call with data to fail, because x.greeting isn't a
public attribute

Traceback (most recent call last):
  File "internal_external.py", line 86, in <module>
    x.display(x.greeting)
  File "internal_external.py", line 13, in __getattribute__
    value = super(Proxy, self).__getattribute__(key)
AttributeError: 'Store_Proxy' object has no attribute 'greeting'

Which is all good. (That error is expected)

If however, you do have the parent class (as per mail) you get:

called for Actor
the x.greet line causes the greet method to be called. That calls
x.display directly, from within the class
Traceback (most recent call last):
  File "internal_external.py", line 81, in <module>
    x.greet()
TypeError: 'tuple' object is not callable

And that's happening because the metaclass wasn't inherited correctly,
due to the class decorator.

> 4. When you call a = Actor(), this is effectively calling Proxy.__init__
> and the proxied object is created (see points 1 and 3).
> 5. When you call s = Store(), you're simply calling plain old
> Store.__init__ and not Proxy.__init__ so no proxied object is created (see
> point 2).
>
> A quick fix is to ensure Store.__init__ calls the superclass __init__ so
> the proxied object is created:

Not really, that doesn't fix the metaclass for Store, which means it's
a non-functional thing :-)

> class Store(Actor):
>   def __init__(self, **defaults):
>     *super(Store, self).init(**defaults)*
>
> ... or simply omit the __init__ method from Store!
>
> These quick fixes aren't ideal as they rely on too much knowledge by the
> subclass, ...

... and don't actually fix the real problem - that the decorated class
created by the metaclass having a metaclass that isn't inherited by
subclasses. I think I can see how to fix that though.

> ... but they shed light on what's going on.  I'll leave a better fix
> as an exercise for the reader ... ;)

As noted I've had some thoughts about it, so I'll have a play.

Michael.

-- 
To post: [email protected]
To unsubscribe: [email protected]
Feeds: http://groups.google.com/group/python-north-west/feeds
More options: http://groups.google.com/group/python-north-west

Reply via email to