কোনও জেনারেটর শুরু থেকে খালি থাকলে কীভাবে জানব?


146

সেখানে পরীক্ষা করে জেনারেটরের কোন আইটেম, মত হয়েছে একটি সহজ উপায় আছে কি peek, hasNext, isEmptyযারা লাইন বরাবর, কিছু?


আমি ভুল হলে আমাকে সংশোধন করুন, তবে আপনি যদি কোনও জেনারেটরের পক্ষে সত্যিই জেনেরিক সমাধান করতে পারেন তবে ফলন বিবৃতিতে ব্রেকপয়েন্ট নির্ধারণ করা এবং "পিছনে পিছনে" যাওয়ার ক্ষমতা থাকার সমতুল্য। এর অর্থ কি উত্পাদনের জন্য স্ট্যাক ফ্রেমকে ক্লোনিং করা এবং স্টপআইটারেশনে পুনরুদ্ধার করা উচিত?

ঠিক আছে, আমি তাদের স্টিপ ইন্টেরেশন পুনরুদ্ধার করব কিনা তা অনুমান করি তবে কমপক্ষে স্টপএইটরেশন আপনাকে বলবে যে এটি খালি ছিল। হাঁ আমি ঘুমের প্রয়োজন ...

4
আমি মনে করি আমি জানি কেন তিনি এটি চান। আপনি যদি টেমপ্লেটগুলি দিয়ে ওয়েব ডেভলপমেন্ট করছেন, এবং চিতা বা অন্য কোনও কিছুর মতো কোনও টেম্পলেটে ফেরতের মানটি প্রেরণ করছেন, খালি তালিকাটি []সুবিধামত ফ্যালসি রয়েছে যাতে আপনি এটি পরীক্ষা করে দেখতে পারেন এবং কিছু বা কিছুই না করার জন্য বিশেষ আচরণ করতে পারেন। জেনারেটরগুলি সত্য না হলেও তারা কোনও উপাদান না দেয়।
jpsimons

এখানে আমার ব্যবহারের কেস ... আমি glob.iglob("filepattern")ব্যবহারকারীর সরবরাহিত ওয়াইল্ডকার্ড প্যাটার্নটি ব্যবহার করছি এবং যদি প্যাটার্নটি কোনও ফাইলের সাথে মেলে না তবে আমি ব্যবহারকারীকে সতর্ক করতে চাই। অবশ্যই আমি এটিকে বিভিন্ন উপায়ে কাজ করতে পারি তবে পুনরাবৃত্তিটি খালি এসেছিল কিনা তা পরিষ্কার করে পরীক্ষা করতে সক্ষম হওয়াই দরকারী।
LarsH

হতে এই সমাধান ব্যবহার করুন: stackoverflow.com/a/11467686/463758
balki

উত্তর:


53

আপনার প্রশ্নের সহজ উত্তর: না, কোনও সহজ উপায় নেই। কাজের পুরো জায়গা রয়েছে।

জেনারেটরগুলি কী কারণে সত্যিকারের কোনও সহজ উপায় হওয়া উচিত নয়: মেমরিতে ক্রমটি ধরে না রেখে মানগুলির ক্রম আউটপুট করার একটি উপায় । সুতরাং পিছনে কোনও ট্র্যাভারসাল নেই।

আপনি একটি হাসি_নেক্সট ফাংশন লিখতে পারেন বা অভিনব সজ্জাকারীর সাথে একটি পদ্ধতি হিসাবে জেনারেটরের কাছে চাপ দিতে পারেন এমনকি যদি আপনি চান wanted


2
যথেষ্ট ন্যায্য, এটি বোঝার। আমি জানতাম যে জেনারেটরের দৈর্ঘ্য সন্ধানের কোনও উপায় নেই, তবে আমি ভেবেছিলাম যে এটি প্রাথমিকভাবে কিছুতেই উত্পন্ন করতে চলেছে কিনা তা খুঁজে পাওয়ার কোনও উপায় আমি হারিয়ে ফেলতে পারি।
ড্যান

1
ওহ, এবং রেফারেন্সের জন্য, আমি আমার নিজের "অভিনব সাজসজ্জা" পরামর্শ বাস্তবায়নের চেষ্টা করেছি। কঠিন। স্পষ্টতই কপি করুন.দীপকপি জেনারেটরগুলিতে কাজ করে না।
ডেভিড বার্গার

