How can a non-assigned string in Python have an address in memory?

前端 未结 5 901
北荒
北荒 2021-02-01 01:43

Can someone explain this to me? So I\'ve been playing with the id() command in python and came across this:

>>> id(\'cat\')
5181152
>>> a = \'c         


        
5条回答
  •  臣服心动
    2021-02-01 01:53

    Python reuses string literals fairly aggressively. The rules by which it does so are implementation-dependent, but CPython uses two that I'm aware of:

    • Strings that contain only characters valid in Python identifiers are interned, which means they are stored in a big table and reused wherever they occur. So, no matter where you use "cat", it always refers to the same string object.
    • String literals in the same code block are reused regardless of their content and length. If you put a string literal of the entire Gettysburg Address in a function, twice, it's the same string object both times. In separate functions, they are different objects: def foo(): return "pack my box with five dozen liquor jugs" def bar(): return "pack my box with five dozen liquor jugs" assert foo() is bar() # AssertionError

    Both optimizations are done at compile time (that is, when the bytecode is generated).

    On the other hand, something like chr(99) + chr(97) + chr(116) is a string expression that evaluates to the string "cat". In a dynamic language like Python, its value can't be known at compile time (chr() is a built-in function, but you might have reassigned it) so it normally isn't interned. Thus its id() is different from that of "cat". However, you can force a string to be interned using the intern() function. Thus:

    id(intern(chr(99) + chr(97) + chr(116))) == id("cat")   # True
    

    As others have mentioned, interning is possible because strings are immutable. It isn't possible to change "cat" to "dog", in other words. You have to generate a new string object, which means that there's no danger that other names pointing to the same string will be affected.

    Just as an aside, Python also converts expressions containing only constants (like "c" + "a" + "t") to constants at compile time, as the below disassembly shows. These will be optimized to point to identical string objects per the rules above.

    >>> def foo(): "c" + "a" + "t"
    ...
    >>> from dis import dis; dis(foo)
      1           0 LOAD_CONST               5 ('cat')
                  3 POP_TOP
                  4 LOAD_CONST               0 (None)
                  7 RETURN_VALUE
    

提交回复
热议问题