Как проверить, является ли объект объектом-генератором в python?
В Python, как проверить, является ли объект объектом-генератором?
Пробую это -
>>> type(myobject, generator)
выдает ошибку -
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'generator' is not defined
(Я знаю, что могу проверить, есть ли у объекта next
метод для него, чтобы быть генератором, но я хочу какой-то способ, с помощью которого я могу определить тип любого объекта, а не только генераторы.)
11 ответов
Вы можете использовать GeneratorType из типов:
>>> import types
>>> types.GeneratorType
<class 'generator'>
>>> gen = (i for i in range(10))
>>> isinstance(gen, types.GeneratorType)
True
Вы имеете в виду функции генератора? использование inspect.isgeneratorfunction
,
РЕДАКТИРОВАТЬ:
если вам нужен объект генератора, вы можете использовать inspect.isgenerator, как указал JAB в своем комментарии.
Я думаю, что важно проводить различие между функциями генератора и генераторами (результат функции генератора):
>>> def generator_function():
... yield 1
... yield 2
...
>>> import inspect
>>> inspect.isgeneratorfunction(generator_function)
True
Вызов generator_function не даст нормального результата, он даже не выполнит никакого кода в самой функции, результатом будет специальный объект, называемый generator:
>>> generator = generator_function()
>>> generator
<generator object generator_function at 0x10b3f2b90>
так что это не функция генератора, а генератор:
>>> inspect.isgeneratorfunction(generator)
False
>>> import types
>>> isinstance(generator, types.GeneratorType)
True
и функция генератора не является генератором:
>>> isinstance(generator_function, types.GeneratorType)
False
просто для справки, фактический вызов тела функции будет происходить при использовании генератора, например:
>>> list(generator)
[1, 2]
Смотрите также В Python есть ли способ проверить, является ли функция "генератором", прежде чем вызывать ее?
inspect.isgenerator
Функция в порядке, если вы хотите проверить чистые генераторы (т.е. объекты класса "генератор"). Однако это вернется False
если вы проверите, например, izip
итерация. Альтернативный способ проверки обобщенного генератора - использовать эту функцию:
def isgenerator(iterable):
return hasattr(iterable,'__iter__') and not hasattr(iterable,'__len__')
Вы можете использовать Итератор или, более конкретно, Генератор из модуля набора текста.
from typing import Generator, Iterator
g = (i for i in range(1_000_000))
print(type(g))
print(isinstance(g, Generator))
print(isinstance(g, Iterator))
результат:
<class 'generator'>
True
True
(Я знаю, что это старый пост.) Нет необходимости импортировать модуль, вы можете объявить объект для сравнения в начале программы:
gentyp= type(1 for i in "")
...
type(myobject) == gentyp
>>> import inspect
>>>
>>> def foo():
... yield 'foo'
...
>>> print inspect.isgeneratorfunction(foo)
True
Если вы используете веб-сервер Tornado или аналогичный, вы можете обнаружить, что методы сервера на самом деле являются генераторами, а не методами. Это затрудняет вызов других методов, так как yield не работает внутри метода, и поэтому вам нужно начать управлять пулами связанных объектов-генераторов. Простой способ управления пулами связанных генераторов состоит в создании вспомогательной функции, такой как
def chainPool(*arg):
for f in arg:
if(hasattr(f,"__iter__")):
for e in f:
yield e
else:
yield f
Теперь пишу цепочечные генераторы, такие как
[x for x in chainPool(chainPool(1,2),3,4,chainPool(5,chainPool(6)))]
Производит вывод
[1, 2, 3, 4, 5, 6]
Что, вероятно, то, что вы хотите, если вы хотите использовать генераторы в качестве альтернативы потока или подобного.
Я знаю, что могу проверить, есть ли у объекта следующий метод, чтобы он был генератором, но мне нужен какой-то способ, с помощью которого я могу определить тип любого объекта, а не только генераторов.
Не делай этого. Это просто очень, очень плохая идея.
Вместо этого сделайте это:
try:
# Attempt to see if you have an iterable object.
for i in some_thing_which_may_be_a_generator:
# The real work on `i`
except TypeError:
# some_thing_which_may_be_a_generator isn't actually a generator
# do something else
В маловероятном случае, что тело цикла for также имеет TypeError
s, есть несколько вариантов: (1) определить функцию для ограничения объема ошибок или (2) использовать вложенный блок try.
Или (3) что-то вроде этого, чтобы различать все эти TypeError
с, которые плавают вокруг.
try:
# Attempt to see if you have an iterable object.
# In the case of a generator or iterator iter simply
# returns the value it was passed.
iterator = iter(some_thing_which_may_be_a_generator)
except TypeError:
# some_thing_which_may_be_a_generator isn't actually a generator
# do something else
else:
for i in iterator:
# the real work on `i`
Или (4) исправьте другие части вашего приложения, чтобы обеспечить генераторы соответствующим образом. Это часто проще, чем все это.
Это немного старый вопрос, однако я искал подобное решение для себя, но для класса асинхронного генератора, так что вы можете найти это полезным.
На основании ответа user472416 :
import types
isinstance(async_generator(), types.AsyncGeneratorType)
Этот тест, кажется, работает, по крайней мере, для примера, который я пытался:
str(type(object))=="<class 'generator'>"