Advantage of using a lambda:None function as a namespace?
This looks like a trick to create a simple object to hold values in one line. Most built-in objects don't allow you to set arbitrary attributes on them:
>>> object().x = 0
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'object' object has no attribute 'x'
>>> ''.x = 0
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'str' object has no attribute 'x'
>>> [].x = 0
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: 'list' object has no attribute 'x'
If you make your own class, then you can add whatever attributes you want. In this case you could make a class whose __init__
method assigns the attributes, but this may not be worth the boilerplate. So you can just make an empty class:
>>> class Data(object): pass
>>> d = Data()
>>> d.x = 0
>>> d.x
0
Apparently the programmer is either not aware of this or doesn't want that extra line where the class is declared and has come up with their own workaround for storing data. It turns out functions, despite being a built-in type do allow you to add attributes to them:
>>> def foo(): pass
>>> foo.x = 0
>>> foo.x
0
Both the above and a lambda let you create such a container in a single statement. I actually think that's a neat idea.
What is the advantage of using a lambda:None function?
What's going on here
eris = lambda:None
eris.jkcpp = ...
is that the writer is using the namespace (the __dict__
) of a function object.
This is very uncommon. I would avoid it.
A namespace is a domain where legal Python names are mapped to objects, and when you do something like the above, the advantage of a namespace is that the names are not in the local and global scope where they could overwrite or be overwritten where same names are intended to point to different objects.
There's nothing wrong with this on the face of it, but if others are trying to read the code to understand what's going on with this function that is being passed around, then they are probably thinking:
Will the lambda ever be called? Why are we passing around a callable? A callable that returns None isn't very useful, this must be some kind of hack.
To avoid confusion, use an object that will be semantically understood to be a namespace.
Namespaces
We have a SimpleNamespace object in the Python 3's Standard Library:
from types import SimpleNamespace
eris = SimpleNamespace()
eris.jkcpp = ...
In Python 2, it would be common to do something like:
class NS(object):
pass
eris = NS()
eris.jkcpp = ...
If you need a simple namespace, these are ok options.
Downsides
However, I have yet to see much use of these forms of namespaces. I either find that a namedtuple would suffice where I want semantics to be carried around with the data (particularly useful when there's a lot of them) or I use a mutable object with more than just pass
in it.
As they are, they are really no different, programmatically, from a simple dictionary. The values that the names point to are stored in the object's __dict__
. You may as well be passing around an dict
instance. The dotted lookup adds a little overhead (checked to see if the object's type has data descriptors before looking in the object's dictionary) too.
Conclusion:
The namespace instance may have some downsides, but it may be more readable. Readability counts. If you think your program needs a simple namespace, use it.
But don't use a do-nothing function for a namespace. It is misleading and will not make sense to anybody.