32 ms·
I've also written a similar-ish thing ( http://py-datakit.googlecode.com/hg/README.html http://py-datakit.googlecode.com/hg/README.html ), which was more focuse
by forgotusername 15y ago
I've also written a similar-ish thing ( http://py-datakit.googlecode.com/hg/README.html http://py-datakit.googlecode.com/hg/README.html ), which was more focused on providing useful encodings.
The problem with these styles of library is that their modularity is relatively poor. Once you start using attribute access for simple data, or relying on extended features of the container, all your callers, and future reuses of the code are forced to also use that style of access.
While it is easy to mock up a container sporting attributes that can be substituted in place of the instance type, e.g.:
class Bag(dict):
__setattribute__ = dict.__setitem__
__getattr__ = dict.__getitem__
Another problem will rear its ugly head: namespace collisions, since the field names of 'user data' with attribute names of the container type cannot conflict with any method you might (now, or most likely in the future, once you've already dug the hole) want to add to the instance type.
For these reasons, mantra 3 of 'import this' comes to mind:
Simple is better than complex.
Why not just use a dict, or something that looks almost identical to a dict, to begin with? Caller code is not polluted with your types, interoperability with things that expect dicts is ensured, and future extension is imminently possible since 'user fields' cannot conflict with methods you may wish to add.
I've recently picked up DataKit work again. The local development version has a dict-like object whose only extension is to ensure the type of assigned items matches that of the schema type. This replaces an old 'Entity' class that required attribute access (essentially chosen only because it was "prettier").
A hidden benefit of passing a simple type is easier testability: from a unit test, initializing a class with a dict literal is much easier than needing some attribute-like stub class that must be declared and initialized first (to avoid that, you're forced to test your container class at the same time as whatever caller code is currently under test, which is a broken habit).
As if it wasn't clear: please, please continue passing naked dictionaries around, they're a universal container protocol evolved over 20+ years that wasn't in need of fixing.
- io41 15y agoI agree. Though a more useful constructor would be nice for naked dicts. I've created a helper function that allows for nicer construction of dicts based on other dicts and potential new fields: https://gist.github.com/24651d78d3f1e3dec6f4 https://gist.github.com/24651d78d3f1e3dec6f4 : def new_dict(args, *kwargs): """ Create new dicts >>> new_dict({1:2}, {2:5}, foo=5) {1: 2, 2: 5, 'foo': 5} """ d = {} for arg in args: d.update(arg) d.update(kwargs) return d d = new_dict(old_dict1, old_dict2, old_dictN, foo='bar')
- wladimir 15y agoI think every Python developer worth their salt implemented a class like this at least once in their career (mine was even called DStruct :-) ). And probably at a certain later point decided it was not that good an idea. (essentially chosen only because it was "prettier"). That was my reason as well. It is easier/prettier to write a.b.c. instead of ['a']['b']['c']. But that's all.
- dorkitude 15y ago(responded in http://news.ycombinator.com/item?id=3274914 http://news.ycombinator.com/item?id=3274914)
- dorkitude 15y agoI must admit, I chose the title of this submission poorly. It should have read "stop passing naked dictionaries around for everything". Of course, dictionaries are incredibly useful when called for (for instance, when you want to iterate over the keys!). But I have frequently seen them being used when class instances would be better suited. Dictionaries' values cannot be replaced with methods via @property, and as a result, I've found they often need to be replaced with objects at some point. DStruct is a response to that problem where your access interfaces aren't forwards-compatible with the great majority of types you might choose in the future (ORM/ODM instances are a big one). But I've also found it quite useful in the other direction: when replacing what was once an ORM/ODM class with something mocked (e.g. the data source that was once a database has become a remote resource, local file, parser output, or configuration dict), having to run around changing attribute accessors to dict accessors is a drag at best, and impossible at worst (e.g. If you were using @property extensively to return computed attributes, or you know at hydration time that code elsewhere relies on a schema (I do both a times, as anyone writing large, maintainable applications should.). As another commenter also mentioned, my approach does yield prettier code. While it's not always sufficient cause, prettier code is in fact a good thing.