47
আমি নিশ্চিত না যে আমি "একটি সহজ উপায় হওয়া উচিত নয়" এর সাথে একমত হতে পারি। কম্পিউটার সায়েন্সে প্রচুর বিমূর্ততা রয়েছে যা মেমোরিতে ক্রম না রেখে মানগুলির ক্রমকে আউটপুট করার জন্য ডিজাইন করা হয়েছে, তবে প্রোগ্রামার যদি এটি জিজ্ঞাসা করতে দেয় যে সেখানে "সারি" থেকে অপসারণ না করে অন্য মান আছে কিনা। "পশ্চাদপদ ট্র্যাভারসাল" প্রয়োজন ছাড়াই একক পিক-ফরোয়ার্ডের মতো জিনিস রয়েছে। এটি বলার অপেক্ষা রাখে না যে একটি পুনরুক্তি নকশা অবশ্যই এই জাতীয় বৈশিষ্ট্য সরবরাহ করতে পারে তবে এটি অবশ্যই কার্যকর। হতে পারে আপনি সেই ভিত্তিতে আপত্তি করছেন যে উঁকি দেওয়ার পরে প্রথম মানটি পরিবর্তিত হতে পারে?
LarsH

9
আমি এই কারণগুলিতে আপত্তি করছি যে একটি সাধারণ বাস্তবায়ন এমনকি প্রয়োজনের আগ পর্যন্ত কোনও মান গণনা করে না। কেউ ইন্টারফেসটিকে এটি করতে বাধ্য করতে পারে তবে এটি লাইটওয়েট বাস্তবায়নের জন্য সাব-অনুকূল হতে পারে।
ডেভিড বার্গার

6
@ এস লট আপনার ক্রমটি খালি আছে কিনা তা জানতে পুরো ক্রমটি তৈরি করার দরকার নেই। একটি উপাদান স্টোরেজ মূল্য যথেষ্ট - আমার উত্তর দেখুন।
মার্ক রান্সম

98

প্রস্তাবনা:

def peek(iterable):
    try:
        first = next(iterable)
    except StopIteration:
        return None
    return first, itertools.chain([first], iterable)

ব্যবহার:

res = peek(mysequence)
if res is None:
    # sequence is empty.  Do stuff.
else:
    first, mysequence = res
    # Do something with first, maybe?
    # Then iterate over the sequence:
    for element in mysequence:
        # etc.

2
আমি প্রথম উপাদানটি দু'বারে ফিরে আসার মত বিন্দুটি পাই না return first, itertools.chain([first], rest)
njzk2

6
@ njzk2 আমি একটি "পিক" অপারেশন করতে যাচ্ছিলাম (সুতরাং ফাংশনটির নাম)। উইকি "পিক হ'ল একটি অপারেশন যা তথ্য থেকে মান সরিয়ে না দিয়ে সংগ্রহের শীর্ষের মান প্রদান করে"
জন ফুহি

জেনারেটরটি কোনওটি উত্পাদন করার জন্য ডিজাইন করা থাকলে এটি কাজ করবে না। def gen(): for pony in range(4): yield None if pony == 2 else pony
পল

4
@ পল রিটার্নের মানগুলি নিবিড়ভাবে দেখুন। যদি জেনারেটরটি করা হয় - অর্থাত্ ফিরে না আসা None, তবে উত্থাপন StopIteration- ফাংশনের ফলাফল None। অন্যথায়, এটি একটি টিপল, যা হয় না None
তহবিল মনিকার লসুইট

এটি আমার বর্তমান প্রকল্পে আমাকে অনেক সহায়তা করেছে। পাইথনের স্ট্যান্ডার্ড লাইব্রেরি মডিউল 'মেলবক্স.পি' এর কোডে আমি একই ধরণের উদাহরণ পেয়েছি। This method is for backward compatibility only. def next(self): """Return the next message in a one-time iteration.""" if not hasattr(self, '_onetime_keys'): self._onetime_keys = self.iterkeys() while True: try: return self[next(self._onetime_keys)] except StopIteration: return None except KeyError: continue
পিয়ার

29

একটি সহজ উপায় হ'ল পরবর্তী () এর জন্য alচ্ছিক প্যারামিটার ব্যবহার করা যা জেনারেটর নিঃশেষ হয়ে গেলে (বা খালি) ব্যবহার করা হয়। উদাহরণ স্বরূপ:

iterable = some_generator()

_exhausted = object()

if next(iterable, _exhausted) == _exhausted:
    print('generator is empty')

সম্পাদনা: মেহতুঙ্গুর মন্তব্যে চিহ্নিত সমস্যাটি সংশোধন করা হয়েছে।


