What is the best approach to take if you want to dynamically create and reference nested attributes?
I was writing a simple Flickr client, and wanted to match the documented API as closely as possible, without actually defining every method. For instance, to make a request to Flickr's flickr.people.getInfo
API method:
flickr = Client()
data = flickr.people.getInfo(user_id='xxx')
In this case flickr.people.getInfo
directly maps to the corresponding method in their API documentation. When called, people
and getInfo
are created as they are looked up, then the proper request to make is determined by the path to getInfo
, which is people.getInfo
. This is the approach I used:
class Attr(object):
def __init__(self, client, name, parent):
self._client = client
self._name = name
self._parent = parent
def __getattr__(self, name):
attr = Attr(self._client, name, self)
setattr(self, name, attr)
return attr
def _get_path(self, path=None):
if path:
path = '.'.join((self._name, path))
else:
path = self._name
if isinstance(self._parent, Attr):
return self._parent._get_path(path)
return path
def __call__(self, *args, **kwargs):
return self._client.execute_method(self._get_path(), *args, **kwargs)
class Client(object):
def __getattr__(self, name):
attr = Attr(self, name, None)
setattr(self, name, attr)
return attr
def execute_method(self, method, *args, **kwargs):
print method, args, kwargs
This works, but I'm curious if my approach to deal with nested attribute assignment/lookup can be improved, or if there are any errors lurking in wait, unbeknownst to me. In particular, I'm curious if there is a better way to figure out the "path" to a given attribute. For example, if I call Client().x.y.z()
, x
, y
, z
do not exist, and will be created one by one (as __getattr__
looks up a single attribute at a time). By the time z
is called, I need to be able to discern that the path to z
is x.y.z
.
__getattr__(self, name) Is an object method that is called if the object's properties are not found. This method should return the property value or throw AttributeError . Note that if the object property can be found through the normal mechanism, it will not be called.
Python getattr() function. Python getattr() function is used to get the value of an object's attribute and if no attribute of that object is found, default value is returned.
Thanks to Thomas K for pointing out that flipy already does this (and seems like a nice library for interacting with flickr). A cleaner approach:
class Method(object):
def __init__(self, client, method_name):
self.client = client
self.method_name = method_name
def __getattr__(self, key):
return Method(self.client, '.'.join((self.method_name, key)))
def __call__(self, **kwargs):
print self.method_name, kwargs
class Client(object):
def __getattr__(self, key):
return Method(self, key)
Et voilà:
>>> c = Client()
>>> c.some.method(x=1, y=2)
some.method {'y': 2, 'x': 1}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With