By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,353 Members | 1,256 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,353 IT Pros & Developers. It's quick & easy.

empty classes as c structs?

P: n/a
I find myself doing the following very often:

class Struct:
pass
....
blah = Struct()
blah.some_field = x
blah.other_field = y
....

Is there a better way to do this? Is this considered bad programming
practice? I don't like using tuples (or lists) because I'd rather use
symbolic names, rather than numeric subscripts. Also, I don't like having
to declare the empty Struct class everytime I want to do this (which is
very often).

Feedback is appreciated, thanks.

Jul 18 '05 #1
Share this Question
Share on Google+
49 Replies


P: n/a
Christopher J. Bottaro wrote:
I find myself doing the following very often:

class Struct:
pass
...
blah = Struct()
blah.some_field = x
blah.other_field = y
...

Is there a better way to do this?


Yes -- help me rally behind my generic object PEP which proposes a Bunch
type (probably to be renamed) for the Python standard lib. =) With this
type, you could write your code as:

blah = Bunch()
blah.some_field = x
blah.other_field = y

or simply:

blah = Bunch(some_field=x, other_field=y)

I requested a PEP number on 2 Jan 2005, but haven't heard back yet.
However, you can see a recent draft of the PEP at:

http://mail.python.org/pipermail/pyt...ry/262201.html

and you can see the first version of the patch at:

http://sourceforge.net/tracker/?func...&group_id=5470

If you'd like to use the Bunch type now (instead of waiting for a future
version of Python, assuming it's accepted), the current code for the
Bunch class follows.

STeVe

----------------------------------------------------------------------
# Copyright (c) 2004 Python Software Foundation.
# All rights reserved.

# Written by Steven Bethard <steven.bethard at gmail.com>

import operator as _operator

class Bunch(object):
"""Bunch([bunch|dict|seq], **kwds) -> new bunch with specified
attributes

The new Bunch object's attributes are initialized from (if
provided) either another Bunch object's attributes, a
dictionary, or a sequence of (name, value) pairs, then from the
name=value pairs in the keyword argument list.

Example Usage:
Bunch(eggs=1, spam=2, ham=3) Bunch(eggs=1, ham=3, spam=2) Bunch({'eggs':1, 'spam':2, 'ham':3}) Bunch(eggs=1, ham=3, spam=2) Bunch([('eggs',1), ('spam',2), ('ham',3)]) Bunch(eggs=1, ham=3, spam=2) Bunch(Bunch(eggs=1, spam=2), ham=3)

Bunch(eggs=1, ham=3, spam=2)
"""

def __init__(*args, **kwds):
"""Initializes a Bunch instance."""
Bunch.update(*args, **kwds)

def __eq__(self, other):
"""x.__eq__(y) <==> x == y

Two Bunch objects are considered equal if they have the same
attributes and the same values for each of those attributes.
"""
return (other.__class__ == self.__class__ and
self.__dict__ == other.__dict__)

def __repr__(self):
"""x.__repr__() <==> repr(x)

If all attribute values in this bunch (and any nested
bunches) are reproducable with eval(repr(x)), then the Bunch
object is also reproducable for eval(repr(x)).
"""
return '%s(%s)' % (self.__class__.__name__,
', '.join('%s=%r' % (k, v)
for k, v
in self.__dict__.items()))

@staticmethod
def update(*args, **kwargs):
"""update(bunch, [bunch|dict|seq,] **kwargs) -> None

Updates the first Bunch object's attributes from (if
provided) either another Bunch object's attributes, a
dictionary, or a sequence of (name, value) pairs, then from
the name=value pairs in the keyword argument list.
"""
if not 1 <= len(args) <= 2:
raise TypeError('expected 1 or 2 arguments, got %i' %
len(args))
self = args[0]
if not isinstance(self, Bunch):
raise TypeError('first argument to update should be Bunch, '
'not %s' % type(self).__name__)
if len(args) == 2:
other = args[1]
if isinstance(other, Bunch):
other = other.__dict__
try:
self.__dict__.update(other)
except (TypeError, ValueError):
raise TypeError('cannot update Bunch with %s' %
type(other).__name__)
self.__dict__.update(kwargs)
Jul 18 '05 #2

P: n/a
Christopher,

I've found myself doing the same thing. You could do something like this:

blah = type('Struct', (), {})()
blah.some_field = x

I think I'd only do this if I needed to construct objects at runtime
based on information that I don't have at compile time, since the two
lines of code for your empty class would probably be more recognizable
to more people.

If this usage of type() strikes anyone as inappropriate please let me
know, because I really don't know. :)

Christopher J. Bottaro wrote:
I find myself doing the following very often:

class Struct:
pass
...
blah = Struct()
blah.some_field = x
blah.other_field = y
...

Is there a better way to do this? Is this considered bad programming
practice? I don't like using tuples (or lists) because I'd rather use
symbolic names, rather than numeric subscripts. Also, I don't like having
to declare the empty Struct class everytime I want to do this (which is
very often).

Feedback is appreciated, thanks.

Jul 18 '05 #3

P: n/a
Christopher J. Bottaro wrote:
I find myself doing the following very often:

class Struct:
pass
...
blah = Struct()
blah.some_field = x
blah.other_field = y
...

Is there a better way to do this? Is this considered bad programming
practice? I don't like using tuples (or lists) because I'd rather use
symbolic names, rather than numeric subscripts. Also, I don't like having
to declare the empty Struct class everytime I want to do this (which is
very often).


I have a module of my own (data.py) that I use a lot. It contains:

class Data(object):
def __init__(self, **initial):
for name, val in initial.iteritems():
setattr(self, name, val)

def __repr__(self):
names = sorted([name for name in dir(self)
if not name.startswith('_')],
key=lambda name: (name.lower(), name))
return '%s(%s)' % (self.__class__.__name__, ', '.join([
'%s=%r' % (nm, getattr(self, nm)) for nm in names]))

The advantage is that I can see the value in the Data object simply
by printing the object. I use it like:

from data import Data

blah = Data(some_field=3, other_field=13)
...
blah.other_field = 23
...

--Scott David Daniels
Sc***********@Acm.Org
Jul 18 '05 #4

P: n/a
Alan McIntyre wrote:
You could do something like this:

blah = type('Struct', (), {})()
blah.some_field = x

I think I'd only do this if I needed to construct objects at runtime
based on information that I don't have at compile time, since the two
lines of code for your empty class would probably be more recognizable
to more people.


Actually, in Python, class definitions are runtime executable statements
just like any other. You can do this:
def make_class(with_spam=True): .... if with_spam:
.... class TheClass(object):
.... def dostuff(self):
.... print 'Spam, spam, spam, spam!'
.... else:
.... class TheClass(object):
.... def dostuff(self):
.... print "I don't like spam!"
.... return TheClass
.... make_class(True)().dostuff() Spam, spam, spam, spam! make_class(False)().dostuff() I don't like spam!

And this:
class Foo(object): .... num = 3
.... for _ in xrange(14):
.... num *= 1.22
.... Foo.num

48.546607267977542
Jul 18 '05 #5

P: n/a
Steven Bethard wrote:
Yes -- help me rally behind my generic object PEP which proposes a Bunch
type (probably to be renamed) for the Python standard lib. =)


Did you see the suggestion of 'namespace' as a name? Given that the idea is to
get access to the contents using the standard Python syntax for accessing module
and class namespaces, it seems to make sense.

Michael Spencer also posted an interesting idea recently about setting up a view
of an existing dictionary, rather than as a separate object:

class attr_view(object):
def __init__(self, data):
object.__setattr__(self, "_data", data)
def __getattr__(self, attrname):
return self._data[attrname]
def __setattr__(self, attrname, value):
self._data[attrname] = value

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #6

P: n/a
Nick Coghlan <nc******@iinet.net.au> wrote:
...
Michael Spencer also posted an interesting idea recently about setting up
a view of an existing dictionary, rather than as a separate object:

class attr_view(object):
def __init__(self, data):
object.__setattr__(self, "_data", data)
def __getattr__(self, attrname):
return self._data[attrname]
def __setattr__(self, attrname, value):
self._data[attrname] = value


Wasted indirection, IMHO. A better implementation:

class attr_view(object):
def __init__(self, data):
self.__dict__ = data
Alex
Jul 18 '05 #7

