Вызов типов через их имя в виде строки в Python - PullRequest
5 голосов
/ 30 октября 2009

Мне известно об использовании globals (), locals () и getattr для ссылки на вещи в Python по строке (как в этот вопрос ), но если я не пропущу что-то очевидное, я не могу показаться использовать это с типами вызовов.

например:.

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')...

Какой лучший способ сделать это?

Ответы [ 6 ]

12 голосов
/ 30 октября 2009

Есть местные, глобальные, а затем и встроенные. Возможно, вы ищете встроенный:

import __builtin__
getattr(__builtin__,'int')
7 голосов
/ 30 октября 2009

Вы уже получили решение с использованием встроенных функций, но еще одна полезная техника, которую можно хранить в вашей сумке для инструментов, - это таблица диспетчеризации. Если ваш CSV предназначен для использования несколькими приложениями, написанными на нескольких языках, он может выглядеть следующим образом:

Integer,15
String,34
Float,1.0
Integer,8

В таком случае вы можете захотеть что-то вроде этого, где csv - это список кортежей, содержащих данные выше:

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

Это дает вам гибкость, позволяя произвольным строкам отображаться на полезные типы. Вам не нужно обрабатывать данные, чтобы получить точные значения, ожидаемые Python.

3 голосов
/ 30 октября 2009
getattr(__builtins__,'int')
2 голосов
/ 31 октября 2009

Комментарии свидетельствуют о том, что вы недовольны идеей использования eval для генерации данных. поиск функции в __builtins__ позволяет найти eval.

самое простое решение выглядит следующим образом:

import __builtin__

def parseInput(typename, value):
    return getattr(__builtins__,typename)(value)

Вы бы использовали это так:

>>> parseInput("int", "123")
123

прохладный. работает довольно хорошо. а как насчет этого?

>>> parseInput("eval", 'eval(compile("print \'Code injection?\'","","single"))')
Code injection?

делает ли это то, что вы ожидаете? Если вы явно не хотите этого, вам нужно что-то сделать, чтобы предотвратить ненадежные входные данные в вашем пространстве имен. Я бы настоятельно рекомендовал простой белый список, изящно вызывающий какое-то исключение в случае неправильного ввода, например:

import __builtin__

def parseInput(typename, value):
    return {"int":int, "float":float, "str":str}[typename](value)

но если вы просто не можете этого вынести, вы все равно можете добавить немного брони, проверив, что запрошенная функция действительно является типом:

import __builtin__

def parseInput(typename, value):
    typector = getattr(__builtins__,typename)
    if type(typector) is type:
        return typector(value)
    else:
        return None
2 голосов
/ 30 октября 2009

Проблема в том, что int является частью модуля __builtins__, а не только частью глобального пространства имен. Вы можете получить встроенный тип, такой как int, используя следующий бит кода:

int_gen = getattr(globals()["__builtins__"], "int")
i = int_gen(4)
# >>> i = 4

Аналогично, вы можете получить доступ к любому другому (импортированному) модулю, передав имя модуля в виде строкового индекса в globals(), а затем используя getattr, чтобы извлечь нужные атрибуты.

1 голос
/ 30 октября 2009

Если у вас есть строка, которая является названием вещи, и вы хотите эту вещь, вы также можете использовать:

thing = 'int'
eval(thing)

Имейте в виду, однако, что это очень мощно, и вам нужно понять, что может содержать вещь и откуда она взялась. Например, если вы принимаете пользовательский ввод как вещь, злоумышленник может нанести неограниченный ущерб вашей машине с помощью этого кода.

...