Variables are fundamental concepts in programming, and Python variables may seem simple, but they can cause problems if not understood properly and copied mechanically.

Here are 10 code examples to show the nature of variables in Python.

It’s just a name

When a appears on the left side of an assignment statement, it simply represents a name:

a = 1024
a = 'davycloud'
a = ['thumb up'.'attention'.'collection']
Copy the code

Once the assignment is complete, the name is bound to the object on the right. And in the process,

  • aIt doesn’t matter if you’re already bound to other objects, that is, you don’t care
    aIt’s bound to something, or it’s not bound to anything, it’s a name.
  • As long as the name is legal, it can be bound to any object regardless of its type

2. Object reference

The name of the bound object, known as a variable, represents a reference to the object when it appears on the right side of an assignment statement:

a = []
b = a
Copy the code

When a is assigned to b, a represents a reference to a list object, that is:

  • List object ontologies are not affected
  • A new list is not copied
  • a
    bAfter that it’s all references to the same list

Since lists are mutable objects, they can be changed by either a or B, both of which reflect the change in the object:

a.append(1)   # a = [1], b = [1]
b.append(2)   # a = [1, 2], b = [1, 2]
Copy the code

Mutable objects are discussed again below

3. First right, then left

When multiple assignments are concatenated, they are processed from right to left:

a = b = []
Copy the code

Here b is first used as a name, bound to a list object; It then acts as a reference to the object and gives it another name, A, which is equivalent to:

Writing # 1
b = []
a = b
Copy the code

This has very different consequences from the following assignment:

# write 2
b = []
a = []
Copy the code

In this case, two variables are bound to two different lists that are unrelated to each other.

But there is an interesting point here. If we replace [] with an integer 1 or a string, there is no difference in the result between the 1 and 2 assignments.

4. Change depends on the object

Continuing with the example above, where two names are bound to the same list and the other is affected by manipulating one of them:

b = []
a = b
a.append(1)
Copy the code

This is because a list is a mutable object. If you replace a list with a number or string:

b = 'davy'
a = b
a += 'cloud'
Copy the code

Increment operation on A does not affect B. First give the equivalent form of the increment operation:

a = a + 'cloud'
Copy the code

So this is still an assignment. Using the previous conclusion:

  • The right of the
    aRepresents a reference to an object, that is
    'davy', and it
    'cloud'The sum generates a new object
  • On the left side of the
    aIs a name, it again and the new object, i.e
    'davycloud'Bind together

In other words, there are three string objects created.

When we look closely, we can see that when we want to change an object, we must do so through the interface provided by the object (append or subscript in the case of a list, or change its properties in the case of other objects), not through reassignment.

Assignment is just a binding of the name, again.

Here’s another conclusion:

Immutable objects are referenced/bound multiple times without side effects. Such as:

# a, b bind to the same object
a = b = 'davy'

# a and b are bound to an object
a = 'davy'
b = 'davy'
Copy the code

In the example above, the syntactic meaning of the two bindings is different, but because strings are immutable, that is, even if A and B are bound to the same string, they do not affect each other. Why create two identical Davy strings in memory? Better direct reuse, can save a bit of memory:

>>> a = 'davy'
>>> b = 'davy'
>>> a is b
True
Copy the code

Again, however, this optimization is not global, that is, it is not necessarily a unique object as long as it is the same string:

>>> a += 'cloud'
>>> b += 'cloud'
>>> a is b
False
>>> a
'davycloud'
>>> b
'davycloud'
>>> a == b
True
Copy the code

So, it’s good to know that for immutable objects, use == instead of is, because it can produce weird results that are sometimes true and sometimes false.

5. The secret of instant exchange

When multiple objects, or references to multiple objects, appear to the right of an assignment statement, they are automatically packaged into a tuple.

On the left side of the assignment statement, there needs to be the same number of names to unpack:

a = [1024]
b = 'davycloud'
a, b = b, a
Copy the code

In this example, a combination of the first three rules is used:

  • Right rear left first
  • Variables are references to objects
  • On the left is the name

It is not hard to conclude that the two names have swapped references to objects, and the object body has not been moved.

6. It’s all about the name

A does not assign a value, and runs directly as a result:

>>> print(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
Copy the code

This seems easy to explain, but the variable A is not defined. Just add a line of assignment.

But:

  • The error reported here is
    NameError:
    name‘A’ is not defined, the name is not defined error, not the variable is not defined
  • If you think about it, this
    aWhat is it? Numbers? The string? Function? The class? Modules?

7. We’re all variables

Here’s another example:

a = 1

def a():
    pass

class a():
    pass

import sys as a
Copy the code

Not only do you assign values, define functions, define classes, import modules or objects in modules, it’s all in the binding name.

To define a function is to bind a name to a function object, to define a class is to bind a name to a class object, and to import a module is to bind a name to a module object.

Everything is an object in Python, so they are variables.

8. Passing references is just naming

Now that we’re talking about functions, let’s look at passing parameters to functions:

def func(x):
    return x
Copy the code

This function is useless, but it does explain the passing in and out of arguments.

a = func(1024)
b = func(a)
Copy the code

The parameter x is also a name, but its scope is limited to the func function itself.

Passing a parameter to a function is like assigning, binding an object to the inner name, and passing a reference to an object, like the variable appearing on the right side of the assignment:

# pseudocode
func(1024):
    x = 1024
a = x
Copy the code

The scope of a variable is covered here and will be discussed in more detail.

Note that the above rules are the same for all object types, whether mutable or immutable.

From the above analysis, it is easy to draw the conclusion that:

  • If the argument/return is an immutable object, then it has no side effects
  • If the argument/return is a mutable object, then operations on it within the function affect other variables bound to the object

Therefore, you need to be careful about passing arguments to mutable objects. In particular, do not use mutable objects for default arguments to functions.

Because the binding of default arguments happens at the function definition stage:

def get_people(people=[]):
    return people
Copy the code

When get_people is called, unless people is given an argument, it is always bound to the list that was created at the time the function was defined. Our intention might be to generate an empty list if there are no arguments by default.

A common practice is to create a new object inside the function:

def get_people(people=None):
    if people is None:
        people = []
    return people
Copy the code

9. Undeleted objects

Python provides the del keyword to be used

delete

Variable, however, the effect of this operation is to unbind the variable name from the object and then delete the name. The deleted name will trigger if accessed again
NameErrorIt’s as if it never existed.

Objects, on the other hand, just subtract a reference:

a = [1, 2, 3]
b = a
del a    # doesn't affect B at all
Copy the code

It makes sense that an object will not be cleared if more than one variable is referenced to it. Even if no name is currently bound to the object, the object will not be deleted immediately:

>>> a = []
>>> id(a)
2292904305736

>>> del a
>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
>>> b = []
>>> id(b)
2292904305736
Copy the code

In short, del means unbind, don’t expect it to delete objects.

Reference counting and destruction of objects are maintained internally in Python, and generally we don’t care. For those interested, check out Python’s garbage collection section.

Shallow copy? Zero copy!

Final example:

a = [[]] * 3
a[0].append(1)
print(a)     # [[1], [1], [1]]
Copy the code

It’s a little confusing here, because you’re using the * operation on the list. When multiplying a list, the common understanding is to copy its elements.

See copy is easy to refer to the so-called shallow copy and deep copy, here is obviously not a deep copy, so it is easy to take for granted is a shallow copy, wrong!

Here’s just another invisible assignment, so let’s expand it:

x = []
y = [x]
a = [x, x, x]  The equivalent of a = y * 3
a[0].append(1)
print(a)
Copy the code

The most important thing is line 3:

  • y * 3Is to get the
    yElement replication in
    3
  • And now this element is going to be
    x.
  • let
    xrepeated
    3Time!
  • The actual effect is that
    [x, x, x].

X is a reference to the object, so we just made three copies of the reference to the object, leaving the object itself untouched.

So what do you do to actually copy this list? Using the system-provided shallow copy function, or using slicing:

# list built-in copy method
a = [x.copy() for i in range(3)]

# Using slices
a = [x[:] for i in range(3)]

Make use of the Copy library
from copy import copy
a = [copy(x) for i in range(3)]
Copy the code

The first two methods are built-in interfaces for list objects, while the copy module is more generic.

summary

  • A variable is a name bound to an object
  • When binding, the variable is the name
  • When used, a variable represents a reference to an object
  • Variables change only the binding relationship
  • To change/copy an object, you need to see if the object provides methods

In addition to the above, another important concept about variables is understanding their scope, which will be covered in another article.

If this article has been helpful to you, please like, share and follow. Thank you!