P: n/a
On Sat, 05 Feb 2005 02:38:13 -0500, Leif K-Brooks <eu*****@ecritters.biz> wrote:
Actually, in Python, class definitions are runtime executable statements
just like any other. You can do this:
>>> def make_class(with_spam=True):

... if with_spam:
... class TheClass(object):
... def dostuff(self):
... print 'Spam, spam, spam, spam!'
... else:
... class TheClass(object):
... def dostuff(self):
... print "I don't like spam!"
... return TheClass


The real power of the class statement is that you can code it this way:

class TheClass(object):
if with_spam:
def dostuff(self):
print 'Spam, spam, spam, spam!'
else:
def dostuff(self):
print "I don't like spam!"

Instead of creating two classes in separate branches of the if
statement, you can as well use the if inside the class statement. It's
perfectly valid. Of course, one still has to feed it with the
'with_spam' argument - but if 'with_spam' is a global, or if the class
statement wrapped inside a function that defines 'with_spam', it will
work just as fine.

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #8

P: n/a
Alex Martelli wrote:
Nick Coghlan <nc******@iinet.net.au> wrote:
...
Michael Spencer also posted an interesting idea recently about setting up
a view of an existing dictionary, rather than as a separate object:

class attr_view(object):
def __init__(self, data):
object.__setattr__(self, "_data", data)
def __getattr__(self, attrname):
return self._data[attrname]
def __setattr__(self, attrname, value):
self._data[attrname] = value

Wasted indirection, IMHO. A better implementation:

class attr_view(object):
def __init__(self, data):
self.__dict__ = data
Alex


Yeah, I caught your comment in the other thread. It was something I'd wondered
about, but never followed up .

And any time you want real dictionary behaviour, a quick call to "vars(x)" will
do nicely.

I think the idea definitely deserves mention as a possible implementation
strategy in the generic objects PEP, with the data argument made optional:

class namespace(object):
def __init__(self, data=None):
if data is not None:
self.__dict__ = data
# Remainder as per Bunch in the PEP. . .

Py> result = namespace()
Py> result.x = 1
Py> result.y = 2
Py> vars(result)
{'y': 2, 'x': 1}
Py> gbls = namespace(globals())
Py> gbls.result
<__main__.namespace object at 0x00B2E370>
Py> gbls.result.x
1
Py> gbls.result.y
2
Py> gbls.gbls
<__main__.namespace object at 0x00B2E410>

This does mean construction using keywords or a sequence of pairs requires an
extra call to dict() at the invocation point. However, it means that the class
can also be used to manipulate an existing dictionary, which the current PEP
version doesn't allow.

namespace(existing_dict) would mean that the namespace should manipulate the
original dictionary.

namespace() would create a new, initially empty, dict to work on.

namespace(dict(<whatever>)) would create a new, non-empty, dict based on the
standard arguments to the dictionary constructor.

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #9

P: n/a
Nick Coghlan wrote:
Steven Bethard wrote:
Yes -- help me rally behind my generic object PEP which proposes a
Bunch type (probably to be renamed) for the Python standard lib. =)


Did you see the suggestion of 'namespace' as a name?


Yup, it's in the current PEP draft. See the "Open Issues" section:
PEP: XXX
Title: Generic Object Data Type
Version: $Revision: 1.0 $
Last-Modified: $Date: 2004/11/29 16:00:00 $
Author: Steven Bethard <st************@gmail.com>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 29-Nov-2004
Python-Version: 2.5
Post-History: 29-Nov-2004
Abstract
========

This PEP proposes a standard library addition to support the simple
creation of 'generic' objects which can be given named attributes
without the need to declare a class. Such attribute-value mappings are
intended to complement the name-value mappings provided by Python's
builtin dict objects.
Motivation
==========

Python's dict objects provide a simple way of creating anonymous
name-value mappings. These mappings use the __getitem__ protocol to
access the value associated with a name, so that code generally appears
like::

mapping['name']

Occasionally, a programmer may decide that dotted-attribute style access
is more appropriate to the domain than __getitem__ style access, and
that their mapping should be accessed like::

mapping.name

Currently, if a Python programmer makes this design decision, they are
forced to declare a new class, and then build instances of this class.
When no methods are to be associated with the attribute-value mappings,
declaring a new class can be overkill. This PEP proposes adding a
simple type to the collections module of the standard library that can
be used to build such attribute-value mappings.

Providing such a type allows the Python programmer to determine which
type of mapping is most appropriate to their domain and apply this
choice with minimal effort. Some of the suggested uses include:
Returning Named Results
-----------------------

It is often appropriate for a function that returns multiple items to
give names to the different items returned. The type suggested in this
PEP provides a simple means of doing this that allows the returned
values to be accessed in the usual attribute-style access::
def f(x): ... return Bunch(double=2*x, squared=x**2)
... y = f(10)
y.double 20 y.squared 100
Representing Hierarchical Data
------------------------------

The type suggested in this PEP also allows a simple means of
representing hierarchical data that allows attribute-style access::
x = Bunch(spam=Bunch(rabbit=1, badger=[2, 3, 4]), ham='neewom')
x.spam.badger [2, 3, 4] x.ham 'neewom'
Rationale
=========

As Bunch objects are intended primarily to replace simple, data-only
classes, simple Bunch construction was a primary concern. As such,
the Bunch constructor supports creation from keyword arguments, dicts,
and sequences of (attribute, value) pairs::
Bunch(eggs=1, spam=2, ham=3) Bunch(eggs=1, ham=3, spam=2) Bunch({'eggs':1, 'spam':2, 'ham':3}) Bunch(eggs=1, ham=3, spam=2) Bunch([('eggs',1), ('spam',2), ('ham',3)]) Bunch(eggs=1, ham=3, spam=2)

To allow attribute-value mappings to be easily combined, the Bunch type
provides a update staticmethod that supports similar arguments::
bunch = Bunch(eggs=1)
Bunch.update(bunch, [('spam', 2)], ham=3)
bunch Bunch(eggs=1, ham=3, spam=2)

Note that update is available through the class, not through the
instances, to avoid the confusion that might arise if an 'update'
attribute added to a Bunch instance hid the update method.
If Bunch objects are used to represent hierarchical data, comparison of
such objects becomes a concern. For this reason, Bunch objects support
object equality which compares Bunch objects by attributes recursively::
x = Bunch(parrot=Bunch(lumberjack=True, spam=42), peng='shrub')
y = Bunch(peng='shrub', parrot=Bunch(spam=42, lumberjack=True))
z = Bunch(parrot=Bunch(lumberjack=True), peng='shrub')
x == y True x == z False
Note that support for the various mapping methods, e.g.
__(get|set|del)item__, __len__, __iter__, __contains__, items, keys,
values, etc. was intentionally omitted as these methods did not seem to
be necessary for the core uses of an attribute-value mapping. If such
methods are truly necessary for a given use case, this may suggest that
a dict object is a more appropriate type for that use.
Examples
=========

Converting an XML DOM tree into a tree of nested Bunch objects::
import xml.dom.minidom
def getbunch(element): ... result = Bunch()
... if element.attributes:
... Bunch.update(result, element.attributes.items())
... children = {}
... for child in element.childNodes:
... if child.nodeType == xml.dom.minidom.Node.TEXT_NODE:
... children.setdefault('text', []).append(
... child.nodeValue)
... else:
... children.setdefault(child.nodeName, []).append(
... getbunch(child))
... Bunch.update(result, children)
... return result
... doc = xml.dom.minidom.parseString("""\ ... <xml>
... <a attr_a="1">
... a text 1
... <b attr_b="2" />
... <b attr_b="3"> b text </b>
... a text 2
... </a>
... <c attr_c="4"> c text </c>
... </xml>""") b = getbunch(doc.documentElement)
b.a[0].b[1]

Bunch(attr_b=u'3', text=[u' b text '])

Reference Implementation
========================

The code is available as SourceForge patch 1094542 [1]_.
Open Issues
===========
What should the type be named? Some suggestions include 'Bunch',
'Record', 'Struct' and 'Namespace'.

Where should the type be placed? The current suggestion is the
collections module.
References
==========

... [1]
http://sourceforge.net/tracker/index...70&atid=305470


...
Local Variables:
mode: indented-text
indent-tabs-mode: nil
sentence-end-double-space: t
fill-column: 70
End:
Jul 18 '05 #10

