empty classes as c structs?

  • Thread starter Christopher J. Bottaro
  • Start date
C

Carlos Ribeiro

One thing I'd like to see in namespaces is _chaining_ -- keeping each
namespace separate but having lookups proceed along the chain. (The
best semantics for _bindings_ as opposed to lookups isn't clear though).

Good point. The name 'namespace' kind of imples chaining, in the usual
Pythonic sense... But I feel that by splitting this into two types
(namespace & bunch) we may be making things overly complicated, and
losing some of the power of the argument. Again, just my $0.02 worth.

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: (e-mail address removed)
mail: (e-mail address removed)
 
N

Nick Coghlan

Alex said:
One thing I'd like to see in namespaces is _chaining_ -- keeping each
namespace separate but having lookups proceed along the chain. (The
best semantics for _bindings_ as opposed to lookups isn't clear though).

Hmm, so if it doesn't find it in the current namespace, it looks in the parent?

For bindings, you could just go with standard Python semantics - normal name
binding always happens in the innermost scope, so binding a name in a namespace
should happen in the directly referenced namespace. Then you can shadow names
from outer scopes, and later regain access to them using 'del'.

Rough concept:
Have a '__fallback__'** attribute that is initialised to None
Have a custom __getattr__ that falls back to the containing namespace if the
result is not found in the current namespace.
Have a class method which allows a namespace to be 'put inside' another
namespace.

** Blech. Trying to add *any* state to namespace instances is going to suck.
Maybe it would be better to just have a single __impl__ attribute and have any
implementation related variables hang off it. This could make life easier when
subclassing. I'm tempted to say update() should just ignore any field with a
leading underscore by default (then we can just use normal private attributes,
which are altered at the user's risk), but that may be too draconian.


On a complete tangent, I thought it might be worthwhile summarising the ideas
that have come up in this thread

- using type(self).method(self,...) as a polymorphism friendly way to access a
class method.

- a 'view' alternate constructor to allow manipulation of an existing
dictionary such as globals()

- a 'record' data type that allows the use of class definition syntax for
simple data structures

- lookup chaining, allowing fallback to an 'outer scope'.


Even though we'll probably end up dropping the last couple as overengineering
things for the first pass, they're still interesting ideas to kick around.

Cheers,
Nick.
 
C

Carlos Ribeiro

Hmm, so if it doesn't find it in the current namespace, it looks in the parent?

For bindings, you could just go with standard Python semantics - normal name
binding always happens in the innermost scope, so binding a name in a namespace
should happen in the directly referenced namespace. Then you can shadow names
from outer scopes, and later regain access to them using 'del'.

What does PyPy do in this case? It seems that a 'namespace' class, or
at least part of its behavior, is needed there anyway... It seems to
be worth checking.
Rough concept:
Have a '__fallback__'** attribute that is initialised to None
Have a custom __getattr__ that falls back to the containing namespace if the
result is not found in the current namespace.
Have a class method which allows a namespace to be 'put inside' another
namespace.

** Blech. Trying to add *any* state to namespace instances is going to suck.
Maybe it would be better to just have a single __impl__ attribute and have any
implementation related variables hang off it. This could make life easier when
subclassing. I'm tempted to say update() should just ignore any field with a
leading underscore by default (then we can just use normal private attributes,
which are altered at the user's risk), but that may be too draconian.

On a complete tangent, I thought it might be worthwhile summarising the ideas
that have come up in this thread

- using type(self).method(self,...) as a polymorphism friendly way to access a
class method.

- a 'view' alternate constructor to allow manipulation of an existing
dictionary such as globals()

- a 'record' data type that allows the use of class definition syntax for
simple data structures

- lookup chaining, allowing fallback to an 'outer scope'.

Even though we'll probably end up dropping the last couple as overengineering
things for the first pass, they're still interesting ideas to kick around.

Another idea, maybe even more distantly related but still worthy
keeping in mind: the 'named tuples' that we talked about a few months
ago. It is in some sense a variation on some of the ideas presented
here; it is an alternative way to build simple records or bunch-like
structures.

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: (e-mail address removed)
mail: (e-mail address removed)
 
A

Alex Martelli

Nick Coghlan said:
Hmm, so if it doesn't find it in the current namespace, it looks in the
parent?
Yep.

For bindings, you could just go with standard Python semantics - normal
name binding always happens in the innermost scope, so binding a name in a
namespace should happen in the directly referenced namespace. Then you can
shadow names from outer scopes, and later regain access to them using
'del'.

....which you can't do in "standard Python semantics" - if a name is
local, it's local throughout. You can't do that with a namespace
object, which is why I think the best semantics for bindings in that
case isn't all that clear.


Alex
 
S

Steven Bethard

Alex said:
One thing I'd like to see in namespaces is _chaining_ -- keeping each
namespace separate but having lookups proceed along the chain. (The
best semantics for _bindings_ as opposed to lookups isn't clear though).

I'm not sure I understand exactly what you're looking for here... Is
this what you want?

py> b = Bunch.chain(Bunch(x=1), Bunch(x=2, y=2), Bunch(y=3))
py> b.x
1
py> del b.x
py> b.x
2
py> del b.x
py> b.x
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "D:\Steve\My Programming\python\bunch.py", line 104, in
__getattribute__
raise AttributeError(name)
AttributeError: x
py> b.y
2
py> del b.y
py> b.y
3
py> del b.y
py> b.y
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "D:\Steve\My Programming\python\bunch.py", line 104, in
__getattribute__
raise AttributeError(name)
AttributeError: y

Or should 'del b.x' remove all 'x' attributes from all the bunches in
the chain?


The code I used for this looks like:

class Bunch(object):
...
class chain(object):
def __init__(self, *bunches):
self._bunches = bunches
def __getattribute__(self, name):
getattribute = super(Bunch.chain, self).__getattribute__
try:
return getattribute(name)
except AttributeError:
for bunch in getattribute('_bunches'):
try:
return getattr(bunch, name)
except AttributeError:
pass
raise AttributeError(name)
def __delattr__(self, name):
for bunch in self._bunches:
try:
return delattr(bunch, name)
except AttributeError:
pass
raise AttributeError(name)

I didn't know what to do for __setattr__... Was that what you meant by
"The best semantics for _bindings_ as opposed to lookups isn't clear
though"?

Steve
 
A

Alex Martelli

Steven Bethard said:
I didn't know what to do for __setattr__... Was that what you meant by
"The best semantics for _bindings_ as opposed to lookups isn't clear
though"?

Yep. __delattr__ ain't too obvious to me either, though I guess your
semantics for that are OK.


Alex
 
S

Steven Bethard

Alex said:
Yep. __delattr__ ain't too obvious to me either, though I guess your
semantics for that are OK.

I'm not sure how much _I_ like them... =) It makes me uneasy that

del b.x
print b.x

doesn't throw an AttributeError. OTOH, if you're using namespaces as
the equivalent of nested scopes, deleting all 'x' attributes is probably
not what you want...

I like the idea of chain, though, so I'll probably add the class with
just __init__ and __getattribute__ to the current implementation. I'm
willing to be persuaded, of course, but for the moment, since I can see
a few different options, I'm refusing the temptation to guess on the
"most natural" behavior for __delattr__ and __setattr__... =)

Steve
 
A

Alex Martelli

Steven Bethard said:
I'm not sure how much _I_ like them... =) It makes me uneasy that

del b.x
print b.x

doesn't throw an AttributeError. OTOH, if you're using namespaces as
the equivalent of nested scopes, deleting all 'x' attributes is probably
not what you want...

Right. Besides, you can easily get such effects today:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: x


All you need is to have (e.g.) the following few lines before these:
.... x = 23
....
I like the idea of chain, though, so I'll probably add the class with
just __init__ and __getattribute__ to the current implementation. I'm
willing to be persuaded, of course, but for the moment, since I can see
a few different options, I'm refusing the temptation to guess on the
"most natural" behavior for __delattr__ and __setattr__... =)

That's probably best in terms of API. Not too sure about the
implementation (why wouldn't __getattr__ suffice, holding the bunches in
an attribute with a magicname?) but that's a secondary issue.


Alex
 
N

Nick Coghlan

Alex said:
...which you can't do in "standard Python semantics" - if a name is
local, it's local throughout. You can't do that with a namespace
object, which is why I think the best semantics for bindings in that
case isn't all that clear.

Heh. I was getting two sets of terminology confused. The nested scopes of
functions, and the 'fallback to class' of class instances.

It was the latter I actually meant by 'standard Python semantics' for binding in
a 'chained' namespace:

Py> class C(object):
.... x = 1
....
Py> c = C()
Py> c = C()
Py> c.x
1
Py> del c.x
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'C' object attribute 'x' is read-only
Py> c.x = 2
Py> c.x
2
Py> del c.x
Py> c.x
1
Py> del c.x
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: x

(Huh, I wonder why the error message changed second time around)

Cheers,
Nick.
 
S

Steven Bethard

Alex said:
That's probably best in terms of API. Not too sure about the
implementation (why wouldn't __getattr__ suffice, holding the bunches in
an attribute with a magicname?) but that's a secondary issue.

Yeah, I had it written with __getattr__ at first... Not sure why I
switched over... ;) I'll probably switch it back.

Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,802
Messages
2,569,663
Members
45,433
Latest member
andrewartemow

Latest Threads

Top