Are object literals Pythonic?

PythonObject Literal

Python Problem Overview


JavaScript has object literals, e.g.

var p = {
  name: "John Smith",
  age:  23
}

and .NET has anonymous types, e.g.

var p = new { Name = "John Smith", Age = 23}; // C#

Something similar can be emulated in Python by (ab)using named arguments:

class literal(object):
    def __init__(self, **kwargs):
        for (k,v) in kwargs.iteritems():
            self.__setattr__(k, v)
    def __repr__(self):
        return 'literal(%s)' % ', '.join('%s = %r' % i for i in sorted(self.__dict__.iteritems()))
    def __str__(self):
        return repr(self)

Usage:

p = literal(name = "John Smith", age = 23)
print p       # prints: literal(age = 23, name = 'John Smith')
print p.name  # prints: John Smith

But is this kind of code considered to be Pythonic?

Python Solutions


Solution 1 - Python

Why not just use a dictionary?

p = {'name': 'John Smith', 'age': 23}

print p
print p['name']
print p['age']

Solution 2 - Python

Have you considered using a named tuple?

Using your dict notation

>>> from collections import namedtuple
>>> L = namedtuple('literal', 'name age')(**{'name': 'John Smith', 'age': 23})

or keyword arguments

>>> L = namedtuple('literal', 'name age')(name='John Smith', age=23)
>>> L
literal(name='John Smith', age=23)
>>> L.name
'John Smith'
>>> L.age
23

It is possible to wrap this behaviour into a function easily enough

def literal(**kw):
    return namedtuple('literal', kw)(**kw)

the lambda equivalent would be

literal = lambda **kw: namedtuple('literal', kw)(**kw)

but personally I think it's silly giving names to "anonymous" functions

Solution 3 - Python

From ActiveState:

class Bunch:
    def __init__(self, **kwds):
        self.__dict__.update(kwds)

# that's it!  Now, you can create a Bunch
# whenever you want to group a few variables:

point = Bunch(datum=y, squared=y*y, coord=x)

# and of course you can read/write the named
# attributes you just created, add others, del
# some of them, etc, etc:
if point.squared > threshold:
    point.isok = 1

Solution 4 - Python

I don't see anything wrong with creating "anonymous" classes/instances. It's often very convienient to create one with simple function call in one line of code. I personally use something like this:

def make_class( *args, **attributes ):
    """With fixed inability of using 'name' and 'bases' attributes ;)"""
    if len(args) == 2:
        name, bases = args
    elif len(args) == 1:
        name, bases = args[0], (object, )
    elif not args:
        name, bases = "AnonymousClass", (object, )
    return type( name, bases, attributes )

obj = make_class( something = "some value" )()
print obj.something

For creating dummy objects it works just fine. Namedtuple is ok, but is immutable, which can be inconvenient at times. And dictionary is... well, a dictionary, but there are situations when you have to pass something with __getattr__ defined, instead of __getitem__.

I don't know whether it's pythonic or not, but it sometimes speeds things up and for me it's good enough reason to use it (sometimes).

Solution 5 - Python

I'd say that the solution you implemented looks pretty Pythonic; that being said, types.SimpleNamespace (documented here) already wraps this functionality:

from types import SimpleNamespace
p = SimpleNamespace(name = "John Smith", age = 23)
print(p)

Solution 6 - Python

From the Python IAQ:

> As of Python 2.3 you can use the syntax > > dict(a=1, b=2, c=3, dee=4) > which is good enough as far as I'm concerned. Before Python 2.3 I used the one-line function >
> def Dict(**dict): return dict >

Solution 7 - Python

I think object literals make sense in JavaScript for two reasons:

  1. In JavaScript, objects are only way to create a “thing” with string-index properties. In Python, as noted in another answer, the dictionary type does that.

  2. JavaScript‘s object system is prototype-based. There’s no such thing as a class in JavaScript (although it‘s coming in a future version) — objects have prototype objects instead of classes. Thus it’s natural to create an object “from nothing”, via a literal, because all objects only require the built-in root object as a prototype. In Python, every object has a class — you’re sort of expected to use objects for things where you’d have multiple instances, rather than just for one-offs.

Thus no, object literals aren’t Pythonic, but they are JavaScripthonic.

Solution 8 - Python

A simple dictionary should be enough for most cases.

If you are looking for a similar API to the one you indicated for the literal case, you can still use dictionaries and simply override the special __getattr__ function:

class CustomDict(dict):
    def __getattr__(self, name):
        return self[name]

p = CustomDict(user='James', location='Earth')
print p.user
print p.location

Note: Keep in mind though that contrary to namedtuples, fields are not validated and you are in charge of making sure your arguments are sane. Arguments such as p['def'] = 'something' are tolerated inside a dictionary but you will not be able to access them via p.def.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionShinNoNoirView Question on Stackoverflow
Solution 1 - PythonWayne WernerView Answer on Stackoverflow
Solution 2 - PythonJohn La RooyView Answer on Stackoverflow
Solution 3 - PythonpillmuncherView Answer on Stackoverflow
Solution 4 - PythoncjiView Answer on Stackoverflow
Solution 5 - PythonMaldusView Answer on Stackoverflow
Solution 6 - PythonKenView Answer on Stackoverflow
Solution 7 - PythonPaul D. WaiteView Answer on Stackoverflow
Solution 8 - PythonunodeView Answer on Stackoverflow