title: What is the source of the malleability between names and strings in Python?
body: <p>I'm used to a firm distinction between identifiers (variable names) and strings in programming languages.</p>
  
  <p>Yet Python has some malleability between the two. For example in the code</p>
  
  <pre><code>import networkx as nx
  G = nx.Graph()
  G.add_edge(1, 2, food='eggs')
  for node1, node2, data in G.edges(data=True):
      print(data['food'])
  </code></pre>
  
  <p>we use <code>food</code> as an identifier on line 3 and then as the string <code>'food'</code> when we retrieve the attribute on line 5.</p>
  
  <p>I'd like to better understand what is happening. What is the feature in a programming language generally and in Python specifically that makes this malleability possible?</p>
  
  <p>(Please note that NetworkX is incidental to the question, which is why I'm not listing it in the keywords.)</p>
  
  <p><strong>Clarification why this question is not asking for an explanation of—and is all but superficially related to <a href="https://stackoverflow.com/questions/1419046/python-normal-arguments-vs-keyword-arguments">keyword arguments</a>:</strong></p>
  
  <p>Sometimes what is happening is perfectly clear. For example if we <a href="https://stackoverflow.com/a/1419107/704972">write</a> the code</p>
  
  <pre><code>def foo(bar, baz):
      pass
  
  foo(1, 2)
  foo(baz=2, bar=1)
  </code></pre>
  
  <p>(using keyword arguments in whichever order we like), the Python interpreter would have seen the names (not the strings) <code>bar</code> and <code>baz</code> and is henceforth expecting names (not strings) <code>bar</code> and <code>baz</code>, in any order.</p>
  
  <p>But in other contexts this malleability is truly puzzling. For example in the <a href="https://stackoverflow.com/a/1419160/704972">following</a> code explaining keyword arguments</p>
  
  <pre><code>def my_function(**kwargs):
      print str(kwargs)
  
  my_function(a=12, b="abc")
  
  {'a': 12, 'b': 'abc'}
  </code></pre>
  
  <p>we introduce keyword arguments in the function call, only, lo and behold, to find that they have become strings.</p>
  
  <p>From an <a href="https://stackoverflow.com/a/39253840/704972">answer</a> to the present question</p>
  
  <pre><code>&gt;&gt;&gt; d = dict(food='eggs')
  &gt;&gt;&gt; d['food']
  'eggs'
  </code></pre>
  
  <p>it becomes clear that in Python there is <em>zero distinction</em> between <code>d1</code> and <code>d2</code> whether we write:</p>
  
  <pre><code>d1 = {'food':'eggs'}
  </code></pre>
  
  <p>or</p>
  
  <pre><code>d2 = dict(food='eggs')
  </code></pre>
  
  <p>What happens with <code>d1</code> makes perfect sense. The type of <code>'food'</code> is a string.</p>
  
  <p>But, again, <code>d2</code> is obscure. Although we end up with exactly the same outcome, the language has somehow molded the identifier/name that we used (<code>food</code>) into a string.</p>
  
  <p>What is the feature of programming languages generally and Python specifically that permits a language to mold a name into a string? Now that a pattern is emerging, might it be the case that Python uses some mechanism for switching names into strings, but there are no instances of switching strings to identifiers?</p>