how do I make an empty generator? (intermediate) anthony explains

Поділитися
Вставка
  • Опубліковано 30 вер 2024
  • today I talk about how (and a little bit why) to make an empty generator in python! the syntax is a little quirky but I show you the details about what makes a generator a generator and why it's tricky to write an empty one!
    - generator basics: • generator basics (+typ...
    - generator send / return type: • python typing: Generat...
    - new generator shorthand! • PEP 696 is a huge qual...
    playlist: • anthony explains
    ==========
    twitch: / anthonywritescode
    dicsord: / discord
    twitter: / codewithanthony
    github: github.com/aso...
    stream github: github.com/ant...
    I won't ask for subscriptions / likes / comments in videos but it really helps the channel. If you have any suggestions or things you'd like to see please comment below!

КОМЕНТАРІ • 39

  • @jamesarthurkimbell
    @jamesarthurkimbell Місяць тому +19

    Just wait until 3.13 introduces the yieldn't keyword

  • @ruroruro
    @ruroruro Місяць тому +19

    `yield from ()` is indeed pretty elegant. One potential downside of it is that it actually compiles to a bunch of extra bytecode that actually creates the empty tuple and then tries to iterate over it.
    On the other hand, `return + yield` and `if False: yield` both compile to what seems to be the minimal number of instructions that emulate the required behavior.
    Also, regarding the correct type signature for such a generator, I think it should be
    def gen() -> Generator[typing.Never, typing.Any, None]:
    return
    yield
    because the yield type (first position) is covariant, while the send type (second position) is contravariant. So Generator[Never, Any, None] should be the broadest correct annotation. The generator never yields any value, accepts any sent value (because you'll never have an opportunity to actually send anything to it) and return None.

    • @siddhantdutta4050
      @siddhantdutta4050 Місяць тому

      Was just about to comment this as i was playing around disassembling the components :)

  • @ccgarciab
    @ccgarciab Місяць тому +10

    Showcasing the fix of a bug you found in a widely used library is cool.
    Empty iterables in general are the modulus of most operations, so they're really important. Thanks for the useful idioms.

  • @er63438
    @er63438 Місяць тому +6

    Expectation: to get my mind blown. Reality: got my mind blown.

  • @viddeshk8020
    @viddeshk8020 Місяць тому +4

    Damm, 😬 The more I learn python the more I am able to understand that I didn't learn anything 😢.

  • @Jakub1989YTb
    @Jakub1989YTb Місяць тому +3

    I'm gonna win so many bets, now that I know "return yield" is a valid syntax.

    • @Zhaxxy
      @Zhaxxy Місяць тому +4

      no, its return
      yield

  • @julius333333
    @julius333333 7 днів тому

    I feel like maybe we should have def and defg for generator functions, as yield changing the whole function is very surprising

  • @dandyddz
    @dandyddz 14 днів тому

    Before watching this video fully I was guessing that
    def a():
    if False:
    yield
    is the most efficient way of doing that.

  • @alainleufroy
    @alainleufroy 19 днів тому

    Before return was accepted in generator i usually used `while False: yield` 😅

  • @redark7
    @redark7 Місяць тому +1

    I actually had a very similar problem, I'll try the return + yield. In my case, I wanted to have an abstract method that returns an AsyncGenerator, so child classes implement it, as an interface. Well, if you define an async function that returns an AsyncGenerator, most abstract functions only 'pass', which was causing mypy to think the return type was Coroutine[AsyncGenerator] instead. Even with explicit type hinting it did not work, I had to make the abstract function not async for mypy to be happy, but that is even worse in my view...

  • @FunkyELF
    @FunkyELF Місяць тому

    I paused it at 30 seconds before seeing the answer. The way I'd do it is...
    def empty_gn():
    if False:
    yield "never"
    ... or if you want to fool your IDE about unreachable code do this:
    def empty_gn():
    if True in [False]:
    yield "never"
    Now I'll watch the rest and see if that's similar to what you do.

    • @FunkyELF
      @FunkyELF Місяць тому

      ah... cool. I like "yield from ()" ... more readable.
      Interesting that we both mentioned issues around unreachable code in the two different solutions.
      Also, I'd argue that mypy was correct that the yield was unreachable.
      Granted, my `yield "never"` is also unreachable but the day MyPy or PyCharm start executing code to determine if something is reachable or not is the day I stop using it anyway.
      My old trick for this with PyCharm was to use "if 1 == 1", then "if 1 + 1 == 2", but PyCharm started evaluating that stuff. I'm not really happy about that.

  • @at2704
    @at2704 Місяць тому +1

    return yeild feels wrong and bad lol

  • @be1tube
    @be1tube Місяць тому

    My first try was:
    for i in range(0,0):
    yield i
    Works but needs optimization.
    Worked great.

  • @Jakub1989YTb
    @Jakub1989YTb Місяць тому +1

    2:44 ... booom ... mind blown

  • @AZIARGROUS
    @AZIARGROUS Місяць тому

    It’s super fun cause I had to do them yesterday ahahah nice Anthony

  • @shunitsu__
    @shunitsu__ Місяць тому

    Will you make a 3.13 release highlight video

    • @anthonywritescode
      @anthonywritescode  Місяць тому +1

      yep! it just got to rc1 so I'm compiling my thoughts!

  • @davititchanturia
    @davititchanturia Місяць тому

    what are the usages of empty generator

    • @float32
      @float32 Місяць тому

      I’ve always wanted to use a for loop as a spooky noop: for _ in noop(): sys.exit()

    • @Clepsyd_
      @Clepsyd_ Місяць тому +6

      It allows for consistency of the type of object you expect: a generator. I just had a practical use case for this: I had a function that yields elements. Each element is kind of expensive to get, and there was a single, cheap check early in the function that, if True, made the function return `None`. That meant I had to check for `None` first when calling the function. Now by returning an empty generator, I can just do `for e in my_function():` regardless, the type returned is a generator.

    • @davititchanturia
      @davititchanturia Місяць тому

      @@Clepsyd_ thank you for answer. Totally Makes sense.

  • @galenseilis5971
    @galenseilis5971 Місяць тому

    What is an example use case for using an empty generator?

    • @anthonywritescode
      @anthonywritescode  Місяць тому

      it's right at the beginning!

    • @ArthurKhazbs
      @ArthurKhazbs 26 днів тому

      @@anthonywritescode I think the question is about a practical example of such usage scenario

  • @AlexLaletin-fr9eh
    @AlexLaletin-fr9eh Місяць тому +8

    I really like how we answered the "How" question but skipped the "WTF why?"

    • @michaelconnell9928
      @michaelconnell9928 Місяць тому +10

      He answers it like 45 seconds into the video

    • @Zmunk19
      @Zmunk19 Місяць тому

      in short, if you want to be able to swap in a null-generator somewhere that only accepts generators you'd need this