Python: Memory-Efficiency of Assigning Variables and Calling Methods
Question: This has been bugging me for a while. I'm wondering about the comparative
memory-efficiency of assigning variables and calling methods. Consider, for
example:

> s = "foo"  
>  x = s.lower()

Versus

> x = "foo".lower()

Which one of these is more efficient in terms of memory use?

This is obviously a trivial example, but it illustrates what I'm wondering
about.  
There are many instances in which we define some variable `var1 = foo`, and
then define a second variable `var2 = var1.method()`. Does this total process
require more memory than just defining `var2 = foo.method()`?


Answer: The bytecode is larger in the first case, but only by a trivial amount.

    
    
    $ python3
    Python 3.3.5 (default, Mar  9 2014, 08:10:50) 
    [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import dis
    >>> def f():
    ...   s = "foo"
    ...   x = s.lower()
    ...   return x
    ... 
    >>> def g():
    ...   x = "foo".lower()
    ...   return x
    ... 
    >>> dis.dis(f)
      2           0 LOAD_CONST               1 ('foo') 
                  3 STORE_FAST               0 (s) 
    
      3           6 LOAD_FAST                0 (s) 
                  9 LOAD_ATTR                0 (lower) 
                 12 CALL_FUNCTION            0 (0 positional, 0 keyword pair) 
                 15 STORE_FAST               1 (x) 
    
      4          18 LOAD_FAST                1 (x) 
                 21 RETURN_VALUE         
    >>> dis.dis(g)
      2           0 LOAD_CONST               1 ('foo') 
                  3 LOAD_ATTR                0 (lower) 
                  6 CALL_FUNCTION            0 (0 positional, 0 keyword pair) 
                  9 STORE_FAST               0 (x) 
    
      3          12 LOAD_FAST                0 (x) 
                 15 RETURN_VALUE         
    >>> 
    

(It's sad that CPython _still_ doesn't do even basic CSE or copyprop at byte-
compilation time, but that's a whole 'nother question.)

The runtime memory requirement is also slightly larger in the first case,
because the function has two variable slots instead of one, but the string
itself is not copied an extra time. Python consistently uses reference
semantics for everything.

**EDIT:** as cdonts points out, if the code is more complicated and the
variables don't immediately go out of scope, the first version keeps the
original string alive on the heap until `s` does go out of scope, which _is_
potentially a significant extra memory cost. I hadn't even thought of that.

