These variable assignments work as I expect:
>>> a = 3 >>> b = a >>> print(a, b) (3, 3) >>> b=4 >>> print(a, b) (3, 4)
However, these assignments behave differently:
>>> class number(): ... def __init__(self, name, number): ... self.name = name ... self.number = number ... >>> c = number("one", 1) >>> d = c >>> print(c.number, d.number) (1, 1) >>> d.number = 2 >>> print(c.number, d.number) (2, 2)
Why is c
is same as d
, unlike in (a, b)
example? How can I do something like in (a, b)
in (c, d)
classes example? That is, copy the object and then change one part of it (that won't affect the object that I borrowed properties from)?
A letter or symbol that represents any member of a collection of two or more numbers is called a variable. A letter or symbol that represents one specific number, known or unknown, is called a constant.
Rules for Python variables: A variable name must start with a letter or the underscore character. A variable name cannot start with a number. A variable name can only contain alpha-numeric characters and underscores (A-z, 0-9, and _ )
The two most widely known and easy to understand approaches to parameter passing amongst programming languages are pass-by-reference and pass-by-value. Unfortunately, Python is “pass-by-object-reference”, of which it is often said: “Object references are passed by value.”
To set the value of a variable is it's equal to null , use the nullish coalescing operator, e.g. myVar = myVar ?? 'new value' .
These lines:
c = number("one", 1) d = c
...are effectively:
number
and assign it to c
c
to a new variable d
You haven't changed or modified anything about c
; d
is another name that points to the same instance.
Without cloning the instance or creating a new instance, you can't do anything similar to how the primitive int is behaving.
To correct a bit of information, the explanation above is rather simplified and a bit incomplete in its nature, although it mostly describes what's going on at 10,000 feet.
For a closer look, we have to realize a few things about Python's variables, or "names", and how they interact with this program.
As mentioned above, you have the notion of "names" and "bindings", which are pretty straightforward to reason at:
a = 3 b = a
In this context, a
is a name, and b
is a binding to a
. We haven't modified or changed anything about a
.
As noted before, there are two types of data in Python: mutable and immutable. A name that points to immutable data, such as primitives and tuples, can be reassigned without any ill effect to any other bindings present on it, because no state is changing with respect to the binding.
This is why this reassignment does what we would expect it to:
print(a, b) b = 4 print(a, b)
The result of b = 4
is that b
is now pointing at a new copy of an integer, the value 4.
Recall that I did mention tuples as immutable data. You can't change the binding of a particular entity in your tuple...
t = ('foo', 'bar') t[0] = 'baz' # illegal
...but you can have mutable data structures as part of those bindings.
t = ([1, 2, 3], 'bar') t[0].append([4, 5, 6]) # ([1, 2, 3, [4, 5, 6]], 'bar')
So where does that leave our example?
c = number("one", 1) d = c
number
is a mutable type which is named as c
, and its values can be changed at will between multiple different bindings to c
.
Effectively, we've got a name and a binding to a name:
number
and refer to it by the name c
.c
to another name d
.Again, nothing's changed about c
, but it can be referenced through another name.
Unlike with the immutable data, when we reassign the value of d.number
, we're reassigning the same binding that c
is aware of:
>>> id(d.number) 36696408 >>> id(c.number) 36696408
This is why you require either a new instance or a copy. You have to refer to a different instance of number
. With this simple binding, you're not going to accomplish that.
from copy import copy c = number("one", 1) d = copy(c) id(c) # 140539175695784 id(d) # 140539175695856
I didn't see that anyone provided details on how to make these two cases work the same by copying the object instead of just assigning a new reference to the same object.
import copy c = number("one", 1) d = c e = copy.copy(c) print(c.number, d.number, e.number) d.number = 2 e.number = 5 print(c.number, d.number, e.number)
This will give you:
1 1 1 2 2 5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With