The problem
When it comes to the Python dict
syntax, what makes it clanky and annoying is the need to always pass keys as strings and use square brackets when accessing a dict
's value:
x = {'a': 1, 'b': 2}
value = x['b'] # we have to write square brackets and use strings inside them
It is made quite concise in JavaScript language where all you need is access your value through the dot syntax like the following:
x = {'a': 1, 'b': 2}
value = x.b // no need to use square brackets or strings!
The solution
This simple package introduces a new Python dict
object which has some similarities to the JavaScript object in terms of dot syntax.
The object is called PyObjectDict
.
import the package and try to initialize your PyObjectDict in a preferred way:
from object_dict import PyObjectDict
a = PyObjectDict({'a': 2, 'b': 3, 'c': 10, 'd': 8})
b = PyObjectDict.form(**{'a': 2, 'b': 3, 'c': 4, 'g': 8})
Note: PyObjectDict
constructor works with types: dict
, OrderedDict
, and PyObjectDict
(to create a copy)
you may add new attributes to the object by simply using the dot syntax:
a.e = 1
a.f = 1
a.g = 1
a.h = 1
a.i = 1
you may then easily access any attribute by using:
print(a.a) # will print 2
print(a.e) # will print 1
The PyObjectDict
also exposes a lot of additional convenience methods as well as standard dict
methods.
They are listed in the table above and an example of their usage can be seen below it.
Name | Parameters | Return value | Description |
---|---|---|---|
length |
- | int |
returns the lenght of the dictionary |
keys |
- | list |
returns the list of keys of the dictionary |
items |
- | list of tuple s |
returns the list of tuples containing key, value pairs of each item in the dicrionary |
iteritems |
- | iterator |
iterator for items method |
values |
- | list |
returns the list of values of the dictionary |
update |
other (PyObjectDict ) |
None |
updates one PyObjectDict with the other (merges them) in place. Returns nothing |
get |
key (str ), default (None ) |
type of key or type of default parameter |
returns value of the key if key exists or default parameter (which isNone by default) |
add |
other (PyObjectDict ) |
PyObjectDict |
merges two PyObjectDict s and returns a merged copy |
add_each_value |
other (PyObjectDict ) |
PyObjectDict |
merges the keys of two PyObjectDict s and adds the corresponding key values together. returns a merged copy |
sub |
other (PyObjectDict ) |
PyObjectDict |
subtracts one PyObjectDict from another and returns a copy containing not intersecting keys of the first PyObjectDict with their values |
sub_each_value |
other (PyObjectDict ) |
PyObjectDict |
subtracts the values of the corresponding keys of the first PyObjectDict from the second one. Returns a copy |
sub_by_value |
other (PyObjectDict ) |
PyObjectDict |
the same as sub but subtraction happens by the unique key: value pairs not just the unique keys |
Name | Parameters | Return value | Description |
---|---|---|---|
+ |
other (PyObjectDict ) |
PyObjectDict |
the same as add method |
+= |
other (PyObjectDict ) |
PyObjectDict |
the same as add method but assigns the result to the PyObjectDict to the left side of the operator |
| |
other (PyObjectDict ) |
PyObjectDict |
the same as add method |
|= |
other (PyObjectDict ) |
PyObjectDict |
the same as += operator |
- |
other (PyObjectDict ) |
PyObjectDict |
the same as sub method |
-= |
other (PyObjectDict ) |
PyObjectDict |
the same as sub method but assigns the result to the PyObjectDict to the left side of the operator |
Name | Parameters | Return value | Description |
---|---|---|---|
len |
- | int |
returns the lenght of the dictionary |
str |
- | str |
returns the string representation of the dicrionary |
Name | Parameters | Return value | Description |
---|---|---|---|
PyObjectDict |
- | PyObjectDict |
creates an PyObjectDict from dict , OrderedDict , or PyObjectDict (copy) |
PyObjectDict.from |
- | PyObjectDict |
creates an PyObjectDict from the key value pairs that are successively passed to the constructor |
from pyobjectdict import PyObjectDict
a = PyObjectDict({'a': 2, 'b': 3, 'c': 10, 'd': 8})
b = PyObjectDict.form(**{'a': 2, 'b': 3, 'c': 4, 'g': 8})
print('a:', a)
print('b:', b)
c = a.sub_by_value(b)
print('c:', c)
print('c.length():', c.length())
print('c.keys():', c.keys())
print('c.items():', c.items())
print('c.iteritems():', list(c.iteritems()))
print('c.values():', c.values())
print('c.update(PyObjectDict({"a": 1, "b": 2, "c": 3})):', c.update(PyObjectDict({'a': 1, 'b': 2, 'c': 3})))
print('c.update(PyObjectDict({"a": 1, "b": 2, "c": 3})):', c.update(PyObjectDict({'a': 1, 'b': 2, 'c': 3})))
print('iteratibng over c:')
for k in c:
print('key: ', k)
print('a + b:', a + b)
print('a | b:', a | b)
print('a.add(b):', a.add(b))
print('a.add_each_value(b):', a.add_each_value(b))
a.update(b)
print('a after a.update(b):', a)
a.cc = 12
b.cc = 12
print('a after adding "cc": 12:', a)
print('b after adding "cc": 12:', b)
print('a - b:', a - b)
print('a.sub(b):', a.sub(b))
print('a.sub_by_value(b):', a.sub_by_value(b))
print('a.sub_each_value(b):', a.sub_each_value(b))
a += b
print('a after a += b:', a)
a -= b
print('a after a -= b:', a)
a |= b
print('a after a |= b', a)
The result of the code above will be:
a: PyObjectDict({'a': 2, 'b': 3, 'c': 10, 'd': 8})
b: PyObjectDict({'a': 2, 'b': 3, 'c': 4, 'g': 8})
c: PyObjectDict({'c': 10, 'd': 8})
c.length(): 2
c.keys(): ['c', 'd']
c.items(): [('c', 10), ('d', 8)]
list(c.iteritems()): [('c', 10), ('d', 8)]
c.values(): [10, 8]
c.update(PyObjectDict({"a": 1, "b": 2, "c": 3})): None
c.update(PyObjectDict({"a": 1, "b": 2, "c": 3})): None
iteratibng over c:
key: c
key: d
key: a
key: b
a + b: PyObjectDict({'a': 2, 'b': 3, 'c': 4, 'd': 8, 'g': 8})
a | b: PyObjectDict({'a': 2, 'b': 3, 'c': 4, 'd': 8, 'g': 8})
a.add(b): PyObjectDict({'a': 2, 'b': 3, 'c': 4, 'd': 8, 'g': 8})
a.add_each_value(b): PyObjectDict({'a': 4, 'b': 6, 'c': 14, 'd': 8})
a after a.update(b): PyObjectDict({'a': 2, 'b': 3, 'c': 4, 'd': 8, 'g': 8})
a after adding "cc": 12: PyObjectDict({'a': 2, 'b': 3, 'c': 4, 'd': 8, 'g': 8, 'cc': 12})
b after adding "cc": 12: PyObjectDict({'a': 2, 'b': 3, 'c': 4, 'g': 8, 'cc': 12})
a - b: PyObjectDict({'d': 8})
a.sub(b): PyObjectDict({'d': 8})
a.sub_by_value(b): PyObjectDict({'d': 8})
a.sub_each_value(b): PyObjectDict({'a': 0, 'b': 0, 'c': 0, 'd': 8, 'g': 0, 'cc': 0})
a after a += b: PyObjectDict({'a': 2, 'b': 3, 'c': 4, 'd': 8, 'g': 8, 'cc': 12})
a after a -= b: PyObjectDict({'d': 8})
a after a |= b PyObjectDict({'d': 8, 'a': 2, 'b': 3, 'c': 4, 'g': 8, 'cc': 12})
Remember that in JavaScripts objects it is possible to access a non-existing attribute and receve an undefined
value.
However, since Python has no concept of undefined
and checking for None
could be missleading (+ the limitations of Python objects), you cannot access an unexisting attribute of PyObjectDict
without triggering an AttributeError
exception. Alternatively you can use get
method as in standard Python dicts to check if the attribute exists before accessing it.