P: n/a
Nick Coghlan wrote:
Alex Martelli wrote:
Nick Coghlan <nc******@iinet.net.au> wrote:
...
Michael Spencer also posted an interesting idea recently about
setting up
a view of an existing dictionary, rather than as a separate object:

class attr_view(object):
def __init__(self, data):
object.__setattr__(self, "_data", data)
def __getattr__(self, attrname):
return self._data[attrname]
def __setattr__(self, attrname, value):
self._data[attrname] = value


Wasted indirection, IMHO. A better implementation:

class attr_view(object):
def __init__(self, data):
self.__dict__ = data


I think the idea definitely deserves mention as a possible
implementation strategy in the generic objects PEP, with the data
argument made optional:


That's basically what the current implementation does (although I use
'update' instead of '='). The code is complicated because the
implementation also takes all the argument types that dicts take.

STeVe
Jul 18 '05 #11

P: n/a
Alex Martelli wrote:
Nick Coghlan <nc******@iinet.net.au> wrote:
...
Michael Spencer also posted ...


Wasted indirection, IMHO. A better implementation:

class attr_view(object):
def __init__(self, data):
self.__dict__ = data
Alex


Indeed! A complete brain-blip
Michael

Jul 18 '05 #12

P: n/a
Steven Bethard wrote:
Nick Coghlan wrote:


class attr_view(object):
def __init__(self, data):
self.__dict__ = data

I think the idea definitely deserves mention as a possible
implementation strategy in the generic objects PEP, with the data
argument made optional:

That's basically what the current implementation does (although I use
'update' instead of '='). The code is complicated because the
implementation also takes all the argument types that dicts take.

STeVe


Have you noted the similarity of bunch and types.ModuleType?

perhaps module.__init__ could take an additional keyword argument to set its
__dict__

Michael

Jul 18 '05 #13

P: n/a
Steven Bethard said unto the world upon 2005-02-05 14:05:
Nick Coghlan wrote:
Steven Bethard wrote:
Yes -- help me rally behind my generic object PEP which proposes a
Bunch type (probably to be renamed) for the Python standard lib. =)

Did you see the suggestion of 'namespace' as a name?

Yup, it's in the current PEP draft. See the "Open Issues" section:
PEP: XXX
Title: Generic Object Data Type
Version: $Revision: 1.0 $
Last-Modified: $Date: 2004/11/29 16:00:00 $
Author: Steven Bethard <st************@gmail.com>
Status: Draft
Type: Standards Track
Content-Type: text/x-rst
Created: 29-Nov-2004
Python-Version: 2.5
Post-History: 29-Nov-2004


<SNIP>
Open Issues
===========
What should the type be named? Some suggestions include 'Bunch',
'Record', 'Struct' and 'Namespace'.


A quick check of the google groups archive didn't lead me to believe
that I'm repeating old suggestions, so: how about 'Bag'?

It's has the small virtue of being short and the great virtue of
employing a good metaphor, I think. A (loose enough) bag takes
whatever shape you impose on it by the things that you stick into it.
If I understand the PEP draft aright, the idea is quite similar -- a
python object with no internal structure other than that imposed by
what the programmer decides to put into it.

(I'm just a hobbyist, so if this suggestion clashes with some well
established use of 'Bag' in CS terminology, well, never mind.)

Best to all,

Brian vdB
Jul 18 '05 #14

P: n/a
On Sat, 05 Feb 2005 12:05:13 -0700, Steven Bethard
<st************@gmail.com> wrote:
The type suggested in this PEP also allows a simple means of
representing hierarchical data that allows attribute-style access::
>>> x = Bunch(spam=Bunch(rabbit=1, badger=[2, 3, 4]), ham='neewom')
>>> x.spam.badger [2, 3, 4] >>> x.ham

'neewom'


Static nested data structures are particularly tricky to declare in
Python. Your example works, but IMHO it's rather a workaround than a
real solution. Other languages (such as Delphi) have a record type
that can be nested naturally. Nested classes in Python don't work the
same as Delphi records; on instantiaton, only the outer (parent) class
is instantiated, and the nested (children) classes stay as classes.
This can lead to subtle bugs as class attribute acesses are mixed with
instance attribute accesses with unpredictable results. I have tried
to deal with these problems on MetaTemplate, a library for
declarative-style code in Python. You can see some ideas on this page:

http://metatemplate.python-hosting.c...i/MetaTemplate

One of my goals was to model nested data structures as nested classes
in Python. My solution to the nesting problem involves some
autoinstantiation magic which breaks traditional semantics, but works
for the particular application ('practicality beats purity').

I'm interested to see where this will lead us. Other related problems
are named tuples, and ordered attribute access. I deal with the later
in MetaTemplate, but the former is out of scope for the library. In
the long term, I wish Python grows a true record type. The semantic
differences between records and classes are enough to justify it in my
opinion.

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #15

P: n/a
On Sat, 05 Feb 2005 15:59:00 -0500, Brian van den Broek
<bv****@po-box.mcgill.ca> wrote:
(I'm just a hobbyist, so if this suggestion clashes with some well
established use of 'Bag' in CS terminology, well, never mind.)


There's already a well know know use for the 'bag' name, including a
recipe in Python. A bag is an arbitrary collection of objects. It's
similar to a set. The cookbook code is at:

http://aspn.activestate.com/ASPN/Coo.../Recipe/259174

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #16

P: n/a
Carlos Ribeiro said unto the world upon 2005-02-05 16:35:
On Sat, 05 Feb 2005 15:59:00 -0500, Brian van den Broek
<bv****@po-box.mcgill.ca> wrote:
(I'm just a hobbyist, so if this suggestion clashes with some well
established use of 'Bag' in CS terminology, well, never mind.)

There's already a well know know use for the 'bag' name, including a
recipe in Python. A bag is an arbitrary collection of objects. It's
similar to a set. The cookbook code is at:

http://aspn.activestate.com/ASPN/Coo.../Recipe/259174


OK then, never mind ;-)

Thanks for the link. Best,

Brian vdB
Jul 18 '05 #17

P: n/a
Steven Bethard wrote:
Nick Coghlan wrote:
I think the idea definitely deserves mention as a possible
implementation strategy in the generic objects PEP, with the data
argument made optional:

That's basically what the current implementation does (although I use
'update' instead of '='). The code is complicated because the
implementation also takes all the argument types that dicts take.


The main difference I noticed is that by using update, any changes made via the
attribute view are not reflected in the original dict.

By assigning to __dict__ directly, you can use the attribute view either as it's
own dictionary (by not supplying one, or supplying a new one), or as a
convenient way to programmatically modify an existing one. For example, you
could use it to easily bind globals without needing the 'global' keyword:

Py> class attr_view(object):
.... def __init__(self, data):
.... self.__dict__ = data
....
Py> def f():
.... gbls = attr_view(globals())
.... gbls.x = 5
....
Py> x
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'x' is not defined
Py> f()
Py> x
5

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #18

P: n/a
Nick Coghlan wrote:
By assigning to __dict__ directly, you can use the attribute view either
as it's own dictionary (by not supplying one, or supplying a new one),
or as a convenient way to programmatically modify an existing one. For
example, you could use it to easily bind globals without needing the
'global' keyword:

Py> class attr_view(object):
... def __init__(self, data):
... self.__dict__ = data
...
Py> def f():
... gbls = attr_view(globals())
... gbls.x = 5
...
Py> x
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'x' is not defined
Py> f()
Py> x
5


Hmm... interesting. This isn't the main intended use of
Bunch/Struct/whatever, but it does seem like a useful thing to have...
I wonder if it would be worth having, say, a staticmethod of Bunch that
produced such a view, e.g.:

class Bunch(object):
...
@staticmethod
def view(data):
result = Bunch()
result.__dict__ = data
return result

Then you could write your code as something like:

gbls = Bunch.view(globals())

I'm probably gonna need more feedback though from people though to know
if this is a commonly desired use case...

Steve
Jul 18 '05 #19

P: n/a
Steven Bethard <st************@gmail.com> wrote:
Hmm... interesting. This isn't the main intended use of
Bunch/Struct/whatever, but it does seem like a useful thing to have...
I wonder if it would be worth having, say, a staticmethod of Bunch that
produced such a view, e.g.:

class Bunch(object):
...
@staticmethod
def view(data):
result = Bunch()
result.__dict__ = data
return result

Then you could write your code as something like:

