Are object literals Pythonic?
Question:
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?
Answers:
Why not just use a dictionary?
p = {'name': 'John Smith', 'age': 23}
print p
print p['name']
print p['age']
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
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
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
I think object literals make sense in JavaScript for two reasons:
-
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.
-
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.
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).
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
.
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)
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?
Why not just use a dictionary?
p = {'name': 'John Smith', 'age': 23}
print p
print p['name']
print p['age']
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
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
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
I think object literals make sense in JavaScript for two reasons:
-
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.
-
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.
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).
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
.
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)