Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6556601
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 25, 20262026-05-25T12:57:57+00:00 2026-05-25T12:57:57+00:00

Here I asked a question about izip_longest function from itertools module. The code of

  • 0

Here I asked a question about izip_longest function from itertools module.

The code of it:

def izip_longest_from_docs(*args, **kwds):
    # izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
    fillvalue = kwds.get('fillvalue')
    def sentinel(counter = ([fillvalue]*(len(args)-1)).pop):
        yield counter()         # yields the fillvalue, or raises IndexError
    fillers = repeat(fillvalue)
    iters = [chain(it, sentinel(), fillers) for it in args]
    try:
        for tup in izip(*iters):
            yield tup
    except IndexError:
        pass

There appeared to be an error in the documentation in the pure Python equivalent of that function. The error was that the real function did and the abovementioned equivalent didn’t
propagate IndexError exceptions that were raised inside the generators sent as the function parameters.

@agf solved the problem and gave a corrected version of the pure Python equivalent.

But at the same time when he was writing his solution I made my own. And while making it I faced one problem which I hope will be unraveled by asking this question.

The code that I came up with is this:

def izip_longest_modified_my(*args, **kwds):
    # izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
    fillvalue = kwds.get('fillvalue')

    class LongestExhausted(Exception):
        pass

    def sentinel(fillvalue = fillvalue, counter = [0]):
        def ret():
            counter[0] += 1
            if counter[0] == len(args):
                raise LongestExhausted
            yield fillvalue
        return ret()

    fillers = repeat(fillvalue)
    iters = [chain(it, sentinel(), fillers) for it in args]
    try:
        for tup in izip(*iters):
            yield tup
    except LongestExhausted:
        pass 

In the original code sentinel is a generator which implements lazy evaluation. So that counter() is returned only when it’s actually needed by the iterator created using chain function.

In my code I added a counter which holds a list of one value [0]. The reason for that was to put a mutable object into some place where it can be accessed by all the returned iterators ret() and changed by them. The only place I found suitable was in the function_defaults of sentinel.

If I put it inside the sentinel function, then the counter would be assigned to [0] on every call of sentinel and that would be different lists for all the ret()s:

def sentinel(fillvalue = fillvalue):
    counter = [0]
    def ret():
        counter[0] += 1
        if counter[0] == len(args):
            raise LongestExhausted
        yield fillvalue
    return ret()

I tried to put it outside of the sentinel function:

counter = 0
def sentinel(fillvalue = fillvalue):
    def ret():
        counter += 1
        if counter == len(args):
            raise LongestExhausted
        yield fillvalue
    return ret()

But the exception rose: UnboundLocalError: local variable 'counter' referenced before assignment.

I added global keyword, but it didn’t help (I think because counter is really not in the global scope):

counter = 0
def sentinel(fillvalue = fillvalue):
    global counter
    def ret():
        counter += 1
        if counter == len(args):
            raise LongestExhausted
        yield fillvalue
    return ret()

So, my question is:

Is the approach that I used (to put mutable list counter = [0] to function_defaults) the best in this case, or there is some better way to solve this problem?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-25T12:57:57+00:00Added an answer on May 25, 2026 at 12:57 pm

    This has been asked many times in many forms. Read any number of other questions about mutable default arguments and the new Python 3 nonlocal keyword. On Python 2, you could use a function attribute:

    def sentinel(fillvalue = fillvalue):
        def ret():
            sentinel.counter += 1
            if sentinel.counter == len(args):
                raise LongestExhausted
            yield fillvalue
        return ret()
    sentinel.counter = 0
    

    or use global both inside ret and inside izip_longest so you’re always referencing a global variable:

    global counter
    counter = 0
    def sentinel(fillvalue = fillvalue):
        def ret():
            global counter
            counter += 1
            if counter == len(args):
                raise LongestExhausted
            yield fillvalue
        return ret()
    

    However, using global restricts you to only one izip_longest at a time — see the comments on the other answer.

    You’re also defining a new ret every time sentinel is called (once per iterator) — you could instead do something like

    global counter
    counter = 0
    arglen = len(args)
    
    def ret():
        global counter
        counter += 1
        if counter == arglen:
            raise LongestExhausted
        return fillvalue
    
    def sentinel():
        yield ret()
    

    Example code for having sentinel outside izip_longest in re your question from the comments:

    def sentinel(counter, arglen, fillvalue):
        def ret():
            counter[0] += 1
            if counter[0] == arglen:
                raise LongestExhausted
            yield fillvalue
        return ret()
    
    
    def izip_longest_modified_my(*args, **kwds):
        # izip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
        fillvalue = kwds.get('fillvalue')
    
        class LongestExhausted(Exception):
            pass
    
        fillers = repeat(fillvalue)
        counter = [0]
        arglen = len(args)
        iters = [chain(it, sentinel(counter, arglen, fillvalue), fillers) for it in args]
        try:
            for tup in izip(*iters):
                yield tup
        except LongestExhausted:
            pass
    

    Here you’re again using a list just as a container to get around the problems accessing outer scopes in Python 2.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I asked a question here about an Linq error that results from mixing Linq-To-SQL
I asked a question about same code but got lost in translation Here's what
Yesterday I asked this general question about decimals and their internal precisions. Here is
I asked a question here : When To Use IEquatable And Why about using
I've asked here a question about Task Killers and widgets stop working ( SO
i've asked the first question about selects here , i thought, that when i
A while back, I asked a question on here about how to run an
I've asked one question about this a month ago, it's here: "post" method to
I just asked a question here about selecting all id's of the form id_*
I have asked this question here about a Python command that fetches a URL

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.