eval evaluates to a tuple - python

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.

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.

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.

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

Related

How can I preserve the value of my parameters through a function so it can be used multiple times with its initial value?

I have just started using SAGE which is pretty close to python as I understand it, and I have come accross this problem where I'll have as a parameter of a function a matrix which I wish to use multiple times in the function with its same original function but through the different parts of the function it changes values.
I have seen in a tutorial that declaring a variable in the function as
variable = list(parameter) doesnt affect the parameter or whatever is put in the parentheses. However I can't make it work..
Below is part of my program posing the problem (I can add the rest if necessary): I declare the variable determinant which has as value the result of the function my_Gauss_determinant with the variable auxmmatrix as parameter. Through the function my_Gauss_determinant the value of auxmmatrix changes but for some reason the value of mmatrix as well. How can avoid this and be able to re-use the parameter mmatrix with its original value?
def my_Cramer_solve(mmatrix,bb):
auxmmatrix=list(mmatrix)
determinant=my_Gauss_determinant(auxmmatrix)
if determinant==0:
print
k=len(auxmmatrix)
solution=[]
for l in range(k):
auxmmatrix1=my_replace_column(list(mmatrix),l,bb)
determinant1=my_Gauss_determinant(auxmmatrix1)
solution.append(determinant1/determinant0)
return solution
What you want is a copy of mmatrix. The reason list(other_list) works is because it iterates through every item in other_list to create a new list. But the mutable objects within the list aren't copied
>>> a = [{1,2}]
>>> b = list(a)
>>> b[0].add(7)
>>> a
[set([1,2,7])]
To make a complete copy, you can use copy.deepcopy to make copies of the elements within the list
>>> import copy
>>> a = [{1,2}]
>>> b = copy.deepcopy(a)
>>> b[0].add(7)
>>> a
[set([1,2])]
So if you only want to copy the list, but don't want to copy the elements within the list, you would do this
auxmmatrix = copy.copy(matrix)
determinant = my_Gauss_determinant(copy.copy(matrix))
If you want to copy the elements within the list as well, use copy.deepcopy
If m is a matrix, you can copy it into mm by doing
sage: mm = m[:, :]
or
sage: mm = matrix(m)
To understand the need to copy container structures such as lists and matrices, you could read the tutorial on objects and classes in Python and Sage.
The other Sage tutorials are recommended too!

Printing a list as variable values

