Bengt said:
Or worse, the dictionary would become not functional depending on what
methods were masked.
And this approach reverses that, The dict values will be masked by the
methods, so the values can't effect the dictionary methods. But those
specific values are only retrievable with the standard dictionary notation.
class namespace(dict):
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
__delattr__ = dict.__delitem__
n = namespace()
n.__getattr__ = 'yes' # doesn't mask __getattr__ method.
print n['__getattr__'] -> 'yes'
The value is there and __getattr__() still works. But n.__getattr__
returns the method not the value.
So is there a way to keep the functionality without loosing the methods?
BTW, I agree with Steven concerning data structures. This really isn't
a substitute for a data structure. Many keys will not work with this.
n.my name = 'Ron'
n.(1,2) = 25
n.John's = [ ... ]
The use case I'm thinking of is not as a shortcut for data structures,
but instead, as a way to keep names as names, and maintaining those
names in a group. Thus the namespace association.
def foo(**kwds):
kwds = namespace(kwds)
print kwds.name
print kwds.value
...
name = 'ron'
value = 25
foo( name=name, position=position )
Just had the thought that if you want to add bindings on the fly modifying the
original object, you could use the __call__ method, e.g.,
... __getattr__ = dict.__getitem__
... __setattr__ = dict.__setitem__
... __delattr__ = dict.__delitem__
... def __call__(self, **upd):
... self.update(upd)
... return self
...-- showing {'initial': 1}
{'initial': 1}
And updating with a second keyword on the fly:
-- showing {'initial': 1}
-- showing {'second': 2, 'initial': 1}
{'second': 2, 'initial': 1}
FWIW ;-)
Regards,
Bengt Richter
Getting better! ;-)
That (or something similar) might avoid copying the whole thing in some
situations, which is something I am concerned about. But how to change
a dict to a namespace without copying the contents item by item?
I'm not sure where or if this is going anywhere. It may tie back into
the properties groups example (see below) I posted earlier and keep
finding improvements for. ;-)
cheers,
Ron
""" GPobject.py
Grouped Properties Object:
This need has presented itself while programming Tkinter
applications where a *LOT* of keywords are used. I think
property groups would also be good for general interface
building. The external view is of a single cohesive
object, while the internal mechanism keeps the attributes
grouped so they can be forwarded easily as **kwds.
class foo(GPobject):
def __init__(self):
self.properties(name, item_1, item_2, ... item_n)
def getter():
...
def setter():
...
def remover():
...
self.name.doc( __doc__ string )
self.name.get = getter
self.name.set = setter
self.name.remove = remover
* The properties() method can also accept a dictionary.
This will set both the names and the values at the same time.
self.properties(name, dictionary)
class myclass(GPobject):
def __init__(self, **kwds):
self.properties('kwds', **kwds)
* group.setup() allows easy initiation of get, set, remove,
and doc group settings in one step.
self.properties( name, *members )
self.name.setup( get=myget, set='set', del='del',
doc='a property group' )
* Using string flags to indicate default values lets you
shorten the expression further.
self.properties( name, *members )
self.name.setup( myget, 'set', 'del', 'a property group')
The following is only somewhat tested... but it seems to work.
"""
class GPdict(dict):
doc = "a property group"
def doc(self, docstring): self.__doc__ = docstring
def get(self, item): return self[item]
def set(self, item, value): self[item] = value
def remove(self, item): del self[item]
def setup( self, fget='get', fset='set',
fdel='del', doc=doc ):
if fget != 'get': self.get = fget
if fset != 'set': self.set = fset
if fdel != 'del': self.remove = fdel
self.__doc__ = doc
# Some useful common alternate methods to
# replace get, set and remove.
def readonly(self, *args):
raise AttributeError, 'read only property'
def setonce(self, item, value):
if self[item] is None: self[item] = value
else:
raise AttributeError, 'set once property'
def nonremovable(self, *args):
raise AttributeError, 'non removable property'
class GPobject(object):
""" an object that can use grouped properties """
__properties__ = {}
def __new__(cls, *args, **kwds):
cls.__properties__ = {}
return object.__new__(cls, *args, **kwds)
def properties(self, *args, **kwds):
dct = GPdict()
for i in args[1:]:
dct.setdefault(i,None)
dct.update(kwds)
self.__properties__[args[0]] = dct
self.__dict__[args[0]] = dct
def __getattr__(self, name):
for dct in self.__properties__:
if name in self.__properties__[dct]:
return self.__properties__[dct].get(name)
return self.__dict__[name]
def __setattr__(self, name, value):
notprop = True
for dct in self.__properties__:
if name in self.__properties__[dct]:
self.__properties__[dct].set(name,value)
notprop = False
if notprop:
self.__dict__[name] = value
def __delattr__(self, name):
for dct in self.__properties__:
if name in self.__properties__[dct]:
self.__properties__[dct].remove(name)
return
del self.__dict__[name]
=================
### Properties as keyword sorter example,
### (sort to groups, not ordered sort)
class sorter(GPobject):
text_group = str.split('text fill font')
line_group = str.split('line fill arrows')
def __init__( self, text=None, fill=None, line=None,
arrows=None, font=None ):
self.properties('_text', *self.text_group)
self.properties('_line', *self.line_group)
self.text = text
self.fill = fill
self.line = line
self.arrows = arrows
self.font = font
s = sorter(text='hello', fill='black', line='solid', arrows='both')
print 's._text =', s._text
print 's._line =', s._line
print s.__properties__