gbls = Bunch.view(globals())

I'm probably gonna need more feedback though from people though to know
if this is a commonly desired use case...


Reasonably so, is my guess. Witness the dict.fromkeys classmethod -- it
gives you, on dict creation, the same kind of nice syntax sugar that
wrapping a dict in a bunch gives you for further getting and setting
(and with similar constraints: all keys must be identifiers and not
happen to clash with reserved words).

I think this ``view'' or however you call it should be a classmethod
too, for the same reason -- let someone handily subclass Bunch and still
get this creational pattern w/o extra work. Maybe a good factoring
could be something like:

class Bunch(object):

def __init__(self, *a, **k):
self.__dict__.update(*a, **k)

def getDict(self):
return self.__dict__

def setDict(self, adict):
self.__dict__ = adict

theDict = property(getDict, setDict, None,
"direct access to the instance dictionary"
)

@classmethod
def wrapDict(cls, adict, *a, **k):
result = cls.__new__(cls, *a, **k)
result.setDict(adict)
cls.__init__(result, *a, **k)
return result

I'm thinking of use cases where a subclass of Bunch might override
setDict (to do something else in addition to Bunch.setDict, e.g.
maintain some auxiliary data structure for example) -- structuring
wrapDict as a classmethod in a ``Template Method'' DP might minimize the
amount of work, and the intrusiveness, needed for the purpose. (I don't
have a real-life use case for such a subclass, but it seems to cost but
little to provide for it as a possibility anyway).

[[given the way property works, one would need extra indirectness in
getDict and setDict -- structuring THEM as Template Methods, too -- to
fully support such a subclass; but that's a well-known general issue
with property, and the cost of the extra indirection -- mostly in terms
of complication -- should probably not be borne here, it seems to me]]
Alex
Jul 18 '05 #20

P: n/a
Alex Martelli wrote:
I think this ``view'' or however you call it should be a classmethod
too, for the same reason -- let someone handily subclass Bunch and still
get this creational pattern w/o extra work. Maybe a good factoring
could be something like:

class Bunch(object):

def __init__(self, *a, **k):
self.__dict__.update(*a, **k)

def getDict(self):
return self.__dict__

def setDict(self, adict):
self.__dict__ = adict

theDict = property(getDict, setDict, None,
"direct access to the instance dictionary"
)

@classmethod
def wrapDict(cls, adict, *a, **k):
result = cls.__new__(cls, *a, **k)
result.setDict(adict)
cls.__init__(result, *a, **k)
return result

I'm thinking of use cases where a subclass of Bunch might override
setDict (to do something else in addition to Bunch.setDict, e.g.
maintain some auxiliary data structure for example) -- structuring
wrapDict as a classmethod in a ``Template Method'' DP might minimize the
amount of work, and the intrusiveness, needed for the purpose. (I don't
have a real-life use case for such a subclass, but it seems to cost but
little to provide for it as a possibility anyway).


Seems pretty reasonable -- the only thing I worry about is that
classmethods and other attributes (e.g. properties) that are accessible
from instances can lead to subtle bugs when a user accidentally
initializes a Bunch object with the attributes of the same name, e.g.:

b = Bunch(getDict=1)

where

b.getDict()

now fails with something like "TypeError: 'int' object is not callable".
(For another discussion about this problem, see [1]).

I don't know what the right solution is here... I wonder if I should
write a classmethod-style descriptor that disallows the calling of a
function from an instance? Or maybe I should just document that the
classmethods should only be called from the class? Hmm...

How do you feel about getDict and setDict also being classmethods?
Steve

[1] http://mail.python.org/pipermail/pyt...ry/051328.html
Jul 18 '05 #21

P: n/a
Steven Bethard <st************@gmail.com> wrote:
Seems pretty reasonable -- the only thing I worry about is that
classmethods and other attributes (e.g. properties) that are accessible
from instances can lead to subtle bugs when a user accidentally
initializes a Bunch object with the attributes of the same name, e.g.:

b = Bunch(getDict=1)

where

b.getDict()

now fails with something like "TypeError: 'int' object is not callable".
Well, that's the problem with confusing items and attributes in the
first place, of course -- which IS Bunch's purpose;-)
(For another discussion about this problem, see [1]).

I don't know what the right solution is here... I wonder if I should
write a classmethod-style descriptor that disallows the calling of a
function from an instance? Or maybe I should just document that the
classmethods should only be called from the class? Hmm...
Another approach is to add a few "reserved words" to the ones Python
itself would reject in the initialization. Just you cannot do:

b = Bunch(continue=23)

you may choose to forbid using getDict=42 - if you do that you probably
want to forbid any magicname too, since e.g.

b = Bunch(__dict__=99)

can't work ``right'' no matter what, while setting e.g. __deepcopy__
similarly might confuse any copy.deepcopy(b), etc, etc.
How do you feel about getDict and setDict also being classmethods?


Uh? I want to get or set the dict of a specific instance -- not those
of the whole class. How would you design them as classmethods...?
Alex
Jul 18 '05 #22

P: n/a
Alex Martelli wrote:
Steven Bethard <st************@gmail.com> wrote:
I don't know what the right solution is here... I wonder if I should
write a classmethod-style descriptor that disallows the calling of a
function from an instance? Or maybe I should just document that the
classmethods should only be called from the class? Hmm...

Another approach is to add a few "reserved words" to the ones Python
itself would reject in the initialization. Just you cannot do:

b = Bunch(continue=23)

you may choose to forbid using getDict=42 - if you do that you probably
want to forbid any magicname too, since e.g.

b = Bunch(__dict__=99)

can't work ``right'' no matter what, while setting e.g. __deepcopy__
similarly might confuse any copy.deepcopy(b), etc, etc.


Yeah, I thought about this. I certainly don't have any problem with
disallowing magic names. For other names, I'm less certain...
How do you feel about getDict and setDict also being classmethods?


Uh? I want to get or set the dict of a specific instance -- not those
of the whole class. How would you design them as classmethods...?


The classmethod would have to be called with an instance, e.g.:

class Bunch(object):
@classmethod
def getDict(cls, self):
return self.__dict__

@classmethod
def setDict(cls, self, dct):
self.__dict__ = dct

Of course, these could be staticmethods instead since they don't need
the class, but the point is that you should be calling them like:

adict = Bunch.getDict(bunch)

or

Bunch.setDict(bunch, adict)

The complications with attribute hiding is one of main reasons I've
tried to minimize the number of methods associated with Bunch...

Steve
Jul 18 '05 #23

P: n/a
Brian van den Broek <bv****@po-box.mcgill.ca> wrote:
...
(I'm just a hobbyist, so if this suggestion clashes with some well
established use of 'Bag' in CS terminology, well, never mind.)


Yep: a Bag is a more common and neater name for a "multiset" -- a
set-like container which holds each item ``a certain number of times''
(you can alternatively see it as a mapping from items to counts of
number of times the item is held).
Alex
Jul 18 '05 #24

P: n/a
Steven Bethard wrote:
The complications with attribute hiding is one of main reasons I've
tried to minimize the number of methods associated with Bunch...


in order for bunches to be fully useful in general, open contexts, I think that
number of methods should be exactly zero (at least without leading
underscores). Otherwise, as soon as someone loads a config file into a bunch
and they assign randomname_which_you'd_used, the whole thing breaks.

I see two ways to implement additional (needed) functionality into bunches:

1. The class/staticmethod approach. This has clean syntax, though it may make
inheritance issues tricky, I'm not too sure.

2. To break with pythonic convention a bit, and make the public API of Bunch
consist of methods which all start with a leading _. You can even (via
__setattr__ or metaclass tricks) block assignment to these, and state up front
that Bunches are meant to hold public data only in attributes starting with a
letter. I think that would be a reasonable compromise, allowing you to do:

b = Bunch()
b.update = 'yes'
b._update(somedict)
b.copy = 'no'
c = b._copy()

# BUT:
c._update = 'no' ## an exception is raised

etc.

It's not very pretty, and it does break with pythonic convention. But a Bunch
class which simultaneously provides certain non-trivial functionality
(otherwise the usual 'class Bunch:pass' idiom would be enough), while allowing
users to store arbitrarily named attributes in it, is inevitably going to need
to play namespace tricks somewhere.

FWIW, I personally could live with #2 as an acceptable compromise.

Cheers,

f

Jul 18 '05 #25