1
না। এটি যে কোনও জেনারেটরের পক্ষে ভুল যেখানে প্রথম ফলনের মান অসত্য।
মেহতুঙ্গুহ

7
একটি ব্যবহার করুন object()পরিবর্তে classএটা এক লাইন খাটো করতে: _exhausted = object(); if next(iterable, _exhausted) is _exhausted:
মেসা 21'16

13

next(generator, None) is not None

বা প্রতিস্থাপন Noneকিন্তু যাই হোক না কেন মান আপনি কি জানেন এটা না আপনার জেনারেটরের হবে।

সম্পাদনা : হ্যাঁ, এটি জেনারেটরে 1 টি আইটেম এড়িয়ে যাবে। তবে প্রায়শই আমি যাচাই করি যে কোনও জেনারেটর কেবল বৈধতার উদ্দেশ্যে খালি রয়েছে, তবে সত্যই এটি ব্যবহার করবেন না। বা অন্যথায় আমি যেমন কিছু করি:

def foo(self):
    if next(self.my_generator(), None) is None:
        raise Exception("Not initiated")

    for x in self.my_generator():
        ...

যে এই কাজ করে আপনার যদি হয় জেনারেটরের একটি থেকে আসে ফাংশন হিসাবে, generator()


4
কেন এটি সেরা উত্তর নয়? জেনারেটর ফিরবে Noneকি?
Sait

8
সম্ভবত কারণ এটি আপনাকে খালি খালি পরীক্ষা করার পরিবর্তে জেনারেটরটি বাস্তবে গ্রাস করতে বাধ্য করে।
bfontaine

3
এটি খারাপ কারণ আপনি যে মুহুর্তে পরবর্তী কল করবেন (জেনারেটর, কিছুই নয়) আপনি যদি 1 টি উপলভ্য থাকে তবে আপনি এড়িয়ে যাবেন
নাথন

ঠিক আছে, আপনি আপনার জেনের প্রথম উপাদানটি মিস করতে চলেছেন এবং আপনি নিজের জেনের খালি খালি পরীক্ষা করার পরিবর্তে সেবন করতে যাচ্ছেন।
এজে

12

আইএমএইচওর সর্বোত্তম পন্থা হ'ল বিশেষ পরীক্ষা এড়ানো। বেশির ভাগ সময়ই, একটি জেনারেটর ব্যবহার হয় পরীক্ষা:

thing_generated = False

# Nothing is lost here. if nothing is generated, 
# the for block is not executed. Often, that's the only check
# you need to do. This can be done in the course of doing
# the work you wanted to do anyway on the generated output.
for thing in my_generator():
    thing_generated = True
    do_work(thing)

যদি এটি যথেষ্ট ভাল না হয় তবে আপনি এখনও একটি স্পষ্ট পরীক্ষা করতে পারেন। এই মুহুর্তে, thingউত্পাদিত শেষ মানটি থাকবে। যদি কিছু উত্পন্ন না হয় তবে এটি অপরিজ্ঞাত হবে - যদি না আপনি ইতিমধ্যে ভেরিয়েবলটি সংজ্ঞায়িত করেন। আপনি এর মান পরীক্ষা করতে পারেন thingতবে এটি কিছুটা বিশ্বাসযোগ্য নয়। পরিবর্তে, কেবলমাত্র ব্লকের মধ্যে একটি পতাকা সেট করুন এবং পরে এটি পরীক্ষা করুন:

if not thing_generated:
    print "Avast, ye scurvy dog!"

3
এই সমাধানটি পুরো জেনারেটরকে গ্রাস করার চেষ্টা করবে ফলে এটি অসীম জেনারেটরগুলির জন্য ব্যবহারযোগ্য নয়।
ভিক্টর স্টেস্কালা

@ ভিক্টর স্টকসালা: আপনার বক্তব্য আমি দেখছি না। যদি অসীম জেনারেটর কোনও ফলাফল দেয় তবে তা পরীক্ষা করা বোকামি হবে।
ভিজুল্ট

আমি উল্লেখ করতে চেয়েছিলাম যে আপনার সমাধানটিতে লুপের জন্য বিরতি থাকতে পারে, কারণ আপনি অন্যান্য ফলাফলগুলি প্রসেস করছেন না এবং এটি উত্পন্ন করার পক্ষে এটি অকেজো। range(10000000)সীমাবদ্ধ জেনারেটর (পাইথন 3), তবে এটি কিছু উত্পন্ন করে কিনা তা জানতে আপনাকে সমস্ত আইটেমের মধ্যে দিয়ে যাওয়ার প্রয়োজন হবে না।
ভিক্টর স্টেস্কালা

