I'm a Python newbie with a very particular itch to experiment with Python's dot-name-lookup process. How do I code either a class or function in "make.py" so that these assignment statements work succesfully?
import make
make.a.dot.separated.name = 666
make.something.else.up = 123
make.anything.i.want = 777
#!/usr/bin/env python
class Make:
def __getattr__(self, name):
self.__dict__[name] = Make()
return self.__dict__[name]
make = Make()
make.a.dot.separated.name = 666
make.anything.i.want = 777
print make.a.dot.separated.name
print make.anything.i.want
The special __getattr__
method is called when a named value isn't found. The line make.anything.i.want
ends up doing the equivalent of:
m1 = make.anything # calls make.__getattr__("anything")
m2 = m1.i # calls m1.__getattr__("i")
m2.want = 777
The above implementation uses these calls to __getattr__
to create a chain of Make
objects each time an unknown property is accessed. This allows the dot accesses to be nested arbitrarily deep until the final assignment at which point a real value is assigned.
Python documentation - customizing attribute access:
object.__getattr__(self, name)
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self
). name
is the attribute name. This method should return the (computed) attribute value or raise an AttributeError
exception.
Note that if the attribute is found through the normal mechanism, __getattr__()
is not called. (This is an intentional asymmetry between __getattr__()
and __setattr__()
.) This is done both for efficiency reasons and because otherwise __getattr__()
would have no way to access other attributes of the instance. Note that at least for instance variables, you can fake total control by not inserting any values in the instance attribute dictionary (but instead inserting them in another object). See the __getattribute__()
method below for a way to actually get total control in new-style classes.
object.__setattr__(self, name, value)
Called when an attribute assignment is attempted. This is called instead of the normal mechanism (i.e. store the value in the instance dictionary). name
is the attribute name, value
is the value to be assigned to it.
If __setattr__()
wants to assign to an instance attribute, it should not simply execute self.name = value
— this would cause a recursive call to itself. Instead, it should insert the value in the dictionary of instance attributes, e.g., self.__dict__[name] = value
. For new-style classes, rather than accessing the instance dictionary, it should call the base class method with the same name, for example, object.__setattr__(self, name, value)
.