Reputation: 341
I have a function (here called analyze_data
) that takes an object and a string as input, and uses the string to "extract" data via getattr
. This works fine when the data are in the "frist" level of attributes (data1
). However, I don't know what I can pass to the function to access the data when they are in a lower level (data2
). Passing a dotted string (as shown below) does not work.
class a:
pass
instance1 = a()
# Create 1st data set
instance1.data1 = [1,2,3]
# Create 2nd data set
instance1.subdata = a()
instance1.subdata.data2 = [4,5,6]
def analyze_data(myvar, dataname):
data = getattr(myvar, dataname)
# Do something with data, e.g.:
print(str(data[0]))
analyze_data(instance1, 'data1')
analyze_data(instance1, 'subdata.data2')
What is the best way to access data2
without changing the existing function analyze_data
too much?
Upvotes: 2
Views: 803
Reputation: 14236
Instead of using getattr
you should use attrgetter
which allows you to specify using the dot notation. This does require a minor change to your function as shown below.
from operator import attrgetter
def analyze_data(myvar, dataname):
fn = attrgetter(dataname)
data = fn(myvar)
# Do something with data, e.g.:
print(str(data[0]))
analyze_data(instance1, 'data1')
1
analyze_data(instance1, 'subdata.data2')
4
Upvotes: 4
Reputation: 166
One way to achieve what you want without changing the function at all is this:
class a:
pass
instance1 = a()
# Create 1st data set
instance1.data1 = [1,2,3]
# Create 2nd data set
instance1.subdata = a()
instance1.subdata.data2 = [4,5,6]
def analyze_data(myvar, dataname):
data = getattr(myvar, dataname)
# Do something with data, e.g.:
print(str(data[0]))
analyze_data(instance1, 'data1')
analyze_data(instance1.subdata, 'data2')
Upvotes: 1
Reputation: 78780
functools.reduce
is another option.
>>> from functools import reduce
>>> reduce(getattr, 'subdata.data2'.split('.'), instance1)
[4, 5, 6]
Upvotes: 1
Reputation: 1957
You can recurse into the data by splitting the dotted path and following it:
def analyze_data(myvar, dataname):
for dn in dataname.split('.'):
myvar = getattr(myvar, dn)
# Do something with data, e.g.:
print(str(myvar[0]))
This keeps updating myvar
until you are at the end of the path.
Upvotes: 0