1
@ ভিক্টরস্টস্কালা: বোঝা গেছে। তবে আমার বক্তব্যটি হ'ল: সাধারণত, আপনি আসলে জেনারেটরের আউটপুটটিতে পরিচালনা করতে চান। আমার উদাহরণে, যদি কিছু উত্পন্ন না হয় তবে আপনি এখন এটি জানেন। অন্যথায়, আপনি উত্পন্ন আউটপুটটি উদ্দেশ্য হিসাবে পরিচালনা করেন - "জেনারেটরের ব্যবহার পরীক্ষা।" বিশেষ পরীক্ষার দরকার নেই, বা অর্থহীনভাবে জেনারেটরের আউটপুট গ্রাস করে। আমি এটি পরিষ্কার করতে আমার উত্তর সম্পাদনা করেছি।
ভিজুল্ট

8

আমি দ্বিতীয় সমাধানটি উপস্থাপন করতে ঘৃণা করি, বিশেষত এমন একটি যা আমি নিজেকে ব্যবহার করব না, তবে, যদি আপনাকে একেবারে এটি করতে হয় এবং জেনারেটরটি গ্রাস না করে, যেমন অন্য উত্তরে:

def do_something_with_item(item):
    print item

empty_marker = object()

try:
     first_item = my_generator.next()     
except StopIteration:
     print 'The generator was empty'
     first_item = empty_marker

if first_item is not empty_marker:
    do_something_with_item(first_item)
    for item in my_generator:
        do_something_with_item(item)

এখন আমি সত্যিই এই সমাধানটি পছন্দ করি না, কারণ আমি বিশ্বাস করি যে জেনারেটরগুলি কীভাবে ব্যবহার করা যায় তা এটি নয়।


4

আমি বুঝতে পারি যে এই পোস্টে এই মুহুর্তে 5 বছরের পুরানো, তবে এটি করার একটি অহঙ্কারী উপায়ের সন্ধান করার সময় আমি এটি খুঁজে পেয়েছি এবং আমার সমাধান পোস্ট করা দেখতে পেল না। উত্তরোত্তর জন্য:

import itertools

def get_generator():
    """
    Returns (bool, generator) where bool is true iff the generator is not empty.
    """
    gen = (i for i in [0, 1, 2, 3, 4])
    a, b = itertools.tee(gen)
    try:
        a.next()
    except StopIteration:
        return (False, b)
    return (True, b)

অবশ্যই, আমি নিশ্চিত যে অনেক ভাষ্যকার উল্লেখ করবেন, এটি হ্যাকি এবং শুধুমাত্র কিছু নির্দিষ্ট সীমিত পরিস্থিতিতে কাজ করে (যেখানে জেনারেটর পার্শ্ব-প্রতিক্রিয়া মুক্ত, উদাহরণস্বরূপ)। YMMV।


1
এটি genপ্রতিটি আইটেমের জন্য কেবল একবার জেনারেটরকে কল করবে , তাই পার্শ্ব-প্রতিক্রিয়া খুব বেশি সমস্যা নয়। তবে এটি জেনারেটর থেকে টানা সমস্ত কিছুর একটি অনুলিপি সংরক্ষণের মাধ্যমে সংরক্ষণ করবে b, তবে এটির মাধ্যমে নয় a, তাই মেমরির প্রভাবগুলি কেবল চলমান list(gen)এবং এটি যাচাইয়ের অনুরূপ ।
ম্যাথিয়াস ফ্রিপ

এটি দুটি সমস্যা আছে। 1. এই ইটারটোলের জন্য উল্লেখযোগ্য সহায়ক স্টোরেজ প্রয়োজন হতে পারে (অস্থায়ী ডেটা সংরক্ষণ করার জন্য কতটা প্রয়োজন তার উপর নির্ভর করে)। সাধারণভাবে, যদি কোনও পুনরাবৃত্তকারী অন্য পুনরুক্তি শুরু হওয়ার আগে যদি বেশিরভাগ বা সমস্ত ডেটা ব্যবহার করে তবে টি () এর পরিবর্তে তালিকা () ব্যবহার করা আরও দ্রুত। ২. টি পুনরুক্তিকারী থ্রেডসেফ নয়। মূল পুনরাবৃত্ত থ্রেডসেফ থাকলেও একই টি () কল দ্বারা একই সাথে পুনরাবৃত্তি পুনরাবৃত্তি ব্যবহার করার সময় একটি রানটাইমরর উত্থাপিত হতে পারে।
এজে

