Generators are elegant and memory-efficient, so I'd like to convert normal functions producing sequences to generators. But I haven't found an easy conversion method, by easy I mean it is best to be done automatically by some tools, maybe simple as string or regex replacement(return
to yield
, for example). If the conversion cannot always be easy, refactoring may introduce bugs. Of course unit testing can capture some bugs, but if the normal function is already fully tested, I doubt the necessity writing extra tests for the generator.
Let me give an example, normal function normalize
accepts a src
parameter, if src
is a list
, then return the list, otherwise return one list with src
as sigle item. Here for simplicity we suppose src
is provided by the caller as either a list
or a simple scalar.
test
f = normalize # replace with other conversions
assert list(f(2)) == [2]
assert list(f([1, 2])) == [1, 2]
normal function
def normalize(src):
if isinstance(src, list):
return src
return [src]
Now I convert it to generator, adding one else
block, test passes:
generator which introducs new code blocks
def normalize_generator(src):
if isinstance(src, list):
for x in src:
yield x
else:
yield src
What I want is keeping the code structure of normalize
, only replacing some keywords, like following, of course test will fail.
generator keeping code structure, test fails:
def normalize_generator_no_else(src):
if isinstance(src, list):
for x in src:
yield x
yield src
test result fail: left is [1, 2, [1, 2]], right is [1, 2]
I basically understand this behaviour, it seems yield
continues code in following lines. I've searched and found similar question Does python yield imply continue? but I haven't found a solution to my question.