(Sep-19-2021, 07:55 AM)buran Wrote: Not sure what you mean with this comment. The output is
from inspect import isgeneratorfunction
def normal_function():
return None
def generator_function():
yield
print("Type of normal_function", type(normal_function))
print("Type of generator_function", type(generator_function))
print("How to find out if generator_function is a generator without calling it?")
print("Return-Type of generator_function()", type(generator_function()))
print("Now the detection of a generator_function without calling this function")
print(isgeneratorfunction(generator_function))
Output:
Type of normal_function <class 'function'>
Type of generator_function <class 'function'>
How to find out if generator_function is a generator without calling it?
Return-Type of generator_function() <class 'generator'>
Now the detection of a generator_function without calling this function
True
A simplified implementation from inspect just for functions, not methods.
(it could also detect generator methods, but the code in inspect is a bit different and does crazy wrapping)
CO_GENERATOR = 32
def isgeneratorfunction(func):
if hasattr(func, "__code__"):
return bool(func.__code__.co_flags & CO_GENERATOR)
return False
With typing.Generator and with collections.abc.Generator you can't detect if a function will return a generator without calling the function.
You can call the generator and without iterating it or use of the send method, the generator
does not execute the code inside.
The thing is, that you call a function to check if it's a Generator and if it's the case, to throw it away or vice versa.
But there is another important point to bring up.
If you have a function which could be a generator, but you don't know it and another fact is, if you call the wrong function, it can take much time to compute something. But what if you have a worker with a bunch of functions/generators/coroutines and you need to branch to put the tasks into the right worker. The synchronous functions to the threaded/multiprocess-worker, the generators to an async worker aswell the coroutines. Calling a generatorfunction, return the generator. Calling a coroutine, returns the coroutine object. Calling a ordinary function, returns the result. But if you want to put this function with arguments to the threaded worker, you can't call the function inside the process which put the tasks to the right workers. So you need to be able to detect this, before you call a function.
The function has in the code-object flags, which define which type the function is.
The Flags:
Output:
CO_OPTIMIZED = 1
CO_NEWLOCALS = 2
CO_VARARGS = 4
CO_VARKEYWORDS = 8
CO_NESTED = 16
CO_GENERATOR = 32
CO_NOFREE = 64
CO_COROUTINE = 128
CO_ITERABLE_COROUTINE = 256
CO_ASYNC_GENERATOR = 512
You should be careful what you ask. The rabbit hole is quite deep.