3

সুস্পষ্ট পদ্ধতির জন্য দুঃখিত, তবে সর্বোত্তম উপায়টি হ'ল:

for item in my_generator:
     print item

এখন আপনি সনাক্ত করেছেন যে জেনারেটরটি এটি ব্যবহার করার সময় খালি রয়েছে। অবশ্যই, জেনারেটর খালি থাকলে আইটেমটি কখনই প্রদর্শিত হবে না।

এটি আপনার কোডের সাথে পুরোপুরি ফিট নাও হতে পারে তবে জেনারেটরের আইডিয়ামটি এটির জন্য: পুনরাবৃত্তি হওয়া, যাতে সম্ভবত আপনি আপনার পদ্ধতির সামান্য পরিবর্তন করতে পারেন, বা জেনারেটরগুলি মোটেও ব্যবহার না করেন।


বা ... প্রশ্নকারী কেন একটি খালি জেনারেটর সনাক্ত করার চেষ্টা করবে সে সম্পর্কে কিছু ইঙ্গিত দিতে পারে?
এস্লট

আপনার অর্থ কি "জেনারেটর খালি থাকায় কিছুই প্রদর্শিত হবে না"?
সাইলেন্টগোস্ট

S.Lott। আমি রাজী. আমি দেখতে পাচ্ছি না কেন। তবে আমি মনে করি কোনও কারণ থাকলেও সমস্যাটির পরিবর্তে প্রতিটি আইটেম ব্যবহারের পরিবর্তে আরও ভাল করা যেতে পারে।
আলী আফশার

1
জেনারেটর খালি থাকলে এটি প্রোগ্রামটি বলে না।
ইথান ফুরম্যান

3

কোনও জেনারেটর খালি রয়েছে কিনা তা দেখার জন্য আপনাকে যা করতে হবে তা হল পরবর্তী ফলাফল পাওয়ার চেষ্টা করা। অবশ্যই যদি আপনি সেই ফলাফলটি ব্যবহার করতে প্রস্তুত না হন তবে আপনাকে আবার এটি ফেরত দেওয়ার জন্য এটি সংরক্ষণ করতে হবে।

এখানে একটি মোড়কের ক্লাস রয়েছে যা একটি __nonzero__পরীক্ষা যোগ করার জন্য একটি বিদ্যমান পুনরাবৃত্তকারীকে যুক্ত করা যেতে পারে , তাই আপনি দেখতে পাচ্ছেন যে কোনও সাধারণ দিয়ে জেনারেটর খালি রয়েছে কিনা if। এটি সম্ভবত ডেকরেটারেও পরিণত হতে পারে।

class GenWrapper:
    def __init__(self, iter):
        self.source = iter
        self.stored = False

    def __iter__(self):
        return self

    def __nonzero__(self):
        if self.stored:
            return True
        try:
            self.value = next(self.source)
            self.stored = True
        except StopIteration:
            return False
        return True

    def __next__(self):  # use "next" (without underscores) for Python 2.x
        if self.stored:
            self.stored = False
            return self.value
        return next(self.source)

আপনি এটি কীভাবে ব্যবহার করবেন তা এখানে রয়েছে:

with open(filename, 'r') as f:
    f = GenWrapper(f)
    if f:
        print 'Not empty'
    else:
        print 'Empty'

মনে রাখবেন যে আপনি যে কোনও সময় শূন্যতার জন্য যাচাই করতে পারেন, কেবল পুনরাবৃত্তির শুরুতে নয়।


এটি সঠিক দিকে এগিয়ে চলেছে। এটি যতটা সম্ভব আপনার সামনে উঁকি দেওয়ার অনুমতি দেওয়া উচিত, যতগুলি প্রয়োজন ফলাফল সংরক্ষণ করা উচিত। আদর্শভাবে এটি স্রোতের মাথায় স্বেচ্ছাচারী আইটেমগুলিকে ঠেলে দেওয়ার অনুমতি দেয়। একটি পুশযোগ্য-পুনরুক্তিকারী একটি খুব দরকারী বিমূর্ততা যা আমি প্রায়শই ব্যবহার করি।
sfkleach

