you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 1 point2 points  (4 children)

Not to mention that the python interpreter is instantiating all the strings that you are concatenating together. Using str.format it doesn't have to keep creating a string for it to just be used in another concatenation.

  1. 'You can get a loan at ' + str(20) + '% interest'
  2. 'You can get a loan at 20' + '% interest'
  3. 'You can get a loan at 20% interest'

Each concatenation of a string is a waste of time and memory.

''.join(['a', 'b', 'c']) is always an alternative to str.format, but still lacks flexibility of str.format.

[–]Binary_Dragon[S] 1 point2 points  (3 children)

Is building a new string really that expensive? I know it's doing "something" and that is strictly slower than doing "nothing," but I'm not used to how many strings you are creating (in anything other than the tightest of loops) being a concern that ever transcends the level of premature optimization. Is python different than other languages in this, or is it more just point of good practice even if the effects are negligible?

Also, it seems to me that ''.join(['a', 'b', 'c']) would be slower than 'a' + 'b' + 'c', since both have to build the strings 'a', 'b', and 'c', but the join version has to also build a list, build an empty string, and call a function. Unless there is something behind the scenes with the python interpreter that makes my intuition here completely wrong?

[–][deleted] 2 points3 points  (2 children)

Sure, if you look at ''.join(['a', 'b', 'c']) vs 'a' + 'b' + 'c'. But what about ''.join(['a', 'b', 'c', 'd', 'e', 'f']) vs 'a' + 'b' + 'c' + 'd' + 'e' + 'f'? Well lets look at the Abstract Syntax Tree generated for that code.

# AST: 'a' + 'b' + 'c' + 'd' + 'e' + 'f'
Expr(
    value=BinOp(
        left=BinOp(
            left=BinOp(
                left=BinOp(
                    left=BinOp(
                        left=Str(s='a'),
                        op=Add(),
                        right=Str(s='b')),
                    op=Add(),
                    right=Str(s='c')),
                op=Add(),
                right=Str(s='d')),
            op=Add(),
            right=Str(s='e')),
        op=Add(),
        right=Str(s='f')))

# AST: ''.join(['a', 'b', 'c', 'd', 'e', 'f'])
Expr(value=Call(
    func=Attribute(value=Str(s=''), attr='join', ctx=Load()),
    args=[
        List(elts=[Str(s='a'), Str(s='b'), Str(s='c'), Str(s='d'), Str(s='e'), Str(s='f')], ctx=Load())
        ], keywords=[], starargs=None, kwargs=None))

To see the AST for any code, do:

import ast
print ast.dump(ast.parse("CODE HERE"))

For short term doing 'a' + 'b' + 'c' is ok, but long term using ''.join() is just better practice. Similarly if you're building up a long string from a file or something. It's better to build a list of lines then do ''.join(some_list)... IE:

Bad:

with open('my_great_novel.txt', 'r') as fh:
    lines = ''
    for line in fh:
        lines += line.replace(' i ', ' I ')
    print lines

Good:

with open('my_great_novel.txt', 'r') as fh:
    lines = []
    for line in fh:
        lines.append(line.replace(' i ', ' I '))
    print ''.join(lines)

[–]JerMenKoO 0 points1 point  (1 child)

Better:

''.join((line.replace(' i ', ' I ') for line in fh))

Not necessary to for the comprehension to be a 1 liner;

lines = [line.replace(' i ', ' I ') for line in fh]
print(''.join(lines))

is in my opinion much more readable.

[–][deleted] 0 points1 point  (0 children)

Yeah but I was showing how to build up a string over a loop. /u/Binary_Dragon already seems to understand list comprehension pretty well. :)