P: n/a
Alex Martelli wrote:
Steven Bethard <st************@gmail.com> wrote:

Hmm... interesting. This isn't the main intended use of
Bunch/Struct/whatever, but it does seem like a useful thing to have...
I wonder if it would be worth having, say, a staticmethod of Bunch that
produced such a view, e.g.:

class Bunch(object):
...
@staticmethod
def view(data):
result = Bunch()
result.__dict__ = data
return result

Then you could write your code as something like:

gbls = Bunch.view(globals())

I'm probably gonna need more feedback though from people though to know
if this is a commonly desired use case...

Reasonably so, is my guess. Witness the dict.fromkeys classmethod -- it
gives you, on dict creation, the same kind of nice syntax sugar that
wrapping a dict in a bunch gives you for further getting and setting
(and with similar constraints: all keys must be identifiers and not
happen to clash with reserved words).

I think this ``view'' or however you call it should be a classmethod
too, for the same reason -- let someone handily subclass Bunch and still
get this creational pattern w/o extra work. Maybe a good factoring
could be something like:

class Bunch(object):

def __init__(self, *a, **k):
self.__dict__.update(*a, **k)

def getDict(self):
return self.__dict__

def setDict(self, adict):
self.__dict__ = adict

theDict = property(getDict, setDict, None,
"direct access to the instance dictionary"
)

@classmethod
def wrapDict(cls, adict, *a, **k):
result = cls.__new__(cls, *a, **k)
result.setDict(adict)
cls.__init__(result, *a, **k)
return result

I'm thinking of use cases where a subclass of Bunch might override
setDict (to do something else in addition to Bunch.setDict, e.g.
maintain some auxiliary data structure for example) -- structuring
wrapDict as a classmethod in a ``Template Method'' DP might minimize the
amount of work, and the intrusiveness, needed for the purpose. (I don't
have a real-life use case for such a subclass, but it seems to cost but
little to provide for it as a possibility anyway).

[[given the way property works, one would need extra indirectness in
getDict and setDict -- structuring THEM as Template Methods, too -- to
fully support such a subclass; but that's a well-known general issue
with property, and the cost of the extra indirection -- mostly in terms
of complication -- should probably not be borne here, it seems to me]]
Alex


Steven et al

I like the idea of making the 'bunch' concept a little more standard.
I also like the suggestion Nick Coghlan cited (not sure who suggested the term
in this context) of calling this 'namespace' in part because it can lead to
easily-explained semantics.

ISTM that 'bunch' or 'namespace' is in effect the complement of vars i.e., while
vars(object) => object.__dict__, namespace(somedict) gives an object whose
__dict__ is somedict.

Looked at this way, namespace (or bunch) is a minimal implementation of an
object that implements the hasattr(object,__dict__) protocol. The effect of the
class is to make operations on __dict__ simpler. namespace instances can be
compared with any other object that has a __dict__. This differs from the PEP
reference implementation which compares only with other bunch instances. In
practice, comparisons with module and class may be useful.

The class interface implements the protocol and little else.

For 'bunch' applications, namespace can be initialized or updated with keyword
args (just like a dict)
i.e.,
bunch = namespace({"a":1,"b":2}) can also be written as bunch = namespace(a=1,b=2)
For dict-wrapping applications: wrappeddict = namespace(bigdict)

but, unlike the PEP implmentation, this sets wrappeddict.__dict__ = bigdict

I think that this interface allows for either use case, without introducing
'fromdict' classmethod.

Some dict-operations e.g., __copy__ might carry over to the namespace class

Michael
An implementation follows:
# An alternative implementation of Steven Bethard's PEP XXX 'bunch' with
# slightly different interface and semantics:

class namespace(object):
"""
namespace(somedict) => object (with object.__dict__ = somedict)
NB, complement of vars: vars(object) => object.__dict__

namespace objects provide attribute access to their __dict__

In general, operations on namespace equate to the operations
on namespace.__dict__

"""

def __init__(self, E = None, **F):
"""__init__([namespace|dict], **kwds) -> None"""
if isinstance(E, dict):
self.__dict__ = E
elif hasattr(E, "__dict__"):
self.__dict__ = E.__dict__
self.__dict__.update(**F)

# define only magic methods to limit pollution
def __update__(self, E = None, **F):
"""update([namespace|dict], **kwds) -> None
equivalent to self.__dict__.update
with the addition of namespace as an acceptable operand"""
if hasattr(other, "keys"):
self.__dict__.update(E)
elif hasattr(other, "__dict__"):
self.__dict__.update(E.__dict__)
self.__dict__.update(**F)
def __repr__(self):
return "namespace(%s)" % repr(self.__dict__)

# Possible additional methods: (All are conveniences for dict operations
# An operation on namespace translates operation on namespace.__dict__
# So A op B => A.__dict__ op B.__dict__)

def __copy__(self):
return namespace(self.__dict__.__copy__)
def __eq__(self, other):
return self.__dict__ == other.__dict__

def __contains__(self, key):
return self.__dict__.__contains__(key)
def __iter__(self):
return iter(self.__dict__)
# etc...

Jul 18 '05 #26

P: n/a
Michael Spencer wrote:
ISTM that 'bunch' or 'namespace' is in effect the complement of vars
i.e., while vars(object) => object.__dict__, namespace(somedict) gives
an object whose __dict__ is somedict.
Yeah, I kinda liked this application too, and I think the symmetry would
be nice.
Looked at this way, namespace (or bunch) is a minimal implementation of
an object that implements the hasattr(object,__dict__) protocol. The
effect of the class is to make operations on __dict__ simpler.
namespace instances can be compared with any other object that has a
__dict__. This differs from the PEP reference implementation which
compares only with other bunch instances.


Yeah, I wanted to support this, but I couldn't decide how to arbitrate
things in update -- if a dict has a __dict__ attribute, do I update the
Namespace object with the dict or the __dict__? That is, what should I
do in the following case:

py> class xdict(dict):
.... pass
....
py> d = xdict(a=1, b=2)
py> d.x = 1
py> d
{'a': 1, 'b': 2}
py> d.__dict__
{'x': 1}
py> Namespace(d)

The dict d has both the items of a dict and the attributes of a
__dict__. Which one gets assigned to the __dict__ of the Namespace? Do
I do:

self.__dict__ = d

or do I do:

self.__dict__ = d.__dict__

It was because these seem like two separate cases that I wanted two
different functions for them (__init__ and, say, dictview)...

Steve
Jul 18 '05 #27

P: n/a
Steven Bethard wrote:
It was because these seem like two separate cases that I wanted two
different functions for them (__init__ and, say, dictview)...


The other issue is that a namespace *is* a mutable object, so the default
behaviour should be to make a copy (yeah, I know, I'm contradicting myself - I
only just thought of this issue). So an alternate constructor is definitely the
way to go.

I think Michael's implementation also fell into a trap whereby 'E' couldn't be
used as an attribute name. The version below tries to avoid this (using
magic-style naming for the other args in the methods which accept keyword
dictionaries).

To limit the special casing in update, I've switched to only using __dict__ for
the specific case of instances of namespace (otherwise the semantics are too
hard to explain). This is to allow easy copying of an existing namespace - for
anything else, invoking vars() is easy enough.

And I was reading Carlos's page on MetaTemplate, so I threw in an extra class
"record" which inherits from namespace and allows complex data structures to be
defined via class syntax (see the record.__init__ docstring for details). That
bit's entirely optional, but I thought it was neat.

Finally, I've just used normal names for the functions. I think the issue of
function shadowing is best handled by recommending that all of the functions be
called using the class explicitly - this works just as well for instance methods
as it does for class or static methods.

Cheers,
Nick.

+++++++++++++++++++++++++++++++++++++++++++++

from types import ClassType

class namespace(object):
"""
namespace([namespace|dict]) => object

namespace objects provide attribute access to their __dict__
Complement of vars: vars(object) => object.__dict__

Non-magic methods should generally be invoked via the class to
avoid inadvertent shadowing by instance attributes

Using attribute names that look like magic attributes is not
prohibited but can lead to surprising behaviour.

In general, operations on namespace equate to the operations
on namespace.__dict__
"""

def __init__(__self__, __orig__ = None, **__kwds__):
"""__init__([namespace|dict], **kwds) -> None"""
type(__self__).update(__self__, __orig__, **__kwds__)