@sfkleach আমি একাধিক উঁকি দেওয়ার জন্য এটি জটিল করার প্রয়োজন দেখছি না, এটি যেমন রয়েছে তেমন কার্যকর এবং প্রশ্নের উত্তর দিয়েছে। যদিও এটি একটি পুরানো প্রশ্ন এটি এখনও মাঝে মাঝে চেহারা পাচ্ছে, তাই আপনি যদি নিজের উত্তরটি ছেড়ে যেতে চান তবে কারও পক্ষে এটি দরকারী হতে পারে।
মার্ক রান্সম

মার্ক ঠিক বলেছেন যে তার সমাধান প্রশ্নের উত্তর দেয়, যা মূল বিষয়। আমার আরও ভাল শব্দ করা উচিত ছিল। আমার অর্থ হ'ল আনবাউন্ডেড পুশব্যাকের সাথে পশাবল-পুনরাবৃত্তিকারীরা হ'ল একটি প্রতিমা যা আমি অত্যন্ত কার্যকর বলে খুঁজে পেয়েছি এবং বাস্তবায়নটি তর্কযোগ্যভাবে এমনকি আরও সহজ। প্রস্তাবিত হিসাবে আমি বৈকল্পিক কোড পোস্ট করব।
sfkleach

2

মার্ক রান্সম দ্বারা প্রম্পট করা হয়েছে, এখানে এমন একটি শ্রেণী রয়েছে যা আপনি যে কোনও পুনরুক্তি বিশিষ্ট করতে ব্যবহার করতে পারেন যাতে আপনি সামনে উঁকি দিতে পারেন, মানগুলি আবার স্ট্রিমের দিকে ঠেলে এবং খালি পরীক্ষা করতে পারেন। এটি একটি সহজ বাস্তবায়নের সাথে একটি সাধারণ ধারণা যা আমি অতীতে খুব সহজ ব্যবহার করেছি।

class Pushable:

    def __init__(self, iter):
        self.source = iter
        self.stored = []

    def __iter__(self):
        return self

    def __bool__(self):
        if self.stored:
            return True
        try:
            self.stored.append(next(self.source))
        except StopIteration:
            return False
        return True

    def push(self, value):
        self.stored.append(value)

    def peek(self):
        if self.stored:
            return self.stored[-1]
        value = next(self.source)
        self.stored.append(value)
        return value

    def __next__(self):
        if self.stored:
            return self.stored.pop()
        return next(self.source)

2

এই থ্রেডে পড়ে গিয়ে বুঝতে পেরেছিলাম যে খুব সহজ এবং পড়ার জন্য সহজ উত্তরটি অনুপস্থিত:

def is_empty(generator):
    for item in generator:
        return False
    return True

যদি আমরা কোনও আইটেম গ্রাস করে না অনুমান করি তবে আমাদের প্রথম আইটেমটি জেনারেটরে পুনরায় ইনজেক্ট করতে হবে:

def is_empty_no_side_effects(generator):
    try:
        item = next(generator)
        def my_generator():
            yield item
            yield from generator
        return my_generator(), False
    except StopIteration:
        return (_ for _ in []), True

উদাহরণ:

>>> g=(i for i in [])
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
True
>>> g=(i for i in range(10))
>>> g,empty=is_empty_no_side_effects(g)
>>> empty
False
>>> list(g)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

1
>>> gen = (i for i in [])
>>> next(gen)
Traceback (most recent call last):
  File "<pyshell#43>", line 1, in <module>
    next(gen)
StopIteration

জেনারেটরের শেষে StopIterationউত্থাপিত হয়, যেহেতু আপনার ক্ষেত্রে শেষ অবিলম্বে পৌঁছেছে, ব্যতিক্রম উত্থাপিত হয়। তবে সাধারণত আপনার পরবর্তী মানের অস্তিত্বের জন্য পরীক্ষা করা উচিত নয়।

আর একটি জিনিস যা আপনি করতে পারেন তা হ'ল:

>>> gen = (i for i in [])
>>> if not list(gen):
    print('empty generator')

2
যা আসলে পুরো জেনারেটর গ্রাস করে। দুঃখের বিষয়, এটি পছন্দসই বা অনাকাঙ্ক্ষিত আচরণ কিনা তা প্রশ্ন থেকে পরিষ্কার নয়।
এস .লট

"স্পর্শ" জেনারেটরের অন্য কোনও উপায় হিসাবে, আমি মনে করি।
সাইলেন্টগোস্ট

আমি বুঝতে পেরেছি এটি পুরানো, তবে 'তালিকা ()' ব্যবহার করা সবচেয়ে ভাল উপায় হতে পারে না, যদি উত্পন্ন তালিকাটি খালি না হয় তবে বাস্তবে বড় আকারের হয় তবে এটি অযথা অপ্রয়োজনীয়
Chris_Rands

1

জেনারেটরটি ব্যবহার করার আগে যদি আপনার জানা দরকার , তবে না, কোনও সহজ উপায় নেই। আপনি যদি জেনারেটরটি ব্যবহারের পরে অপেক্ষা করতে পারেন তবে একটি সহজ উপায় রয়েছে:

was_empty = True

for some_item in some_generator:
    was_empty = False
    do_something_with(some_item)

if was_empty:
    handle_already_empty_generator_case()

1

কেবল জেনারেটরকে itertools.chain দিয়ে মুড়ে রাখুন , এমন কোনও কিছু রাখুন যা পুনরাবৃত্তের শেষটিকে দ্বিতীয় পুনরাবৃত্ত হিসাবে চিহ্নিত করবে, তারপরে কেবল তার জন্য পরীক্ষা করুন।

উদা:

import itertools

g = some_iterable
eog = object()
wrap_g = itertools.chain(g, [eog])

এখন যা বাকি আছে তা হল সেই মানটি যাচাই করা উচিত যা আমরা পুনরাবৃত্তের শেষে যুক্ত করেছিলাম, আপনি যখন এটি পড়েন তখন এটি শেষকে বোঝায়

for value in wrap_g:
    if value == eog: # DING DING! We just found the last element of the iterable
        pass # Do something

eog = object()অনুমানের পরিবর্তে ব্যবহার করুন float('-inf')যা পুনরাবৃত্তিতে কখনও ঘটবে না।
bfontaine

@bfontaine ভাল ধারণা
smac89

1

আমার ক্ষেত্রে আমার জানার দরকার ছিল আমি কোনও ফাংশন এ দেওয়ার আগে যে কোনও জেনারেটর পপুলেট ছিল, যা আইটেমগুলিকে একত্রিত করেছে, অর্থাৎ zip(...),। সমাধানটি অনুরূপ, তবে গ্রহণযোগ্য উত্তর থেকে ভিন্ন,

সংজ্ঞা:

def has_items(iterable):
    try:
        return True, itertools.chain([next(iterable)], iterable)
    except StopIteration:
        return False, []

ব্যবহার:

def filter_empty(iterables):
    for iterable in iterables:
        itr_has_items, iterable = has_items(iterable)
        if itr_has_items:
            yield iterable


def merge_iterables(iterables):
    populated_iterables = filter_empty(iterables)
    for items in zip(*populated_iterables):
        # Use items for each "slice"

আমার বিশেষ সমস্যাটির এমন সম্পত্তি রয়েছে যা পুনরাবৃত্তিগুলি খালি হয় বা ঠিক একই সংখ্যক এন্ট্রি থাকে।


1

আমি কেবল এই সমাধানটি খালি পুনরাবৃত্তির জন্য কাজ করার হিসাবে পেয়েছি।

def is_generator_empty(generator):
    a, b = itertools.tee(generator)
    try:
        next(a)
    except StopIteration:
        return True, b
    return False, b

is_empty, generator = is_generator_empty(generator)

অথবা আপনি যদি এই ব্যবহারের জন্য ব্যতিক্রম ব্যবহার করতে না চান

def is_generator_empty(generator):
    a, b = itertools.tee(generator)
    for item in a:
        return False, b
    return True, b

is_empty, generator = is_generator_empty(generator)

ইন চিহ্নিত সমাধান আপনার মত খালি জেনারেটর জন্য এটি ব্যবহার করা সম্ভব হয় না

def get_empty_generator():
    while False:
        yield None 

generator = get_empty_generator()


0

