Deep dive into the copying and scoping of variables in Python

Source: Internet
Author: User
In Python, an assignment statement always establishes a reference value for an object, rather than copying an object. Therefore, Python variables are more like pointers than data storage areas.

This is similar to most OO languages, such as C + +, Java, etc. ~
1. Let's take a look at the question first:

In Python, what makes values=[0,1,2];values[1]=values, why does the result be [0,[...],2]?

>>> values = [0, 1, 2]>>> values[1] = values>>> values[0, [...], 2]

I expected it to be

[0, [0, 1, 2], 2]

But why do they have to be assigned an infinite number of times?

It can be said that Python has no assignment, only references. You create a structure that refers to itself, so it causes an infinite loop. To understand the problem, there is a basic concept that needs to be made clear.

Python does not have a "variable", and what we call a variable is actually a "tag", a reference.

Perform

values = [0, 1, 2]

, Python does this by first creating a list object [0, 1, 2], and then pasting it with a label named values. If you then execute

values = [3, 4, 5]

, what Python does is create another list object [3, 4, 5], and then rip the tag that was named values from the previous [0, 1, 2] object and re-paste it onto the object [3, 4, 5].

From the beginning to the end, there is no List object container called values, and Python does not copy the values of any objects into values. Process:

Perform

VALUES[1] = values

, what Python does is point to the second element of the list object referenced by the values tag as the list object itself referenced by values. After execution, the values tag still points to the original object, except that the structure of the object has changed, from the previous list [0, 1, 2] into [0,?, 2], and this? is a reference to the object itself. :

To achieve the effect you need, you get [0, [0, 1, 2], 2] This object, you cannot direct values[1] to the object referenced by the values itself, but need it [0, 1, 2] This object "copy" again, get a new object, then values[1] refers to To this copied object. The operation of copying objects in Python varies by object type, and the copy list values are

values[:] #生成对象的拷贝或者是复制序列, is no longer a reference and shared variable, but this method can only be replicated at the top level

So you need to execute

VALUES[1] = values[:]

What Python does is dereference get the object that values points to [0, 1, 2], then executes [0, 1, 2][:] The copy operation gets a new object, the content is [0, 1, 2], and then the second of the list object pointed to by values Element points to the list object that is copied, and the final values point to the object is [0, [0, 1, 2], 2]. Process:

Further down, values[:] The copy operation is so-called "shallow copy" (Shallow copy), and when the list object is nested, it also generates unexpected errors, such as

A = [0, [1, 2], 3]b = a[:]a[0] = 8a[1][1] = 9

Q: What is a and B at this time?

The correct answer is a for [8, [1, 9], 3],b for [0, [1, 9], 3]. Did you find it? The second element of B has also been changed. Think about it. If you don't understand, look.

The correct way to copy nested elements is to make a deep copy, by


Import Copy a = [0, [1, 2], 3]b = Copy.deepcopy (a) a[0] = 8a[1][1] = 9

2. Reference VS copy:

(1) A Shard expression (l[:]) without a constraint can copy a sequence, but this method can only be copied in shallow layers.

(2) Dictionary copy method, d.copy () can copy the dictionary, but this method can only shallow copy

(3) Some built-in functions, such as list, can generate a copy list (L)

(4) Copy standard library module can generate a full copy: Deepcopy is essentially a recursive copy

(5) For non-mutable and mutable objects, shallow copy is a copy of the reference, except that the copy-invariant object and the copy-invariant object's reference are equivalent (because the object is immutable and the new object is re-assigned when changed). So it seems that shallow copy copies only immutable objects (integers, real numbers, strings, etc.), and for mutable objects, shallow copy actually creates a reference to the object, that is, it just labels the same object with another label.

L = [1, 2, 3]d = {' A ': 1, ' B ': 2}a = L[:]b = D.copy () print "L, D" Print L, Dprint "A, B" print A, bprint "-------------------- "A[1] = ' NI ' b[' c '] = ' spam ' print" L, D "Print L, dprint" A, b "Print A, b  L, D[1, 2, 3] {' A ': 1, ' B ': 2}a, B[1, 2, 3] {' A ': 1, ' B ': 2}--------------------L, D[1, 2, 3] {' A ': 1, ' B ': 2}a, b[1, ' NI ', 3] {' A ': 1, ' C ': ' Spam ', ' B ': 2}

3. Enhanced assignment and shared references:

x = x + Y,x appears two times, must execute two times, performance is bad, merge must create new object x, and then copy two list merge

belongs to copy/copy

X + = Y,x occurs only once, and is calculated once, performs well, does not generate new objects, and only adds elements at the end of the memory block.

When x and Y are list, + = automatically calls the Extend method for the merge operation, in-place the change.

belongs to a shared reference

L = [1, 2]m = LL = L + [3, 4]print L, Mprint "-------------------" L = [1, 2]m = LL + = [3, 4]print L, M  [1, 2, 3, 4] [1 , 2]-------------------[1, 2, 3, 4] [1, 2, 3, 4]

4, Python from 2.x to 3.x, the variable scope problem caused by the statement variable function

First look at the paragraph code:

def test ():  a = False  exec ("a = True")  print ("a =", a) test () b = Falseexec ("B = true") print ("b =", b)

In Python 2.x and 3.x you will find that their results are different:

2.x:a = Trueb = True 3.x:a = Falseb = True

What is this for?

Since the exec in 3.x is a function of the statement, the variables in the function are local by default, which means

The two A that you see is two different variables that are in different namespaces and do not conflict with each other.

For specific reference "learning Python" p331-p332

Knowing why, we can change this:

def test ():  a = False  ldict = locals ()  exec ("A=true", Globals (), ldict)  a = ldict[' a ']  print (a) test () b = Falseexec ("b = True", globals ()) print ("b =", b)

This question has already been asked on the StackOverflow, and some Python officials have reported the bug ...

Specific links are below:

Http://stackoverflow.com/questions/7668724/variables-declared-in-execed-code-dont-become-local-in-python-3-documentatio

http://bugs.python.org/issue4831

Http://stackoverflow.com/questions/1463306/how-does-exec-work-with-locals

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.