This article is divided into the following sections
- Concept
- Address issues
- As a function parameter
- Variable parameters are used in a class
- function default Parameters
- Differences in the implementation of the class
Concept
The difference between a mutable object and an immutable object is whether the object itself is mutable.
Some of the types built into Python
- mutable objects: List dict set
- Immutable object: tuple string int float bool
Give an example
# mutable object >>> a = [1, 2, 3] >>> a[1] = 4>>> a[ 1, 4, 3 " # immutable object >>> B = (1, 2, 3 >>> b[1] = 4 Traceback (most recent): File <stdin> , Line 1, in < Module>typeerror: " tuple " object does not Support Item Assignment
The above example shows intuitively that mutable objects can be changed directly, while immutable objects cannot.
address Issues
Let's take a look at the memory address change of a mutable object
>>> a = [1, 2, 3]>>> ID (a)2139167175368>>> a[1] = 4>>> ID (a)
2139167175368
We can see that the address is unchanged after the variable object has changed.
If two variables point to an address at the same time
1. mutable Objects
>>> a = [1, 2, 3]>>> ID (a)2139167246856>>> B = a>>> ID (b)2139167246856>>> a[1] = 4>>> a[1, 4, 3]>>> b[1, 4, 3 ]>>> ID (a)2139167246856>>> ID (b)2139167246856
As we can see, the change is a
b
also changed, because they always point to the same address
2. Immutable Objects
>>> a = (1, 2, 3)>>> ID (a)2139167074776>>> B = a>>> a = (4, 5, 6)>>> A (4, 5, 6)>>> B (1, 2, 3)>>> ID (a) 2139167075928>>> ID (b)2139167074776
We can see that a
after the change, its address also changed, and b
then maintain the original address, the original address of the content has not changed.
as a function parameter
1. mutable Objects
def MyFunc (L): ... L.append (1) ... Print (l) ... >>> L = [1, 2, 3]>>> myfunc (L) [1, 2, 3, 1]>>> l[1, 2, 3, 1]
As we can see, when a mutable object is passed in as a parameter, it modifies itself in the function, which affects the value of the variable in the global, because the function directly modifies the value of that address .
2. Immutable Objects
def MyFunc (a): ... + = 1 ... Print (a) ... >>> a = 2>>> myfunc (a)3>>> a2
For non-mutable objects, although the value in the function a
changes, the value in the global is a
not changed because the value in the function a
already corresponds to another address, and the value of the a
original address pointed to in the global is unchanged.
3. Summary
In Python, the pass-through argument to a function can only be a reference pass, indicating that its address is passed in, which brings up the above phenomenon.
Some programming languages allow values to be passed, that is, simply pass the values in and find an additional address in it so that the variables in the global are not affected.
variable parameters are used in a class
Let's look directly at the following example
class Myclass: def __init__ (Self, a): = a def Printa (self): print(SELF.A)
Run as follows
>>> AA = [up]>>> my = Myclass (aa)>>> My.printa () [1, 2] >>> aa.append (3)>>> My.printa () [1, 2, 3]
As we can see, the variables in the class and the global variable address are still shared, and no matter where the modification will affect the other.
In fact, this feature can not be said to be a disadvantage, to use this to do some very convenient operation, such as two threads to operate a queue at the same time, we do not have to set up a queue global
, as long as the queue this variable object passed into the class, the modification will be automatically synchronized.
The following example of producer consumers is this
Import TimeImportThreadingImportRandom fromQueueImportQueueclassProducer (Threading. Thread):def __init__(self, queue): Threading. Thread.__init__(self) self.queue=QueuedefRun (self): whileTrue:random_integer= Random.randint (0, 100) Self.queue.put (Random_integer)Print('Add {}'. Format (Random_integer)) Time.sleep (Random.random () )classConsumer (Threading. Thread):def __init__(self, queue): Threading. Thread.__init__(self) self.queue=QueuedefRun (self): whileTrue:get_integer=Self.queue.get ()Print('Lose {}'. Format (Get_integer)) Time.sleep (Random.random () )defMain (): Queue=Queue () Th1=Producer (queue) Th2=Consumer (queue) Th1.start () Th2.start ()if __name__=='__main__': Main ()
Will queue
pass in two classes, change randomly in two classes, and automatically synchronize between two classes.
function Default Parameters
The default parameter of the function must be set to immutable parameter, otherwise it will cause some errors, let's take a look at the following example
>>>defMyFunc (l=[]): ..... l.append ('Add')... Print(l) ...>>> MyFunc ([1, 2, 3])[1, 2, 3,'Add']>>> MyFunc (['a','b'])['a','b','Add']
The above code is working, so let's look at the following
>>> MyFunc () [ " add " ] >> > MyFunc () [ " add , " add " " >>> MyFunc () [ " add ", " add " , " add " ]
Supposedly every time [‘add‘]
, but now there are unexpected mistakes.
This is because it l = []
is determined at the time of the function definition , so each time you call this function, you use the l
same one, and if you do not specify a new value for this parameter, the above problem occurs.
The above l
can be set by default None
, which is an immutable object.
differences in the implementation of the class
In fact, these elements in the list tuple are equivalent to the properties of the class, modifying their equivalent to modifying the properties of the class.
Normal defines a class whose properties are normally accessed and modified, so instances of those classes are mutable objects.
We can create an immutable object simply by defining a class and not allowing it to modify the properties.
There are two main ways to use Python's Magic method
- Set a
__setattr__
direct throw exception, that is, whenever you want to set a property value, an exception is thrown
- Set
__slot__
restrictions on the access of properties, if the properties are not accessible, it must not be modified
More detailed implementations can refer to the answers on the StackOverflow
Reference
Python mutable objects and immutable objects for beginners