Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The standard approach to this in Python is

    rv = []
    for x in y:
        rv.append(f(x))
        if g(x):
            rv.append(h(x))
    return ''.join(rv)
This gives you the same O(N²) to O(N) speedup you would get from a StringBuilder.

More recently, though, I've often been preferring the following construction instead:

    for x in y:
        yield f(x)
        if g(x):
            yield h(x)
This is sometimes actually faster (when you can pass the result to somefile.writelines, for example, which does not append newlines to the items despite its name) and is usually less code. If you want to delegate part of this kind of string generation to another function, in Python 3.3+, you can use `yield from f(x)` rather than `for s in f(x): yield s` or the just `yield f(x)` you use if `f` returns a string, and the delegation is cleaner and more efficient than if you're appending to a list and the other function is internally joining a list to give you a string.

However, if you're optimizing a deeply nested string generator, you're better off using the list approach and passing in the incomplete list to callee functions so they can append to it. Despite the suggestive syntax, at least last time I checked, `yield from` doesn't directly delegate the transmission of the iterated values; on this old netbook, it costs about 240 ns per item per stack level of `yield from`. (By comparison, a simple Python function call and return takes about 420 ns on the same machine.)

But if you really wanted your code to run fast you wouldn't have written it in Python anyway. You'd've used JS, LuaJIT, or Golang. Or maybe Scheme. Or C or Rust. But not Python.



Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: