วิธีการตรวจสอบว่าวัตถุเป็นวัตถุกำเนิดในหลาม?


157

ในไพ ธ อนฉันจะตรวจสอบได้อย่างไรว่าวัตถุเป็นวัตถุกำเนิด?

ลองนี้ -

>>> type(myobject, generator)

ให้ข้อผิดพลาด -

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

(ฉันรู้ว่าฉันสามารถตรวจสอบว่าวัตถุมีnextวิธีการที่จะเป็นตัวสร้างหรือไม่ แต่ฉันต้องการวิธีการใช้ซึ่งฉันสามารถกำหนดประเภทของวัตถุใด ๆ ไม่ใช่แค่กำเนิด)


4
คุณกำลังพยายามแก้ไขปัญหาอะไรที่แท้จริง โพสต์บริบทเพิ่มเติมอาจมีวิธีที่ฉลาดกว่า ทำไมคุณต้องรู้ว่ามันเป็นเครื่องกำเนิดไฟฟ้าหรือไม่?
Daenyth

7
from types import GeneratorType;type(myobject, GeneratorType)จะให้ผลลัพธ์ที่เหมาะสมสำหรับวัตถุของ 'generator' ของคลาส แต่เมื่อ Daenyth บอกเป็นนัยว่าไม่จำเป็นต้องไปทางที่ถูกต้อง
JAB

7
หากคุณกำลังตรวจสอบอยู่แสดง__next__ว่าคุณยอมรับการทำซ้ำใด ๆ ไม่ใช่แค่เครื่องกำเนิดไฟฟ้าซึ่งเป็นไปได้มากว่าคุณต้องการ

2
บ่อยครั้งที่จุดที่แท้จริงของการรู้ว่ามีบางสิ่งบางอย่างที่เป็นเครื่องกำเนิดไฟฟ้าที่จะสามารถหลีกเลี่ยงพวกเขาเพราะต้องการที่จะย้ำมากกว่าคอลเลกชันเดียวกันหลายครั้ง
เอียน

2
สำหรับคนที่สงสัยเกี่ยวกับการใช้กรณีนี้อาจจะมีประโยชน์เมื่อคุณต้องการที่จะรู้ว่าถ้า iterator จะถูกบริโภค (เช่นถ้าฟังก์ชั่นของคุณยอมรับ iterator ใด ๆ แต่ความต้องการที่จะทำซ้ำมากกว่าหนึ่งครั้งคุณจะต้องเป็นรูปธรรมก่อนที่จะทำซ้ำ)
wbadart

คำตอบ:


227

คุณสามารถใช้ GeneratorType จากประเภท:

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

5
น่าเสียดายที่นี่ใช้ไม่ได้กับคลาสตัวสร้าง (ตัวอย่างเช่นแผนที่หรือตัวกรองวัตถุ)
Ricardo Cruz

อาจisinstance(gen, (types.GeneratorType, map, filter))เป็นประโยชน์ในการตรวจจับmapและfilterด้วย สิ่งนี้จะยังไม่รวม iterables และ iterators อื่น ๆ
jlh

38

คุณหมายถึงฟังก์ชั่นเครื่องกำเนิด? inspect.isgeneratorfunctionใช้

แก้ไข:

ถ้าคุณต้องการให้วัตถุเครื่องกำเนิดไฟฟ้าคุณสามารถใช้inspect.isgeneratorตามที่ JAB ชี้ในความคิดเห็นของเขา


1
ฟังก์ชั่นเครื่องกำเนิดไฟฟ้าไม่ได้เป็นวัตถุกำเนิด ดูคำตอบของ @ utdemir
Piotr Findeisen

5
@Piotr: inspect.isgeneratorกรณีที่คุณใช้ใน
JAB

@JAB, @Piotr: สะท้อนไปยังที่อยู่เป็นไปได้ทั้งหมดของสิ่งที่ OP อาจหมายถึงขอบคุณ JAB :)
mouad

1
หมายเหตุ: หากคุณต้องการเพียงการทดสอบนี้คุณสามารถหลีกเลี่ยงค่าใช้จ่ายเล็ก ๆ โดยใช้@utdemirแก้ปัญหาเพราะเป็นเพียงการจดชวเลขไป:inspect.isgenerator isinstance(object, types.GeneratorType)
bufh

ดู @RobertLujo คำตอบสำหรับความแตกต่างระหว่างวัตถุกำเนิดและฟังก์ชั่นเครื่องกำเนิด stackoverflow.com/a/32380774/3595112
industryworker3595112

24

ฉันคิดว่ามันสำคัญที่จะต้องสร้างความแตกต่างระหว่างฟังก์ชั่นเครื่องกำเนิดและเครื่องกำเนิด (ผลลัพธ์ของฟังก์ชั่นเครื่องกำเนิด):

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

โทร generator_function จะไม่เกิดผลปกติมันก็จะไม่ได้รันโค้ดใด ๆ ในการทำงานของตัวเองผลจะเป็นวัตถุพิเศษที่เรียกว่าเครื่องกำเนิดไฟฟ้า :

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

ดูเพิ่มเติมในงูหลามมีวิธีการตรวจสอบว่าฟังก์ชั่นเป็น "เครื่องกำเนิดไฟฟ้าฟังก์ชั่น" ก่อนที่จะเรียกมันได้หรือไม่


11