How would I print a list of strings as their individual variable values?
For example, take this code:
a=1
b=2
c=3
text="abc"
splittext = text.split(text)
print(splittext)
How would I get this to output 123?
You could do this using eval, but it is very dangerous:
>>> ''.join(map(lambda x : str(eval(x)),Text))
'123'
eval (perhaps they better rename it to evil, no hard feelings, simply use it as a warning) evaluates a string as if you would have coded it there yourself. So eval('a') will fetch the value of a. The problem is that a hacker could perhaps find some trick to inject arbitrary code using this, and thus hack your server, program, etc. Furthermore by accident it can perhaps change the state of your program. So a piece of advice is "Do not use it, unless you have absolutely no other choice" (which is not the case here).
Or a less dangerous variant:
>>> ''.join(map(lambda x : str(globals()[x]),Text))
'123'
in case these are global variables (you can use locals() for local variables).
This is ugly and dangerous, because you do not know in advance what a, b and c are, neither do you have much control on what part of the program can set these variables. So it can perhaps allow code injection. As is advertised in the comments on your question, you better use a dictionary for that.
Dictionary approach
A better way to do this is using a dictionary (as #Ignacio Vazquez-Abrams was saying):
>>> dic = {'a':1,'b': 2,'c':3}
>>> ''.join(map(lambda x : str(dic[x]),Text))
'123'
List instead of string
In the above we converted the content to a string using str in the lambda-expression and used ''.join to concatenate these strings. If you are however interested in an array of "results", you can drop these constructs. For instance:
>>> map(lambda x : dic[x],Text)
[1, 2, 3]
The same works for all the above examples.
EDIT
For some reason, I later catched the fact that you want to print the valuesm, this can easily be achieved using list comprehension:
for x in Text :
print dic[x]
again you can use the same technique for the above cases.
In case you want to print out the value of the variables named in the string you can use locals (or globals, depending on what/where you want them)
>>> a=1
>>> b=2
>>> c=3
>>> s='abc'
>>> for v in s:
... print(locals()[v])
...
1
2
3
or, if you use separators in the string
>>> s='a,b,c'
>>> for v in s.split(','):
... print(locals()[v])
...
1
2
3

What does the slice() function do in Python?

First of all, I'd like to clarify the question: it's about the slice() function, not slices of lists or strings like a[5:4:3].
The docs mention that this function is used in NumPy and give no examples of usage (it's said how to use it but it's not said when to use it). Moreover, I've never seen this function used in any Python program.
When should one use the slice() function when programming in plain Python (without NumPy or SciPy)? Any examples will be appreciated.
a[x:y:z] gives the same result as a[slice(x, y, z)]. One of the advantages of a slice object is that it can be stored and retrieved later as a single object instead of storing x, y and z.
It is often used to let the user define their own slice that can later be applied on data, without the need of dealing with many different cases.
(Using function semantics) Calling the slice class instantiates a slice object (start,stop,step), which you can use as a slice specifier later in your program:
>>> myname='Rufus'
>>> myname[::-1] # reversing idiom
'sufuR'
>>> reversing_slice=slice(None,None,-1) # reversing idiom as slice object
>>> myname[reversing_slice]
'sufuR'
>>> odds=slice(0,None,2) # another example
>>> myname[odds]
'Rfs'
If you had a slice you often used, this is preferable to using constants in multiple program areas, and save the pain of keeping 2 or 3 references that had to be typed in
each time.
Of course, it does make it look like an index, but after using Python a while, you learn that everything is not what it looks like at first glance, so I recommend naming your variables better (as I did with reversing_slice, versus odds which isn't so clear.
No, it's not all!
As objects are already mentioned, first you have to know is that slice is a class, not a function returning an object.
Second use of the slice() instance is for passing arguments to getitem() and getslice() methods when you're making your own object that behaves like a string, list, and other objects supporting slicing.
When you do:
print "blahblah"[3:5]
That automatically translates to:
print "blahblah".__getitem__(slice(3, 5, None))
So when you program your own indexing and slicing object:
class example:
def __getitem__ (self, item):
if isinstance(item, slice):
print "You are slicing me!"
print "From", item.start, "to", item.stop, "with step", item.step
return self
if isinstance(item, tuple):
print "You are multi-slicing me!"
for x, y in enumerate(item):
print "Slice #", x
self[y]
return self
print "You are indexing me!\nIndex:", repr(item)
return self
Try it:
>>> example()[9:20]
>>> example()[2:3,9:19:2]
>>> example()[50]
>>> example()["String index i.e. the key!"]
>>> # You may wish to create an object that can be sliced with strings:
>>> example()["start of slice":"end of slice"]
Older Python versions supported the method getslice() that would be used instead of getitem(). It is a good practice to check in the getitem() whether we got a slice, and if we did, redirect it to getslice() method. This way you will have complete backward compatibility.
This is how numpy uses slice() object for matrix manipulations, and it is obvious that it is constantly used everywhere indirectly.
From your question I believe you are looking for an example. So here is what I have when I try to slice a list from range(1, 20) with a step of 3
>>> x = range(1, 20)
>>> x[1:20:3]
[2, 5, 8, 11, 14, 17]
>>> x[slice(1, 20, 3)]
[2, 5, 8, 11, 14, 17]

assignment to multiple indirectly addressed variables

Single assignment works like this: (there may be better ways)
b='bb'
vars()[b] = 10
bb
>>>10
but if I do this:
c='cc'
vars() [b,c]= 10,11
it doesn't successfully assign bb and cc.
I don't understand why, nor how best to do this.
Thanks
PS, several people have asked, quite reasonably, why I wanted to do this. I found I was setting up a lot of variables and objects according to options specified by the user. So if the user specified options 2, 3 and 7, I would want to create a2, a3 and 7, plus b2, b3, b7 etc. It may not be usual practice but using vars and eval is a very easy and transparent way to do it, requiring simple concise code:
For i in input_vector: vars()['a'+input_vector[i]] = create_a (input_vector[i])
For i in input_vector: vars()['b'+input_vector[i]] = create_b (input_vector[i])
This works for some of the data. The trouble is when I use another function, create_c_and_d. This requires me to compress the above two lines into one function call. If this can be done easily using dictionaries, I am happy to switch to that method. I am new to python so it isn't obvious to me whether it can.
Because b,c is a tuple, so you're actually assiging to the key ('bb', 'cc').
>>> vars() [b,c]= 10,11
>>> vars()[('bb', 'cc')]
(10, 11)
>>> x = b,c
>>> type(x)
<type 'tuple'>
I don't understand why, nor how best to do this.
Well, I have to say, uh.. the best way would be to not do it. At all.
Just use a dict like it's supposed to be used:
d = {}
d['aa'] = 10
d['bb'] = 11
Anyway, to answer your question, you're doing the tuple unpacking in the wrong place. Or, rather, not unpacking at all; when you specify a,b to a dict, that means you're assigning a tuple as the key. Instead, unpack like this:
vars()[b], vars()[c] = 10,11
I'll again recommend that you not do this and just use dicts to map strings (or whatever hashable datatype) to values. Dynamically naming variables is not good practice.

Is it pythonic for a function to return multiple values?

In python, you can have a function return multiple values. Here's a contrived example:
def divide(x, y):
quotient = x/y
remainder = x % y
return quotient, remainder
(q, r) = divide(22, 7)
This seems very useful, but it looks like it can also be abused ("Well..function X already computes what we need as an intermediate value. Let's have X return that value also").
When should you draw the line and define a different method?
Absolutely (for the example you provided).
Tuples are first class citizens in Python
There is a builtin function divmod() that does exactly that.
q, r = divmod(x, y) # ((x - x%y)/y, x%y) Invariant: div*y + mod == x
There are other examples: zip, enumerate, dict.items.
for i, e in enumerate([1, 3, 3]):
print "index=%d, element=%s" % (i, e)
# reverse keys and values in a dictionary
d = dict((v, k) for k, v in adict.items()) # or
d = dict(zip(adict.values(), adict.keys()))
BTW, parentheses are not necessary most of the time.
Citation from Python Library Reference:
Tuples may be constructed in a number of ways:
Using a pair of parentheses to denote the empty tuple: ()
Using a trailing comma for a singleton tuple: a, or (a,)
Separating items with commas: a, b, c or (a, b, c)
Using the tuple() built-in: tuple() or tuple(iterable)
Functions should serve single purpose
Therefore they should return a single object. In your case this object is a tuple. Consider tuple as an ad-hoc compound data structure. There are languages where almost every single function returns multiple values (list in Lisp).
Sometimes it is sufficient to return (x, y) instead of Point(x, y).
Named tuples
With the introduction of named tuples in Python 2.6 it is preferable in many cases to return named tuples instead of plain tuples.
>>> import collections
>>> Point = collections.namedtuple('Point', 'x y')
>>> x, y = Point(0, 1)
>>> p = Point(x, y)
>>> x, y, p
(0, 1, Point(x=0, y=1))
>>> p.x, p.y, p[0], p[1]
(0, 1, 0, 1)
>>> for i in p:
... print(i)
...
0
1
Firstly, note that Python allows for the following (no need for the parenthesis):
q, r = divide(22, 7)
Regarding your question, there's no hard and fast rule either way. For simple (and usually contrived) examples, it may seem that it's always possible for a given function to have a single purpose, resulting in a single value. However, when using Python for real-world applications, you quickly run into many cases where returning multiple values is necessary, and results in cleaner code.
So, I'd say do whatever makes sense, and don't try to conform to an artificial convention. Python supports multiple return values, so use it when appropriate.
The example you give is actually a python builtin function, called divmod. So someone, at some point in time, thought that it was pythonic enough to include in the core functionality.
To me, if it makes the code cleaner, it is pythonic. Compare these two code blocks:
seconds = 1234
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
seconds = 1234
minutes = seconds / 60
seconds = seconds % 60
hours = minutes / 60
minutes = minutes % 60
Yes, returning multiple values (i.e., a tuple) is definitely pythonic. As others have pointed out, there are plenty of examples in the Python standard library, as well as in well-respected Python projects. Two additional comments:
Returning multiple values is sometimes very, very useful. Take, for example, a method that optionally handles an event (returning some value in doing so) and also returns success or failure. This might arise in a chain of responsibility pattern. In other cases, you want to return multiple, closely linked pieces of data---as in the example given. In this setting, returning multiple values is akin to returning a single instance of an anonymous class with several member variables.
Python's handling of method arguments necessitates the ability to directly return multiple values. In C++, for example, method arguments can be passed by reference, so you can assign output values to them, in addition to the formal return value. In Python, arguments are passed "by reference" (but in the sense of Java, not C++). You can't assign new values to method arguments and have it reflected outside method scope. For example:
// C++
void test(int& arg)
{
arg = 1;
}
int foo = 0;
test(foo); // foo is now 1!
Compare with:
# Python
def test(arg):
arg = 1
foo = 0
test(foo) # foo is still 0
It's definitely pythonic. The fact that you can return multiple values from a function the boilerplate you would have in a language like C where you need to define a struct for every combination of types you return somewhere.
However, if you reach the point where you are returning something crazy like 10 values from a single function, you should seriously consider bundling them in a class because at that point it gets unwieldy.
Returning a tuple is cool. Also note the new namedtuple
which was added in python 2.6 which may make this more palatable for you:
http://docs.python.org/dev/library/collections.html#collections.namedtuple
OT: RSRE's Algol68 has the curious "/:=" operator. eg.
INT quotient:=355, remainder;
remainder := (quotient /:= 113);
Giving a quotient of 3, and a remainder of 16.
Note: typically the value of "(x/:=y)" is discarded as quotient "x" is assigned by reference, but in RSRE's case the returned value is the remainder.
c.f. Integer Arithmetic - Algol68
It's fine to return multiple values using a tuple for simple functions such as divmod. If it makes the code readable, it's Pythonic.
If the return value starts to become confusing, check whether the function is doing too much and split it if it is. If a big tuple is being used like an object, make it an object. Also, consider using named tuples, which will be part of the standard library in Python 2.6.
I'm fairly new to Python, but the tuple technique seems very pythonic to me. However, I've had another idea that may enhance readability. Using a dictionary allows access to the different values by name rather than position. For example:
def divide(x, y):
return {'quotient': x/y, 'remainder':x%y }
answer = divide(22, 7)
print answer['quotient']
print answer['remainder']

Categories