Лексическое литье из строки в тип
В последнее время я пытался хранить и читать информацию из файлов в Python и сталкивался с небольшой проблемой: мне хотелось прочитать информацию о типе из текстовых файлов. Тип casting от string до int или float довольно эффективен, но тип casting из строки в тип кажется еще одной проблемой. Естественно, я попробовал что-то вроде этого:
var_type = type('int')
Однако type
не используется как литой, а как механизм для поиска типа переменной, которая на самом деле str
здесь.
Я нашел способ сделать это с помощью:
var_type = eval('int')
Но я вообще стараюсь избегать функций/операторов типа eval
или exec
, где могу. Поэтому мой вопрос заключается в следующем: существует ли еще один питонический (и более конкретный) способ передать строку в тип?
Ответы
Ответ 1
Мне нравится использовать locate
, который работает со встроенными типами:
>>> from pydoc import locate
>>> locate('int')
<type 'int'>
>>> t = locate('int')
>>> t('1')
1
... а также все, что может найти в пути:
>>> locate('datetime.date')
<type 'datetime.date'>
>>> d = locate('datetime.date')
>>> d(2015, 4, 23)
datetime.date(2015, 4, 23)
... включая ваши пользовательские типы:
>>> locate('mypackage.model.base.BaseModel')
<class 'mypackage.model.base.BaseModel'>
>>> m = locate('mypackage.model.base.BaseModel')
>>> m()
<mypackage.model.base.BaseModel object at 0x1099f6c10>
Ответ 2
Вы немного смущены тем, что вы пытаетесь сделать. Типы, также известные как классы, являются объектами, как и все остальное в python. Когда вы пишете int
в своих программах, вы ссылаетесь на глобальную переменную с именем int
, которая является классом. То, что вы пытаетесь сделать, это не "лить строку для ввода", она обращается к встроенным переменным по имени.
Как только вы это понимаете, решение легко увидеть:
def get_builtin(name):
return getattr(__builtins__, name)
Если вы действительно хотели превратить имя типа в объект типа, вот как вы это сделаете. Я использую deque
, чтобы выполнить обход дерева по ширине без рекурсии.
def gettype(name):
from collections import deque
# q is short for "queue", here
q = deque([object])
while q:
t = q.popleft()
if t.__name__ == name:
return t
else:
print 'not', t
try:
# Keep looking!
q.extend(t.__subclasses__())
except TypeError:
# type.__subclasses__ needs an argument, for whatever reason.
if t is type:
continue
else:
raise
else:
raise ValueError('No such type: %r' % name)
Ответ 3
Почему бы просто не использовать справочную таблицу?
known_types = {
'int': int,
'float': float,
'str': str
# etc
}
var_type = known_types['int']
Ответ 4
Возможно, это то, что вы хотите, оно смотрит только на встроенные типы:
def gettype(name):
t = getattr(__builtins__, name)
if isinstance(t, type):
return t
raise ValueError(name)