inspect.isgeneratorฟังก์ชั่นปรับถ้าคุณต้องการที่จะตรวจสอบการกำเนิดบริสุทธิ์ (เช่นวัตถุของคลาส "กำเนิด") อย่างไรก็ตามมันจะกลับมาFalseถ้าคุณตรวจสอบเช่นizipiterable อีกทางเลือกหนึ่งสำหรับการตรวจสอบเครื่องกำเนิดไฟฟ้าทั่วไปคือการใช้ฟังก์ชั่นนี้:

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

1
อืมมม x=iter([1,2])นี้กลับมาจริง ดูเหมือนว่าฉันกำลังทดสอบว่าวัตถุนั้นเป็นตัววนซ้ำไม่ใช่ตัวกำเนิดหรือไม่ แต่บางที "iterator" เป็นสิ่งที่คุณหมายถึงโดย "เครื่องกำเนิดทั่วไป"
Josh O'Brien

3

คุณสามารถใช้ Iterator หรือเฉพาะเจาะจงมากขึ้นเครื่องสร้างจากโมดูลการพิมพ์

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

1
+1 สำหรับวิธีการทำงาน สิ่งนี้ถูกกล่าวว่าเอกสารสำหรับtyping.TypeVarชั้นเรียนดูเหมือนจะกีดกันการใช้งานisinstanceร่วมกับtypingโมดูล: "ที่รันไทม์isinstance(x, T)จะเพิ่มขึ้นTypeErrorโดยทั่วไปแล้วisinstance()และissubclass()ไม่ควรใช้กับประเภท"
Jasha

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

มันจะทำงานได้ก็ต่อเมื่อมันเป็นฟังก์ชั่น ถ้า 'foo' เป็นวัตถุของตัวสร้างมันจะแสดง 'เท็จ' ดูคำถามของฉันฉันต้องการตรวจสอบวัตถุเครื่องกำเนิดไฟฟ้า
Pushpak Dagade

2

ฉันรู้ว่าฉันสามารถตรวจสอบว่าวัตถุนั้นมีวิธีการถัดไปเพื่อให้เป็นตัวสร้างหรือไม่ แต่ฉันต้องการวิธีการใช้ที่ฉันสามารถกำหนดประเภทของวัตถุใด ๆ ไม่ใช่แค่กำเนิด

อย่าทำอย่างนี้ มันเป็นความคิดที่แย่มาก ๆ

ให้ทำสิ่งนี้แทน:

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 loop ยังมีTypeErrors มีหลายตัวเลือก: (1) กำหนดฟังก์ชันเพื่อ จำกัด ขอบเขตของข้อผิดพลาดหรือ (2) ใช้บล็อกลองแบบซ้อน

หรือ (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) แก้ไขส่วนอื่น ๆ ของแอปพลิเคชันของคุณเพื่อให้เครื่องกำเนิดไฟฟ้าเหมาะสม ซึ่งมักจะง่ายกว่าทั้งหมดนี้


1
โซลูชันของคุณจะตรวจจับ TypeErrors ที่ถูกโยนโดยเนื้อความของ for loop ฉันเสนอการแก้ไขที่จะป้องกันพฤติกรรมที่ไม่พึงประสงค์นี้
Dunes

นี่เป็นวิธี Pythonic มากขึ้นของการทำมันถ้าฉันไม่ผิด
JAB

ถึงแม้ว่าหากคุณกำลังวนซ้ำรายการสิ่งของและมากกว่านั้นไม่ใช่ตัววนซ้ำมากกว่าตัววนซ้ำแล้วอาจใช้เวลานานกว่านี้ใช่ไหม
Jakob Bowyer

1
@Jakob Bowyer: ข้อยกเว้นเร็วกว่าifข้อความสั่ง และ. การเพิ่มประสิทธิภาพขนาดเล็กแบบนั้นเป็นการเสียเวลา แก้ไขอัลกอริทึมที่ผลิตถุงผสมของตัววนซ้ำและไม่ใช่ตัววนซ้ำเพื่อผลิตเฉพาะตัววนซ้ำและช่วยรักษาความเจ็บปวดทั้งหมดนี้ให้ตัวคุณเอง
S.Lott

10
นี่จะถือว่าผิดพลาดใด ๆ ที่ทำซ้ำเป็นเครื่องกำเนิดไฟฟ้า
balki

1

หากคุณใช้เว็บเซิร์ฟเวอร์ทอร์นาโดหรือที่คล้ายกันคุณอาจพบว่าวิธีการเซิร์ฟเวอร์เป็นเครื่องกำเนิดไฟฟ้าและไม่ใช่วิธีการ สิ่งนี้ทำให้ยากต่อการเรียกใช้วิธีการอื่นเนื่องจากผลผลิตไม่ทำงานภายในวิธีการและดังนั้นคุณต้องเริ่มจัดการกลุ่มของวัตถุตัวกำเนิดที่ถูกล่ามโซ่ วิธีง่าย ๆ ในการจัดการกลุ่มของเครื่องกำเนิดไฟฟ้าแบบโซ่คือการสร้างฟังก์ชั่นช่วยเหลือเช่น

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]

ซึ่งอาจเป็นสิ่งที่คุณต้องการหากคุณต้องการใช้เครื่องกำเนิดไฟฟ้าเป็นทางเลือกด้ายหรือคล้ายกัน


1

(ฉันรู้ว่ามันเป็นโพสต์เก่า) ไม่จำเป็นต้องนำเข้าโมดูลคุณสามารถประกาศวัตถุเพื่อเปรียบเทียบที่จุดเริ่มต้นของโปรแกรม:

gentyp= type(1 for i in "")                                                                                          
       ...
type(myobject) == gentyp
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.