@classmethod
def view(cls, orig):
"""namespace.view(dict) -> namespace

Creates a namespace that is a view of the original
dictionary. Allows modification of an existing
dictionary via namespace syntax"""
new = cls()
new.__dict__ = orig
return new

def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self.__dict__))

# Recommend calling non-magic methods via class form to
# avoid problems with inadvertent attribute shadowing
def _checked_update(self, other):
try:
self.__dict__.update(other)
except (TypeError):
raise TypeError("Namespace update requires mapping "
"keyed with valid Python identifiers")

def update(__self__, __other__ = None, **__kwds__):
"""type(self).update(self, [namespace|dict], **kwds) -> None
equivalent to self.__dict__.update"""
# Handle direct updates
if __other__ is not None:
if isinstance(__other__, namespace):
type(__self__)._checked_update(__self__, __other__.__dict__)
else:
type(__self__)._checked_update(__self__, __other__)
# Handle keyword updates
if __kwds__ is not None:
type(__self__)._checked_update(__self__, __kwds__)
class record(namespace):
def __init__(self, definition=None):
"""record([definition]) -> record

Constructs a namespace based on the given class definition
Nested classes are created as sub-records
Fields starting with an underscore are ignored
If definition is not given, uses current class
This is handy with subclasses
Using subclasses this way has the advantage that the
created records are also instances of the subclass.

For example:
Py> from ns import namespace, record
Py> class Record:
... a = 1
... b = ""
... class SubRecord:
... c = 3
...
Py> x = record(Record)
Py> x
record({'a': 1, 'b': '', 'SubRecord': record({'c': 3})})
Py> class Record2(record):
... a = 1
... b = ""
... class SubRecord2(record):
... c =3
...
Py> x = Record2()
Py> x
Record2({'a': 1, 'b': '', 'SubRecord2': SubRecord2({'c': 3})})
"""
cls = type(self)
if definition is None:
definition = cls
cls.update_from_definition(self, definition)

def update_from_definition(self, definition):
"""type(self).update_from_definition(self, definition) -> None

Updates the namespace based on the given class definition
Nested classes are created as sub-records
Fields starting with an underscore are ignored"""
try:
for field, default in definition.__dict__.iteritems():
if field.startswith("_"):
continue
if (isinstance(default, (type, ClassType))
and issubclass(default, record)):
# It's a record, so make it an instance of itself
self.__dict__[field] = default()
else:
try:
# If we can make a record of it, do so
self.__dict__[field] = record(default)
except TypeError:
# Throw it in a standard field
self.__dict__[field] = default
except AttributeError:
raise TypeError("Namespace definition must have __dict__ attribute")

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #28

P: n/a
Alex Martelli said unto the world upon 2005-02-06 18:06:
Brian van den Broek <bv****@po-box.mcgill.ca> wrote:
...
(I'm just a hobbyist, so if this suggestion clashes with some well
established use of 'Bag' in CS terminology, well, never mind.)

Yep: a Bag is a more common and neater name for a "multiset" -- a
set-like container which holds each item ``a certain number of times''
(you can alternatively see it as a mapping from items to counts of
number of times the item is held).
Alex


Thanks for that info. I've yet to check the link to the Bag cookbook
recipe that Carlos Ribeiro posted for me
<http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/259174>, but
now I definitely will! (When I first learned of Python's set type, I
was disappointed there wasn't also a multi-set type.)

Thanks and best,

Brian vdB

Jul 18 '05 #29

P: n/a
Nick Coghlan wrote:
Finally, I've just used normal names for the functions. I think the
issue of function shadowing is best handled by recommending that all of
the functions be called using the class explicitly - this works just as
well for instance methods as it does for class or static methods.


I wonder if it would be worth adding a descriptor that gives a warning
for usage from instances, e.g.:

py> import new
py> import warnings
py> class InstanceWarner(object):
.... def __init__(self, func):
.... self.func = func
.... def __get__(self, obj, type=None):
.... if obj is None:
.... return self.func
.... else:
.... warnings.warn('methods of this type should not be '
.... 'invoked from instances')
.... return new.instancemethod(self.func, obj, type)
....
py> class Bunch(object):
.... @InstanceWarner
.... def update(self):
.... print 'updating', self
....
py> Bunch.update(Bunch())
updating <__main__.Bunch object at 0x01152830>
py> Bunch().update()
__main__:8: UserWarning: methods of this type should not be invoked from
instances
updating <__main__.Bunch object at 0x011527D0>

Steve
Jul 18 '05 #30

P: n/a
Nick Coghlan wrote:
Steven Bethard wrote:
It was because these seem like two separate cases that I wanted two
different functions for them (__init__ and, say, dictview)...
I see this, but I think it weakens the case for a single implementation, given
that each implementation is essentially one method.
The other issue is that a namespace *is* a mutable object, so the
default behaviour should be to make a copy
I don't follow this argument. Why does mutability demand copy? Given that
somedict here is either a throwaway (in the classic bunch application ) or a
dict that must be updated (the wrap-dict case), copying doesn't make much sense
to me.

OTOH, dict.__init__(dict) copies. hmmmm....

I think Michael's implementation also fell into a trap whereby 'E'
couldn't be used as an attribute name. The version below tries to avoid
this (using magic-style naming for the other args in the methods which
accept keyword dictionaries).
You're right - I hadn't considered that. In case it wasn't obvious, I was
matching the argspec of dict. Your solution avoids the problem.
To limit the special casing in update, I've switched to only using
__dict__ for the specific case of instances of namespace
That seems a pity to me.
(otherwise the semantics are too hard to explain). This is to allow easy copying of an
existing namespace -
Can't this be spelled namespace(somenamespace).__copy__()?
for anything else, invoking vars() is easy enough.
If there is potential for confusion, I'd be tempted to disallow namespaces as an
argument to update/__update__

We could use __add__, instead for combining namespaces

And I was reading Carlos's page on MetaTemplate, so I threw in an extra
class "record" which inherits from namespace and allows complex data
structures to be defined via class syntax (see the record.__init__
docstring for details). That bit's entirely optional, but I thought it
was neat.
Good idea. The implementation ought to be tested against several plausible
specializations.
Finally, I've just used normal names for the functions. I think the
issue of function shadowing is best handled by recommending that all of
the functions be called using the class explicitly - this works just as
well for instance methods as it does for class or static methods.
I don't like the sound of that. The whole point here - whether as Steven's nice
straightforward bunch, as originally conceived, or the other cases you and I and
others have been 'cluttering' the discussion with ;-) is convenience, and
readability. If there are hoops to jump through to use it, then the benefit is
quickly reduced to zero.

Regards

Michael

Cheers,
Nick.

+++++++++++++++++++++++++++++++++++++++++++++

from types import ClassType

class namespace(object):
"""
namespace([namespace|dict]) => object

namespace objects provide attribute access to their __dict__
Complement of vars: vars(object) => object.__dict__

Non-magic methods should generally be invoked via the class to
avoid inadvertent shadowing by instance attributes

Using attribute names that look like magic attributes is not
prohibited but can lead to surprising behaviour.

In general, operations on namespace equate to the operations
on namespace.__dict__
"""

def __init__(__self__, __orig__ = None, **__kwds__):
"""__init__([namespace|dict], **kwds) -> None"""
type(__self__).update(__self__, __orig__, **__kwds__)

@classmethod
def view(cls, orig):
"""namespace.view(dict) -> namespace

Creates a namespace that is a view of the original
dictionary. Allows modification of an existing
dictionary via namespace syntax"""
new = cls()
new.__dict__ = orig
return new

def __repr__(self):
return "%s(%s)" % (self.__class__.__name__, repr(self.__dict__))

# Recommend calling non-magic methods via class form to
# avoid problems with inadvertent attribute shadowing
def _checked_update(self, other):
try:
self.__dict__.update(other)
except (TypeError):
raise TypeError("Namespace update requires mapping "
"keyed with valid Python identifiers")

