파이썬에서 함수를 호출하기 전에 "생성기 함수"인지 확인하는 방법이 있습니까?
두 가지 기능이 있다고 가정 해 봅시다.
def foo():
return 'foo'
def bar():
yield 'bar'
첫 번째는 일반 함수이고 두 번째는 생성기 함수입니다. 이제 다음과 같이 작성하고 싶습니다.
def run(func):
if is_generator_function(func):
gen = func()
gen.next()
#... run the generator ...
else:
func()
간단한 구현은 어떤 is_generator_function()
모습일까요? types
패키지를 사용하여 gen
가 생성기 인지 테스트 할 수 있지만을 호출하기 전에 그렇게하고 싶습니다 func()
.
이제 다음과 같은 경우를 고려하십시오.
def goo():
if False:
yield
else:
return
을 호출 goo()
하면 생성기가 반환됩니다. 파이썬 파서가 goo()
함수에 yield 문이 있다는 것을 알고 있다고 가정하고 그 정보를 쉽게 얻을 수 있는지 궁금합니다.
감사!
>>> import inspect
>>>
>>> def foo():
... return 'foo'
...
>>> def bar():
... yield 'bar'
...
>>> print inspect.isgeneratorfunction(foo)
False
>>> print inspect.isgeneratorfunction(bar)
True
- Python 버전 2.6의 새로운 기능
사실, 그런 가설 is_generator_function()
이 실제로 얼마나 유용한 지 궁금합니다 . 중히 여기다:
def foo():
return 'foo'
def bar():
yield 'bar'
def baz():
return bar()
def quux(b):
if b:
return foo()
else:
return bar()
What should is_generator_function()
return for baz
and quux
? baz()
returns a generator but isn't one itself, and quux()
might return a generator or might not.
>>> def foo():
... return 'foo'
...
>>> def bar():
... yield 'bar'
...
>>> import dis
>>> dis.dis(foo)
2 0 LOAD_CONST 1 ('foo')
3 RETURN_VALUE
>>> dis.dis(bar)
2 0 LOAD_CONST 1 ('bar')
3 YIELD_VALUE
4 POP_TOP
5 LOAD_CONST 0 (None)
8 RETURN_VALUE
>>>
As you see, the key difference is that the bytecode for bar
will contain at least one YIELD_VALUE
opcode. I recommend using the dis
module (redirecting its output to a StringIO instance and checking its getvalue
, of course) because this provides you a measure of robustness over bytecode changes -- the exact numeric values of the opcodes will change, but the disassembled symbolic value will stay pretty stable;-).
I've implemented a decorator that hooks on the decorated function returned/yielded value. Its basic goes:
import types
def output(notifier):
def decorator(f):
def wrapped(*args, **kwargs):
r = f(*args, **kwargs)
if type(r) is types.GeneratorType:
for item in r:
# do something
yield item
else:
# do something
return r
return decorator
It works because the decorator function is unconditionnaly called: it is the return value that is tested.
EDIT: Following the comment by Robert Lujo, I ended up with something like:
def middleman(f):
def return_result(r):
return r
def yield_result(r):
for i in r:
yield i
def decorator(*a, **kwa):
if inspect.isgeneratorfunction(f):
return yield_result(f(*a, **kwa))
else:
return return_result(f(*a, **kwa))
return decorator
ReferenceURL : https://stackoverflow.com/questions/1871685/in-python-is-there-a-way-to-check-if-a-function-is-a-generator-function-before
'Nice programing' 카테고리의 다른 글
스트림의 다음 항목을 변경하는 C ++ 사용자 정의 스트림 조작기 (0) | 2021.01.07 |
---|---|
HTTP 304 Not Modified-responses에 캐시 제어 헤더가 포함되어야합니까? (0) | 2021.01.07 |
Oracle SQL Developer로 데이터를 내보내는 방법은 무엇입니까? (0) | 2021.01.07 |
WPF 용 Visual Studio 디자이너를 수동으로 다시로드하는 방법 (0) | 2021.01.07 |
MySQL : 싫어요 (0) | 2021.01.07 |