1

I have three indexes, x,y,t and a tridimensional matrix (it's actually a netcdf variable) in python but the order in which the indexes have to be applied to the matrix change. So, to make it easily user-definable I am trying to get the specific element I want as

order='t,x,y'  # or 't,y,x' or anything like this
elem=matrix[eval(order)]

but this fails with TypeError: illegal subscript type. When I try

a=eval(order)
print type(a)

it gives me that a is a tuple, so I'm guessing this is the source of my problem. But why is a a tuple? Any ideas as how to do this? Documentation wasn't helpful.

Also, somehow doing

a=eval(order)
i,j,k=a
elem=matrix[i,j,k]

doesn't work either. Not sure as to why.

EDIT

People are misunderstanding what I'm trying to do here apparently, so let me explain a little better. This is inside a function where the values x, y, t are already defined. However, the order in which to apply those indexes should be provided by the user. So the call would be something like func(order='t,x,y'). That's at least the only way I figured the user could pass the order of the indexes as a parameter. Sorry for the confusion.

TomCho
  • 3,204
  • 6
  • 32
  • 83
  • 5
    `a` is a tuple because you are using commas; it is the comma that defines a tuple, not the parentheses. – Martijn Pieters May 20 '15 at 12:40
  • @MartijnPieters I editted the question. Hopefully it will make more sense now. It was, indeed, lacking some crucial information. Let me know if it needs further editing. – TomCho May 20 '15 at 12:50

3 Answers3

1

Why is a a tuple?

Because it is: if you leave eval() out of the picture, you get the same, when you are just using commas:

>>> a = 1, 2, 3
>>> type(a)
<type 'tuple'>

do instead this:

Give the order directly as list, lists maintain order:

def some_method(order=None):
    order = order or [t, y, x]  
    # t, y, x have to be known out side this scope         
    ...

If your t, x, y are only known within the scope, you - of course - have to give the order in a symbolic way, thus back to eval. Here you assume knowledge about the inner state of your function

def some_method(order='t,x,y'):
    order = eval(order)
    ...
    elem = matrix[order[0]][order[1]][order[2]]

EDIT

wims answer shows how to avoid eval() which should be preferred at least when the input to this function would come from an untrusted source, because eval() would gladly run arbitrary python code.

Community
  • 1
  • 1
knitti
  • 6,817
  • 31
  • 42
  • But when I call `func(order=[t,y,x])` from the main function won't it give me an error because neither `t`,`x` or `y` are defined in the main function? They are only defined within `func` – TomCho May 20 '15 at 12:57
0

I think what you're looking for is called "slicing", or even "extended slicing", depending on the data format you're slicing. Oh, and you don't need eval for that at all, tuples would do just fine.

See also this question: Explain Python's slice notation

Community
  • 1
  • 1
wouter bolsterlee
  • 3,879
  • 22
  • 30
0

You should try to avoid using eval for this. It's hacky and ugly, and it's easily possible to avoid it just by making a lookup dict.

>>> order = 'x,y,t'  # this is specified outside your function

You can still pass this string into your function if you want:

>>> # this is inside your function:
>>> t,x,y = 0,1,2  # I don't know what your actual values are..
>>> lookup = {'t': t, 'x': x, 'y': y}  # make this inside your function
>>> tuple_ = tuple(lookup[k] for k in order.split(','))  
>>> tuple_
(1, 2, 0)

Now use the tuple_ to index your array.

wim
  • 338,267
  • 99
  • 616
  • 750