Bir nesnenin python'da bir jeneratör nesnesi olup olmadığı nasıl kontrol edilir?


157

Python'da, bir nesnenin bir jeneratör nesnesi olup olmadığını nasıl kontrol edebilirim?

Bunu deniyorum -

>>> type(myobject, generator)

hata veriyor -

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'generator' is not defined

(Nesnenin nextbir jeneratör olması için bir yöntemi olup olmadığını kontrol edebileceğimi biliyorum , ancak sadece jeneratörleri değil, herhangi bir nesnenin türünü belirleyebileceğim bir yol istiyorum.)


4
Hangi gerçek sorunu çözmeye çalışıyorsunuz? Daha fazla içerik yayınlayın, daha akıllı bir yol olabilir. Bir jeneratör olup olmadığını neden bilmeniz gerekiyor?
Daenyth

7
from types import GeneratorType;type(myobject, GeneratorType)'jeneratör' sınıfı nesneler için doğru sonucu verecektir. Ancak Daenyth'in ifade ettiği gibi, bu mutlaka doğru yol değildir.
JAB

7
Eğer kontrol ediyorsanız __next__, sadece jeneratörleri değil, herhangi bir yineleyiciyi kabul ediyorsunuz - ki bu muhtemelen istediğiniz şeydir.

2
Sıklıkla, bir şeyin jeneratör olup olmadığını bilmenin asıl amacı, aynı koleksiyon üzerinde birden çok kez yineleme isteğinden dolayı onlardan kaçınabilmektir.
Ian

2
Kullanım durumunu merak eden insanlar için, yineleyicinin tüketilip tüketilmeyeceğini bilmeniz gerektiğinde yararlı olabilir (örneğin, işleviniz herhangi bir yineleyiciyi kabul eder, ancak bir kereden fazla yineleme gerekiyorsa, yinelemeden önce bunu gerçekleştirmek istersiniz)
wbadart

Yanıtlar:


227

GeneratorType'ı aşağıdaki türlerden kullanabilirsiniz:

>>> import types
>>> types.GeneratorType
<class 'generator'>
>>> gen = (i for i in range(10))
>>> isinstance(gen, types.GeneratorType)
True

5
Bu maalesef jeneratör sınıfları için geçerli değildir (örneğin, nesneleri eşleme veya filtreleme).
Ricardo Cruz

Belki isinstance(gen, (types.GeneratorType, map, filter))de mapve tespit etmek için yararlıdır filter. Bu yine de diğer yinelemeleri ve yineleyicileri içermeyecektir.
jlh

38

Jeneratör fonksiyonları mı demek istiyorsun? kullanın inspect.isgeneratorfunction.

DÜZENLE :

Bir jeneratör nesnesi istiyorsanız, yorumunda JAB'ın işaret ettiği gibi inspect.isgenerator kullanabilirsiniz .


1
jeneratör işlevi jeneratör nesnesi değildir; @ utdemir'in cevabına bakınız
Piotr Findeisen

5
@Piotr: Bu durumda kullanırsınız inspect.isgenerator.
JAB

@JAB, @Piotr: OP'nin ne anlama gelebileceğinin tüm olasılıklarına hitap etmek için yansıtıldı, teşekkürler JAB :)
mouad

1
Not: Yalnızca bu testi gerekiyorsa, kullanarak küçük bir yükü önleyebilirsiniz @utdemir çözüm çünkü inspect.isgeneratorsadece bir kısaltmadır şudur: isinstance(object, types.GeneratorType).
bufh

Jeneratör nesnesi ve jeneratör fonksiyonu arasındaki ayrım için @RobertLujo cevabına bakınız. stackoverflow.com/a/32380774/3595112
industryworker3595112

24

Jeneratör fonksiyonları ve jeneratörler (jeneratör fonksiyonunun sonucu) arasında ayrım yapmak önemli olduğunu düşünüyorum :

>>> def generator_function():
...     yield 1
...     yield 2
...
>>> import inspect
>>> inspect.isgeneratorfunction(generator_function)
True

generator_function çağrısı normal sonuç vermez, hatta işlevin kendisinde herhangi bir kod yürütmez, sonuç jeneratör adlı özel nesne olacaktır :

>>> generator = generator_function()
>>> generator
<generator object generator_function at 0x10b3f2b90>

yani jeneratör işlevi değil, jeneratör:

>>> inspect.isgeneratorfunction(generator)
False

>>> import types
>>> isinstance(generator, types.GeneratorType)
True

ve jeneratör işlevi jeneratör değildir:

>>> isinstance(generator_function, types.GeneratorType)
False

sadece referans için, fonksiyon gövdesinin gerçek çağrısı jeneratörü tüketerek gerçekleşir, örneğin:

>>> list(generator)
[1, 2]

Ayrıca bkz . Python'da çağırmadan önce bir fonksiyonun "jeneratör fonksiyonu" olup olmadığını kontrol etmenin bir yolu var mı?


11