def update(__self__, __other__ = None, **__kwds__):
"""type(self).update(self, [namespace|dict], **kwds) -> None
equivalent to self.__dict__.update"""
# Handle direct updates
if __other__ is not None:
if isinstance(__other__, namespace):
type(__self__)._checked_update(__self__,
__other__.__dict__)
else:
type(__self__)._checked_update(__self__, __other__)
# Handle keyword updates
if __kwds__ is not None:
type(__self__)._checked_update(__self__, __kwds__)
class record(namespace):
def __init__(self, definition=None):
"""record([definition]) -> record

Constructs a namespace based on the given class definition
Nested classes are created as sub-records
Fields starting with an underscore are ignored
If definition is not given, uses current class
This is handy with subclasses
Using subclasses this way has the advantage that the
created records are also instances of the subclass.

For example:
Py> from ns import namespace, record
Py> class Record:
... a = 1
... b = ""
... class SubRecord:
... c = 3
...
Py> x = record(Record)
Py> x
record({'a': 1, 'b': '', 'SubRecord': record({'c': 3})})
Py> class Record2(record):
... a = 1
... b = ""
... class SubRecord2(record):
... c =3
...
Py> x = Record2()
Py> x
Record2({'a': 1, 'b': '', 'SubRecord2': SubRecord2({'c': 3})})
"""
cls = type(self)
if definition is None:
definition = cls
cls.update_from_definition(self, definition)

def update_from_definition(self, definition):
"""type(self).update_from_definition(self, definition) -> None

Updates the namespace based on the given class definition
Nested classes are created as sub-records
Fields starting with an underscore are ignored"""
try:
for field, default in definition.__dict__.iteritems():
if field.startswith("_"):
continue
if (isinstance(default, (type, ClassType))
and issubclass(default, record)):
# It's a record, so make it an instance of itself
self.__dict__[field] = default()
else:
try:
# If we can make a record of it, do so
self.__dict__[field] = record(default)
except TypeError:
# Throw it in a standard field
self.__dict__[field] = default
except AttributeError:
raise TypeError("Namespace definition must have __dict__
attribute")


Jul 18 '05 #31

P: n/a
Michael Spencer wrote:
Nick Coghlan wrote:
Steven Bethard wrote:
It was because these seem like two separate cases that I wanted two
different functions for them (__init__ and, say, dictview)...
I see this, but I think it weakens the case for a single implementation,
given that each implementation is essentially one method.
Do you mean there should be a separate Namespace and Bunch class? Or do
you mean that an implementation with only a single method is less useful?

If the former, then you either have to repeat the methods __repr__,
__eq__ and update for both Namespace and Bunch, or one of Namespace and
Bunch can't be __repr__'d, __eq__'d or updated.

If the latter (setting aside the fact that the implementation provides 4
methods, not 1), I would argue that even if an implementation is only
one method, if enough users are currently writing their own version,
adding such an implementation to the stdlib is still a net benefit.
I think Michael's implementation also fell into a trap whereby 'E'
couldn't be used as an attribute name. The version below tries to
avoid this (using magic-style naming for the other args in the methods
which accept keyword dictionaries).


You're right - I hadn't considered that. In case it wasn't obvious, I
was matching the argspec of dict. Your solution avoids the problem.


Another way to avoid the problem is to use *args, like the current Bunch
implementation does:

def update(*args, **kwargs):
"""bunch.update([bunch|dict|seq,] **kwargs) -> None

Updates the Bunch object's attributes from (if
provided) either another Bunch object's attributes, a
dictionary, or a sequence of (name, value) pairs, then from
the name=value pairs in the keyword argument list.
"""
if not 1 <= len(args) <= 2:
raise TypeError('expected 1 or 2 arguments, got %i' %
len(args))
self = args[0]
if len(args) == 2:
other = args[1]
if isinstance(other, Bunch):
other = other.__dict__
try:
self.__dict__.update(other)
except (TypeError, ValueError):
raise TypeError('cannot update Bunch with %s' %
type(other).__name__)
self.__dict__.update(kwargs)

This even allows you to use the keywords __self__ and __orig__ if you're
sick enough to want to. It's slightly more work, but I prefer it
because it's more general.
To limit the special casing in update, I've switched to only using
__dict__ for the specific case of instances of namespace


That seems a pity to me.


Is it that much worse to require the following code:

Namespace.update(namespace, obj.__dict__)

or:

namespace.udpate(obj.__dict__)

if you really want to update a Namespace object with the attributes of a
non-Namespace object?

For that matter, do you have a use-case for where this would be useful?
I definitely see the view-of-a-dict example, but I don't see the
view-of-an-object example since an object already has dotted-attribute
style access...
This is to allow easy copying of an existing namespace -


Can't this be spelled namespace(somenamespace).__copy__()?


I'd prefer to be consistent with dict, list, set, deque, etc. all of
which use their constructor for copying.
We could use __add__, instead for combining namespaces


I don't think this is a good idea. For the same reasons that dicts
don't have an __add__ (how should attributes with different values be
combined?), I don't think Bunch/Namespace should have an __add__.

Steve
Jul 18 '05 #32

P: n/a
On Mon, 07 Feb 2005 11:50:53 -0700, Steven Bethard
<st************@gmail.com> wrote:
Michael Spencer wrote:
We could use __add__, instead for combining namespaces


I don't think this is a good idea. For the same reasons that dicts
don't have an __add__ (how should attributes with different values be
combined?), I don't think Bunch/Namespace should have an __add__.


For entirely unrelated reasons I did it for a bunch-like class of
mine, and called it 'merge'. For this particular application it was a
better name than update and append, but that's IMHO.

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #33

P: n/a
Carlos Ribeiro wrote:
On Mon, 07 Feb 2005 11:50:53 -0700, Steven Bethard
<st************@gmail.com> wrote:
Michael Spencer wrote:
We could use __add__, instead for combining namespaces


I don't think this is a good idea. For the same reasons that dicts
don't have an __add__ (how should attributes with different values be
combined?), I don't think Bunch/Namespace should have an __add__.


For entirely unrelated reasons I did it for a bunch-like class of
mine, and called it 'merge'. For this particular application it was a
better name than update and append, but that's IMHO.


Did 'merge' have the same semantics as the 'update' being discussed?
That is, did it modify the first 'bunch'? Or did it create a new
'bunch'? To me, 'merge' sounds more like the second...

Steve
Jul 18 '05 #34

P: n/a
On Mon, 07 Feb 2005 13:31:20 -0700, Steven Bethard
<st************@gmail.com> wrote:
Carlos Ribeiro wrote:
On Mon, 07 Feb 2005 11:50:53 -0700, Steven Bethard
<st************@gmail.com> wrote:
Michael Spencer wrote:

We could use __add__, instead for combining namespaces

I don't think this is a good idea. For the same reasons that dicts
don't have an __add__ (how should attributes with different values be
combined?), I don't think Bunch/Namespace should have an __add__.


For entirely unrelated reasons I did it for a bunch-like class of
mine, and called it 'merge'. For this particular application it was a
better name than update and append, but that's IMHO.


Did 'merge' have the same semantics as the 'update' being discussed?
That is, did it modify the first 'bunch'? Or did it create a new
'bunch'? To me, 'merge' sounds more like the second...


In my particular example it was more like the second, but it doesn't
apply exactly because the goal was a little bit different; I
implemented it to merge two configuration dictionaries, one being the
'base' (with default values) and the other one with values to
overrride the base values. Anyway, it was just a suggestion; and while
I don't think that merge really implies one behavior over the other,
having it as a constructor does make sense...

--
Carlos Ribeiro
Consultoria em Projetos
blog: http://rascunhosrotos.blogspot.com
blog: http://pythonnotes.blogspot.com
mail: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #35

P: n/a
Steven Bethard wrote:
Do you mean there should be a separate Namespace and Bunch class? Or do
you mean that an implementation with only a single method is less useful?
The former.
If the former, then you either have to repeat the methods __repr__,
__eq__ and update for both Namespace and Bunch, or one of Namespace and
Bunch can't be __repr__'d, __eq__'d or updated.
I see no problem in repeating the methods, or inheriting the implementation.
However, if namespace and bunch are actually different concepts (one with
reference semantics, the other with copy), then __repr__ at least would need to
be specialized, to highlight the difference.

So, on balance, if copy semantics are important to bunch uses, and references
for namespace (though Nick changed his mind on this, and I don't yet know why) I
think they would be better as two small implementations. I remain unsure about
why you need or want copying, aside from matching the behavior of the builtins.

If the latter (setting aside the fact that the implementation provides 4
methods, not 1), I would argue that even if an implementation is only
one method, if enough users are currently writing their own version,
adding such an implementation to the stdlib is still a net benefit.
Yes, I agree with this: I was not picking on the class size ;-)

