Reputation: 9469
I'm aware of using globals(), locals() and getattr to referance things in Python by string (as in this question) but unless I'm missing something obvious I can't seem to use this with calling types.
e.g.:
In [12]: locals()['int']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
e:\downloads_to_access\<ipython console> in <module>()
KeyError: 'int'
In [13]: globals()['int']
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
e:\downloads_to_access\<ipython console> in <module>()
KeyError: 'int'
getattr(???, 'int')...
What's the best way of doing this?
Upvotes: 5
Views: 2235
Reputation: 156238
Comments suggest that you are unhappy with the idea of using eval to generate data. looking for a function in __builtins__
allows you to find eval
.
the most basic solution given looks like this:
import __builtin__
def parseInput(typename, value):
return getattr(__builtins__,typename)(value)
You would use it like so:
>>> parseInput("int", "123")
123
cool. works pretty ok. how about this one though?
>>> parseInput("eval", 'eval(compile("print \'Code injection?\'","","single"))')
Code injection?
does this do what you expect? Unless you explicitly want this, you need to do something to prevent untrustworthy inputs from poking about in your namespace. I'd strongly recommend a simple whitelist, gracefully raising some sort of exception in the case of invalid input, like so:
import __builtin__
def parseInput(typename, value):
return {"int":int, "float":float, "str":str}[typename](value)
but if you just can't bear that, you can still add just a bit of armor by verifying that the requested function is actually a type:
import __builtin__
def parseInput(typename, value):
typector = getattr(__builtins__,typename)
if type(typector) is type:
return typector(value)
else:
return None
Upvotes: 2
Reputation: 19165
You've already gotten a solution using builtins, but another worthwhile technique to hold in your toolbag is a dispatch table. If your CSV is designed to be used by multiple applications written in multiple languages, it might look like this:
Integer,15
String,34
Float,1.0
Integer,8
In such a case you might want something like this, where csv
is a list of tuples containing the data above:
mapping = {
'Integer': int,
'String': str,
'Float': float,
'Unicode': unicode
}
results = []
for row in csv:
datatype = row[0]
val_string = row[1]
results.append(mapping[datatype](val_string))
return results
That gives you the flexibility of allowing arbitrary strings to map to useful types. You don't have to massage your data to give you the exact values python expects.
Upvotes: 7
Reputation: 410942
The issue here is that int
is part of the __builtins__
module, not just part of the global namespace. You can get a built-in type, such as int
, using the following bit of code:
int_gen = getattr(globals()["__builtins__"], "int")
i = int_gen(4)
# >>> i = 4
Similarly, you can access any other (imported) module by passing the module's name as a string index to globals()
, and then using getattr
to extract the desired attributes.
Upvotes: 2
Reputation: 375744
If you have a string that is the name of a thing, and you want the thing, you can also use:
thing = 'int'
eval(thing)
Keep in mind though, that this is very powerful, and you need to understand what thing might contain, and where it came from. For example, if you accept user input as thing, a malicious user could do unlimited damage to your machine with this code.
Upvotes: 1
Reputation: 880269
There are locals,globals, and then builtins. Perhaps you are looking for the builtin:
import __builtin__
getattr(__builtin__,'int')
Upvotes: 12