mavnn
mavnn

Reputation: 9469

Calling types via their name as a string in Python

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

Answers (6)

SingleNegationElimination
SingleNegationElimination

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

jcdyer
jcdyer

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

mipadi
mipadi

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

Ned Batchelder
Ned Batchelder

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

unutbu
unutbu

Reputation: 880269

There are locals,globals, and then builtins. Perhaps you are looking for the builtin:

import __builtin__
getattr(__builtin__,'int')

Upvotes: 12

Jonathan Feinberg
Jonathan Feinberg

Reputation: 45344

getattr(__builtins__,'int')

Upvotes: 3

Related Questions