0

In python3 I have the following complete code:

class Test:
    def __init__(self):
        self.x = [42, 4711]
        self.y = [4, 6]
        self.z = 99

t = Test()
v = 'x[1]' # or can be 'y[0]' or can be 'z' ...
print(eval('t.'+v))
print(getattr(t,v))

which throws an error for the last line

AttributeError: 'Test' object has no attribute 'x[1]'

Is there a way to access a list inside an object via getattr, or do I have to use eval in this case?

HINT: The index is part of the string! I do not know if the attribute I am about to access is a list or just a value, This need to work for the following cases:

v = 'x[0]'
v = 'x[1]'
v = 'y[0]'
v = 'z'
Alex
  • 41,580
  • 88
  • 260
  • 469

3 Answers3

0

Don't use eval.

You can use getattr but you don't need the . nor the index in the string, just the attribute name.

t = Test()
v = 'x'
print(getattr(t, v)[0])

Outputs

42

This assumes that you actually need v to be a string (ie it comes from user input). Otherwise use the trivial way

print(t.x[0])
DeepSpace
  • 78,697
  • 11
  • 109
  • 154
  • I do not know the index beforehand. I even do not know if the object is a list; see updated question. – Alex Jan 06 '20 at 13:02
  • @Alex Why don't you know? what are you not telling us? This feels like an XY problem. Either way, this is not possible out of the box without using `eval`, but you really don't want to use it. You may try to use a regex to search for `[\d]` in the string, and use the way I showed – DeepSpace Jan 06 '20 at 13:03
0

Maybe this is what you need :

class Test:
    def __init__(self):
        self.x = [42, 4711]
        self.y = [4, 6]
        self.z = 99

t = Test()

my_x = getattr(t,'x')
print(my_x) # output : [42, 4711]
print(my_x[1]) # output : 4711
Phoenixo
  • 2,071
  • 1
  • 6
  • 13
  • The index is part of the string! – Alex Jan 06 '20 at 13:00
  • Maybe you could use 2 strings ? one with "x" and the second with "1" ? Can you tell us where the string comes from, the constraints you have, etc – Phoenixo Jan 06 '20 at 13:03
  • Please assume it is a fundamental question -> I can do it with `eval` in the generic way depicted. Can I do the same with out `eval`? – Alex Jan 06 '20 at 13:05
0

If the value is str you need to use eval(). You can override __getattr__ in Test and use it there

class Test:
    def __init__(self):
        self.x = [42, 4711]
        self.y = [4, 6]
        self.z = 99

    def __getattr__(self, item):
        return eval('self.' + item)


t = Test()
v = 'x[1]'
print(getattr(t, v)) # 4711
Guy
  • 46,488
  • 10
  • 44
  • 88