এখানে আমার সহজ পদ্ধতিটি যা আমি কোনও পুনরুদ্ধারকারীকে ফেরত রাখতে ব্যবহার করি যখন কিছু পাওয়া যায় কিনা তা পরীক্ষা করে দেখি কেবল লুপটি চলে কিনা তা পরীক্ষা করে দেখছি:

        n = 0
        for key, value in iterator:
            n+=1
            yield key, value
        if n == 0:
            print ("nothing found in iterator)
            break

0

এখানে একটি সাধারণ সাজসজ্জা রয়েছে যা জেনারেটরটিকে আবৃত করে, তাই খালি থাকলে এটি কোনওটিই দেয় না। আপনার কোডটি জেনারেটরটি লুপিংয়ের আগে কোনও উত্পাদন করবে কিনা তা জানতে যদি এটি কোডের প্রয়োজন হয় তবে এটি কার্যকর হতে পারে ।

def generator_or_none(func):
    """Wrap a generator function, returning None if it's empty. """

    def inner(*args, **kwargs):
        # peek at the first item; return None if it doesn't exist
        try:
            next(func(*args, **kwargs))
        except StopIteration:
            return None

        # return original generator otherwise first item will be missing
        return func(*args, **kwargs)

    return inner

ব্যবহার:

import random

@generator_or_none
def random_length_generator():
    for i in range(random.randint(0, 10)):
        yield i

gen = random_length_generator()
if gen is None:
    print('Generator is empty')

এটি কার্যকর যেখানে একটি উদাহরণ টেম্প্লেটিং কোড - যেমন জিনজা 2

{% if content_generator %}
  <section>
    <h4>Section title</h4>
    {% for item in content_generator %}
      {{ item }}
    {% endfor %
  </section>
{% endif %}

এটি জেনারেটরের ফাংশনটিকে দু'বার কল করে, ফলে জেনারেটরের স্টার্ট-আপ ব্যয় দু'বার হবে। এটি যথেষ্ট হতে পারে যদি, উদাহরণস্বরূপ, জেনারেটর ফাংশন একটি ডাটাবেস কোয়েরি হয়।
ইয়ান গোল্ডবি

0

আইলিস ব্যবহার করে আপনাকে খালি কিনা তা আবিষ্কার করতে কেবল প্রথম পুনরুক্তি পরীক্ষা করতে হবে।

ইয়ারটুলগুলি আমদানি করে আইসলিস

Def isempty (পুনরাবৃত্তযোগ্য):
    প্রত্যাবর্তন তালিকা (islice (পুনরাবৃত্ত, 1)) == []


দুঃখিত, এটা একটা ক্ষয়কারী পঠিত ... আছে StopIteration দিয়ে চেষ্টা / ধরা করতে
Quin

0

কোন () ব্যবহার সম্পর্কে কি? আমি এটি জেনারেটরগুলির সাথে ব্যবহার করি এবং এটি ঠিকঠাক কাজ করছে। এখানে এই সম্পর্কে একটু ব্যাখ্যা করে লোক রয়েছে


2
আমরা সবকিছু জেনারেটরের জন্য "কোনও ()" ব্যবহার করতে পারি না। এটি কেবল এমন এক জেনারেটরের সাথে ব্যবহার করার চেষ্টা করেছিল যাতে একাধিক ডেটাফ্রেম থাকে। আমি এই বার্তাটি পেয়েছি "একটি ডেটা ফ্রেমের সত্য মান অস্পষ্ট" " যে কোনও (আমার_জেনার_ও_ডিএফ)
প্রিবেটেল

any(generator)যখন আপনি জানবেন জেনারেটর এমন মান তৈরি করে যা কাস্ট করা যায় bool- মূল ডেটা ধরণের (যেমন, int, স্ট্রিং) কাজ। any(generator)জেনারেটর খালি থাকলে, বা যখন জেনারেটরের কেবলমাত্র ভ্যালু থাকে - যেমন উদাহরণস্বরূপ, যদি কোনও জেনারেটর 0, '' (খালি স্ট্রিং) এবং মিথ্যা উত্পাদন করে তবে তা মিথ্যা হবে। এটি সম্ভবত আপনি যতক্ষণ অবহিত হবেন ততক্ষণ এই উদ্দেশ্যমূলক আচরণ বা নাও হতে পারে :)
ড্যানিয়েল

0

ব্যবহার করুন উঁকি cytoolz মধ্যে ফাংশন।

from cytoolz import peek
from typing import Tuple, Iterable

def is_empty_iterator(g: Iterable) -> Tuple[Iterable, bool]:
    try:
        _, g = peek(g)
        return g, False
    except StopIteration:
        return g, True

এই ফাংশনটি দিয়ে ফিরে আসা পুনরাবৃত্তিটি আর্গুমেন্ট হিসাবে পাস করা মূলটির সমান হবে।


-2

আমি যোগফলটি ব্যবহার করে এটি সমাধান করেছি। Glob.iglob (যা একটি জেনারেটর ফিরিয়ে দেয়) দিয়ে আমি ব্যবহার করেছি এমন উদাহরণের জন্য নীচে দেখুন।

def isEmpty():
    files = glob.iglob(search)
    if sum(1 for _ in files):
        return True
    return False

* এটি সম্ভবত বিশাল জেনারেটরের পক্ষে কাজ করবে না তবে ছোট তালিকার জন্য দুর্দান্ত সম্পাদন করবে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.