inspect.isgeneratorSaf üreteçleri (yani, "üreteç" sınıfındaki nesneleri) kontrol etmek istiyorsanız, bu fonksiyon iyidir. Ancak False, örneğin, bir izipyinelenebilir kontrol ederseniz dönecektir. Genelleştirilmiş bir jeneratörü kontrol etmenin alternatif bir yolu, bu işlevi kullanmaktır:

def isgenerator(iterable):
    return hasattr(iterable,'__iter__') and not hasattr(iterable,'__len__')

1
Hmm. Bu, için true değerini döndürür x=iter([1,2]). Bana öyle geliyor ki, bir nesnenin bir jeneratör değil , bir yineleyici olup olmadığını test ediyor . Ama belki "yineleyici" tam olarak "jenerasyon jeneratörü" ile kastettiğiniz şeydir.
Josh O'Brien

3

Yazma modülünden Yineleyici veya daha özel olarak Jeneratör kullanabilirsiniz .

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

sonuç:

<class 'generator'>
True
True

1
Çalışan bir çözüm için +1. Bununla birlikte , typing.TypeVarsınıf dokümanları modül isinstanceile birlikte kullanımını engellemektedir typing: "Çalışma zamanında, isinstance(x, T)yükselecektir TypeError. Genel olarak isinstance()ve issubclass()türlerle kullanılmamalıdır."
Jasha

2
>>> import inspect
>>> 
>>> def foo():
...   yield 'foo'
... 
>>> print inspect.isgeneratorfunction(foo)
True

Bu yalnızca bir işlevse çalışır. 'Foo' bir jeneratör nesnesiyse, 'False' değerini gösterir. Soruma bakın, jeneratör nesneleri için kontroller yapmak istiyorum.
Pushpak Dagade

2

Nesnenin bir jeneratör olması için bir sonraki yöntemi olup olmadığını kontrol edebilirsiniz biliyorum, ama ben sadece jeneratörleri değil, herhangi bir nesnenin türünü belirleyebilir kullanarak bir şekilde istiyorum.

Bunu yapma. Bu çok ama çok kötü bir fikir.

Bunun yerine şunu yapın:

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 döngüsünün gövdesinin de TypeErrors olması olası olmayan durumlarda, birkaç seçenek vardır: (1) hataların kapsamını sınırlamak için bir işlev tanımlayın veya (2) iç içe geçmiş bir try bloğu kullanın .

Veya (3) TypeErroretrafta yüzen tüm bu şeyleri ayırt etmek için böyle bir şey .

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`

Veya (4) jeneratörleri uygun şekilde sağlamak için uygulamanızın diğer kısımlarını sabitleyin. Bu genellikle tüm bunlardan daha basittir.


1
Çözümünüz, for döngüsünün gövdesi tarafından atılan TypeErrors'u yakalar. Bu istenmeyen davranışı önleyecek bir düzenleme önerdim.
Dunes

Eğer yanılmıyorsam, bu daha Pitonik bir yöntemdir.
JAB

Her ne kadar, bir öğe listesi üzerinde yineleme yapıyorsanız ve daha fazlası yineleyicilerden daha fazla yineleyici değilse, bu daha uzun sürebilir mi?
Jakob Bowyer

1
@ Jakob Bowyer: İstisnalar ifadelerden daha hızlıdır if. Ve. Bu tür bir mikro optimizasyon zaman kaybıdır. Sadece yineleyiciler üretmek ve tüm bu acıyı kurtarmak için karışık bir yineleyici ve yineleyici olmayan çanta üreten algoritmayı düzeltin.
S.Lott

10
Bu yanlışlıkla bir üreteç olarak yinelenebilir kabul edilir.
balki

1

Kasırga web sunucusu veya benzeri kullanıyorsanız, sunucu yöntemlerinin aslında yöntem değil, jeneratörler olduğunu fark etmiş olabilirsiniz. Bu, diğer yöntemlerin çağrılmasını zorlaştırır, çünkü verim yöntemin içinde çalışmaz ve bu nedenle zincirli jeneratör nesnelerinin havuzlarını yönetmeye başlamanız gerekir. Zincirleme jeneratörlerin havuzlarını yönetmenin basit bir yöntemi,

def chainPool(*arg):
    for f in arg:
      if(hasattr(f,"__iter__")):
          for e in f:
             yield e
      else:
         yield f

Şimdi zincirleme jeneratörler gibi

[x for x in chainPool(chainPool(1,2),3,4,chainPool(5,chainPool(6)))]

Çıktı üretir

[1, 2, 3, 4, 5, 6]

Bu, jeneratörleri iplik alternatifi veya benzeri olarak kullanmak istiyorsanız, muhtemelen istediğiniz şeydir.


1

(Eski bir yazı olduğunu biliyorum.) Bir modül almanıza gerek yok, programın başında karşılaştırma için bir nesne bildirebilirsiniz:

gentyp= type(1 for i in "")                                                                                          
       ...
type(myobject) == gentyp
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.