....
Another way to avoid the problem is to use *args, like the current Bunch
implementation does:

def update(*args, **kwargs):
"""bunch.update([bunch|dict|seq,] **kwargs) -> None
Sure - nice trick to avoid shadowing self too

.... Is it that much worse to require the following code:

Namespace.update(namespace, obj.__dict__)
or:
namespace.udpate(obj.__dict__)

if you really want to update a Namespace object with the attributes of a
non-Namespace object?
No problem at all - just a question of what the class is optimized for, and
making the interface as convenient as possible, given the use case. I agree
that for straight attribute access to a dictionary, your update interface is
clearly superior.

For that matter, do you have a use-case for where this would be useful?
I definitely see the view-of-a-dict example, but I don't see the
view-of-an-object example since an object already has dotted-attribute
style access...

Yes, I have various cases in mind relating to argument-passing, dispatching,
interface-checking and class composition. Here the class becomes useful if it
grows some namespace-specific semantics.

For example, I could write something like:
namespace(obj1) >= namespace(obj2) to mean obj1 has at least the attributes of obj2

implemented like:

def __ge__(self, other):
for attrname in other.__dict__.keys():
if not attrname in self.__dict__:
return False
return True

I realize that interfaces may be addressed formally by a current PEP, but, even
if they are, this "cheap and cheerful" approach appeals to me for duck-typing.
However, as I think more about this, I realize that I am stretching your concept
past its breaking point, and that whatever the merits of this approach, it's not
helping you with bunch. Thanks for knocking the ideas around with me.

Cheers

Michael

Jul 18 '05 #36

P: n/a
Michael Spencer wrote:
I see no problem in repeating the methods, or inheriting the
implementation. However, if namespace and bunch are actually different
concepts (one with reference semantics, the other with copy), then
__repr__ at least would need to be specialized, to highlight the
difference.
Yeah, I could certainly see them being separate... Of course, someone
else will have to write the PEP for Namespace then. ;)
def __ge__(self, other):
for attrname in other.__dict__.keys():
if not attrname in self.__dict__:
return False
return True

I realize that interfaces may be addressed formally by a current PEP,
but, even if they are, this "cheap and cheerful" approach appeals to me
for duck-typing.

However, as I think more about this, I realize that I am stretching your
concept past its breaking point, and that whatever the merits of this
approach, it's not helping you with bunch. Thanks for knocking the
ideas around with me.


My pleasure. It's good to talk some use-cases, and make sure I cover as
much as is feasible in the PEP. I think __ge__ is probably too far out
from the original intentions, but I'll make sure to write
Bunch/Namespace to be as inheritance-friendly as possible so that adding
such behavior by inheriting from Bunch/Namespace should be simple.

Thanks for all your comments!

Steve
Jul 18 '05 #37

P: n/a
Steven Bethard wrote:
I wonder if it would be worth adding a descriptor that gives a warning
for usage from instances, e.g.:


Thinking about it some more, I realised that a class method approach means that
'type(self).method(self,...)' still works as a way to spell the call in a
polymorphism friendly way.

And if we're going to have to spell the call that way *anyway*. . .

So maybe it does make sense to simply say that all non-magic Bunch/namespace
operations are implemented as class methods (and most magic methods are
effectively treated as class methods when it comes to looking them).

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #38

P: n/a
Michael Spencer wrote:
Nick Coghlan wrote:
The other issue is that a namespace *is* a mutable object, so the
default behaviour should be to make a copy
I don't follow this argument. Why does mutability demand copy? Given
that somedict here is either a throwaway (in the classic bunch
application ) or a dict that must be updated (the wrap-dict case),
copying doesn't make much sense to me.

OTOH, dict.__init__(dict) copies. hmmmm....


As you noticed, it's a precedent from the other builtins and objects in the
standard library. The mutable ones (dict, list, set, etc) all make a copy of
whatever you pass in.
This is to allow easy copying of
an existing namespace -


Can't this be spelled namespace(somenamespace).__copy__()?


Again, as Steven mentioned, this is based on precedent from other objects in the
interpreter. To get your own copy of a mutable type, you invoke the constructor
with the original as the sole argument.
> for anything else, invoking vars() is easy enough.


If there is potential for confusion, I'd be tempted to disallow
namespaces as an argument to update/__update__


Limiting confusion is why I decided to restrict the special-case of querying the
__dict__ to instances of namespace. Again, as Steven pointed out, the semantics
get screwed up when the object supplied is usable as a dictionary, but also has
a __dict__ attribute.

For a namespace, the special case means that namespace(ns_obj) and
namespace(vars(ns_obj)) have the same result. Just don't go creating a namespace
subclass which provides a direct mapping interface to anything other than it's
own __dict__ and expect to affect namespaces created using the normal
constructor. I figure that limitation is obscure enough that we can live with it :)

For an arbitrary object, you can poke around in its __dict__ by doing:
namespace.view(vars(obj))
We could use __add__, instead for combining namespaces
Update already let's us combine namespaces. To create a new object that merges
two namespaces do:
namespace.update(namespace(ns_1), ns_2)
Good idea. The implementation ought to be tested against several
plausible specializations.
One thing I'm going to drop is the ability to use an arbitrary class as a
subrecord. I realised it screws up storage of classes and class instances which
have a __dict__ attribute.

Instead, I'll change it so that the optional argument allows you to set some of
the attributes.
I don't like the sound of that. The whole point here - whether as
Steven's nice straightforward bunch, as originally conceived, or the
other cases you and I and others have been 'cluttering' the discussion
with ;-) is convenience, and readability. If there are hoops to jump
through to use it, then the benefit is quickly reduced to zero.


Yes, once I realised that the polymorphism friendly 'type(self).update(self,
other)' works with a classmethod, I realised it made sense to go with Steven's
classmethod approach.

I'll also revert to his *args based solution to the keyword argument problem, too.

Time to go play cricket, so I won't actually be posting any of the above changes
tonight :)

Cheers,
Nick.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #39

P: n/a
Nick Coghlan <nc******@iinet.net.au> wrote:
We could use __add__, instead for combining namespaces


Update already let's us combine namespaces. To create a new object that merges
two namespaces do:
namespace.update(namespace(ns_1), ns_2)


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).
Alex
Jul 18 '05 #40

P: n/a
On Tue, 8 Feb 2005 12:01:23 +0100, Alex Martelli <al*****@yahoo.com> wrote:
Nick Coghlan <nc******@iinet.net.au> wrote:
We could use __add__, instead for combining namespaces


Update already let's us combine namespaces. To create a new object that merges
two namespaces do:
namespace.update(namespace(ns_1), ns_2)


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: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #41

P: n/a
Alex Martelli wrote:
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.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #42

P: n/a
On Wed, 09 Feb 2005 21:56:54 +1000, Nick Coghlan <nc******@iinet.net.au> wrote:
Alex Martelli wrote:
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'.


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: ca********@gmail.com
mail: ca********@yahoo.com
Jul 18 '05 #43

P: n/a
Nick Coghlan <nc******@iinet.net.au> wrote:
Alex Martelli wrote:
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?


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
Jul 18 '05 #44

P: n/a
Alex Martelli wrote:
Nick Coghlan <nc******@iinet.net.au> wrote:

We could use __add__, instead for combining namespaces


Update already let's us combine namespaces. To create a new object that merges
two namespaces do:
namespace.update(namespace(ns_1), ns_2)

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
Jul 18 '05 #45

P: n/a
Steven Bethard <st************@gmail.com> wrote:
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
Jul 18 '05 #46

P: n/a
Alex Martelli wrote:
Steven Bethard <st************@gmail.com> wrote:
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.


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
Jul 18 '05 #47

P: n/a
Steven Bethard <st************@gmail.com> wrote:
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:
b.x = 15
print b.x 15 del b.x
print b.x 23 del b.x 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:
class B(object): .... x = 23
.... b=B()


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
Jul 18 '05 #48

P: n/a
Alex Martelli wrote:
Nick Coghlan <nc******@iinet.net.au> wrote:
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.


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.

--
Nick Coghlan | nc******@email.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net
Jul 18 '05 #49

P: n/a
Alex Martelli wrote:
Steven Bethard <st************@gmail.com> wrote:
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.


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

Steve
Jul 18 '05 #50

This discussion thread is closed

Replies have been disabled for this discussion.