Python's dict() user interface pretty much blows; you end strewing quotes everywhere and
having to remember the idiom for setting the first use of a key. On the other hand,
lua's table (hash)
user interface rocks. I want my python dict()s to look more like lua tables:
my_dict = Dict()
my_dict.foo += ".py"
my_dict.bar += 1
In python, we can use a descriptor type class to implement the basic usage; however the
autovivification of an attribute and increment requires a little trickiness. We
need to create a new class to override the typical operators. Ideally (?), python
would have an IdentityType type that acts like an identity operator for types: i.e.
IdentityType operating on any other type returns the other type.
Originally, I thought that NoneType or NotImplementedType might satisfy this; they don't.
So, we have to implement a new type, IdentityType, and use it to deal with the
autovivification.
Update: 2008-10-28
I cleaned up the Dict class by subclassing dict() and converted the unknown attribute operations
to just call the __*item__ methods. And added a bunch more tests.
import types
class UnknownType(object):
""" provide type that becomes the type of the parameter """
def __init__( self ):
return None
def __add__(self, n):
return n
def __sub__(self, n):
if type(n) in (types.IntType, types.FloatType, types.LongType, types.ComplexType):
return -1 * n
raise TypeError
def __mul__(self, n):
return n
def __div__(self, n):
if type(n) in (types.IntType, types.FloatType, types.LongType, types.ComplexType):
return 1/n
raise TypeError
def __mod__(self, n):
raise TypeError
class Dict(dict):
def __init__(self):
return dict.__init__(self)
def __setattr__(self, attr, val):
self[attr] = val
def __getattr__(self, attr):
if attr in self.keys():
return self[attr]
return UnknownType()
def __getitem__(self, k):
if k in self.keys():
return super(Dict, self).__getitem__(k)
return UnknownType()
if __name__ == '__main__':
print "Beginning tests..."
h = Dict()
print " Object instantiation OK"
h['a'] = 1
assert h['a'] == 1, "subscript set/get item"
assert h.a == 1, "attribute get"
print " Subscript get/set OK"
h.a = 2
assert h.a == 2, "attribute set"
print " Attribute get/set OK"
h.b += 1
assert h.b == 1, "+="
h.c -= 1
assert h.c == -1, "-="
h.d *= 2
assert h.d == 2, "*="
h.e /= 2
assert h.e == 1/2, "/="
try:
h.f %= 2
except TypeError:
pass
print " UnknownType operations OK"
# use cases
for i in (1,3,1,3,2,1,3,3,4):
h[i] += 1
print " Subscript with UnknownType OK"
test = { 'a' : 2,
1 : 3,
'c' : -1,
'b' : 1,
'e' : 0,
'd' : 2,
2 : 1,
3 : 4,
4 : 1,
}
assert test == h, "storage inconsistent!"
print " Storage consistency OK"
print "All tests passed OK"