Creating a list in Python- something sneaky going on? - python

Apologies if this doesn't make any sense, I'm very new to Python!
From testing in an interpreter, I can see that list() and [] both produce an empty list:
>>> list()
[]
>>> []
[]
From what I've learned so far, the only way to create an object is to call its constructor (__init__), but I don't see this happening when I just type []. So by executing [], is Python then mapping that to a call to list()?

Those two constructs are handled quite differently:
>>> import dis
>>> def f(): return []
...
>>> dis.dis(f)
1 0 BUILD_LIST 0
3 RETURN_VALUE
>>> def f(): return list()
...
>>> dis.dis(f)
1 0 LOAD_GLOBAL 0 (list)
3 CALL_FUNCTION 0
6 RETURN_VALUE
>>>
The [] form constructs a list using the opcode BUILD_LIST, whereas the list() form calls the list object's constructor.

No, Python does not call list(), or you could affect what type [] creates by assigning to list, which you cant:
>>> import __builtin__
>>> __builtin__.list = set
>>> list()
set([])
>>> []
[]
[] is syntax for creating a list. It's a builtin type and it has special syntax, just like dicts and strings and ints and floats and lots of other types.
Creating instances of types can also be done by calling the type, like list() -- which will in turn call the type's constructor and initializer for you. Calling the initializer (__init__) directly does not create a new instance of the type. Calling the constructor (__new__) does, but you should not be calling it directly.

I started learning python yesterday....
I guess you would have to say its internally mapped
>>> a = []
>>> type(a)
<type 'list'>
>>> a = list()
>>> type(a)
<type 'list'>

What are the key differences between using list() and []?
The most obvious and visible key difference between list() and [] is the syntax. Putting the syntax aside for a minute here, someone whose new or intermediately exposed to python might argue that they’re both lists or derive from the same class; that is true. Which furthermore increases the importance of understanding the key differences of both, most of which are outlined below.
list() is a function and [] is literal syntax.
Let’s take a look at what happens when we call list() and [] respectively through the disassembler.
>>> import dis
>>> print(dis.dis(lambda: list()))
1 0 LOAD_GLOBAL 0 (list)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 RETURN_VALUE
None
>>> print(dis.dis(lambda: []))
1 0 BUILD_LIST 0
3 RETURN_VALUE
None
The output from the disassembler above shows that the literal syntax version doesn’t require a global lookup, denoted by the op code LOAD_GLOBAL or a function call, denoted by the op code CALL_FUNCTION.
As a result, literal syntax is faster than it’s counterpart. – Let’s take a second and look at the timings below.
import timeit
>>> timeit.timeit('[]', number=10**4)
0.0014592369552701712
>>> timeit.timeit('list()', number=10**4)
0.0033833282068371773
On another note it’s equally important and worth pointing out that literal syntax, [] does not unpack values. An example of unpacking is shown below.
>>> list('abc') # unpacks value
['a', 'b', 'c']
>>> ['abc'] # value remains packed
['abc']
What’s a literal in python?
Literals are notations or a way of writing constant or raw variable values which python recognises as built-in types.
Sourced from my post on PythonRight - what's the difference between list and [].

In addition to the other answers, from the Language Reference:
A list display is a possibly empty series of expressions enclosed in square brackets:
list_display ::= "[" [expression_list | list_comprehension] "]"
...
A list display yields a new list object.
It does not explicitly mention how "yielding a new list object" is implemented. It could well be a call to the list() constructor, like you mentioned. Or maybe lists, being so elementary, get special treatment, and list() is actually mapped to something different entirely.
Either way, [] is certainly not mapped to a call to the constructor of the type named __builtins__.list, because redefining that type still causes [] to return an actual list, as other answerers have shown.

Python, like most programming langauges, has something called literals, meaning that special syntax can be used to write out some of the most important types of values. Very little of this is necessary, but it makes it easier to use Python that we can write literals.
>>> 0
0
>>> int()
0
>>> 5
5
>>> int('5') # I'm using a string literal here though!
5
>>> 0.0
0.0
>>> float()
0.0
>>> ""
''
>>> str()
''
>>> u""
u''
>>> unicode()
u''
>>> ()
()
>>> tuple()
()
>>> {}
{}
>>> dict()
{}
When we make our own types (classes), we create instances of them using their constructors, like list for lists. When we use literals, it's sort of like syntactic sugar for calling list, but in reality it calls that same basic things behind the scene.

Since :
class list(object):
"""
list() -> new empty list
list(iterable) -> new list initialized from iterable's items
"""
If the element in your lists is an iterable (i.e. a str), the list() and [] don't work the same way.
So
>>> a = ['ab']
>>> b = list('ab')
>>> a[0]
'ab'
>>> b[0]
'a'

Related

In which ways are Python strings lists? [duplicate]

I'm confused on what an immutable type is. I know the float object is considered to be immutable, with this type of example from my book:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
Is this considered to be immutable because of the class structure / hierarchy?, meaning float is at the top of the class and is its own method call. Similar to this type of example (even though my book says dict is mutable):
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Whereas something mutable has methods inside the class, with this type of example:
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
Also, for the last class(SortedKeyDict_a), if I pass this type of set to it:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
without calling the example method, it returns a dictionary. The SortedKeyDict with __new__ flags it as an error. I tried passing integers to the RoundFloat class with __new__ and it flagged no errors.
What? Floats are immutable? But can't I do
x = 5.0
x += 7.0
print x # 12.0
Doesn't that "mut" x?
Well you agree strings are immutable right? But you can do the same thing.
s = 'foo'
s += 'bar'
print s # foobar
The value of the variable changes, but it changes by changing what the variable refers to. A mutable type can change that way, and it can also change "in place".
Here is the difference.
x = something # immutable type
print x
func(x)
print x # prints the same thing
x = something # mutable type
print x
func(x)
print x # might print something different
x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing
x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different
Concrete examples
x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo
x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]
def func(val):
val += 'bar'
x = 'foo'
print x # foo
func(x)
print x # foo
def func(val):
val += [3, 2, 1]
x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]
You have to understand that Python represents all its data as objects. Some of these objects like lists and dictionaries are mutable, meaning you can change their content without changing their identity. Other objects like integers, floats, strings and tuples are objects that can not be changed.
An easy way to understand that is if you have a look at an objects ID.
Below you see a string that is immutable. You can not change its content. It will raise a TypeError if you try to change it. Also, if we assign new content, a new object is created instead of the contents being modified.
>>> s = "abc"
>>> id(s)
4702124
>>> s[0]
'a'
>>> s[0] = "o"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>> id(s)
4800100
>>> s += "uvw"
>>> id(s)
4800500
You can do that with a list and it will not change the objects identity
>>> i = [1,2,3]
>>> id(i)
2146718700
>>> i[0]
1
>>> i[0] = 7
>>> id(i)
2146718700
To read more about Python's data model you could have a look at the Python language reference:
Python 2 datamodel
Python 3 datamodel
Common immutable type:
numbers: int(), float(), complex()
immutable sequences: str(), tuple(), frozenset(), bytes()
Common mutable type (almost everything else):
mutable sequences: list(), bytearray()
set type: set()
mapping type: dict()
classes, class instances
etc.
One trick to quickly test if a type is mutable or not, is to use id() built-in function.
Examples, using on integer,
>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)
using on list,
>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)
First of all, whether a class has methods or what it's class structure is has nothing to do with mutability.
ints and floats are immutable. If I do
a = 1
a += 5
It points the name a at a 1 somewhere in memory on the first line. On the second line, it looks up that 1, adds 5, gets 6, then points a at that 6 in memory -- it didn't change the 1 to a 6 in any way. The same logic applies to the following examples, using other immutable types:
b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')
For mutable types, I can do thing that actallly change the value where it's stored in memory. With:
d = [1, 2, 3]
I've created a list of the locations of 1, 2, and 3 in memory. If I then do
e = d
I just point e to the same list d points at. I can then do:
e += [4, 5]
And the list that both e and d points at will be updated to also have the locations of 4 and 5 in memory.
If I go back to an immutable type and do that with a tuple:
f = (1, 2, 3)
g = f
g += (4, 5)
Then f still only points to the original tuple -- you've pointed g at an entirely new tuple.
Now, with your example of
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Where you pass
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
(which is a tuple of tuples) as val, you're getting an error because tuples don't have a .clear() method -- you'd have to pass dict(d) as val for it to work, in which case you'll get an empty SortedKeyDict as a result.
Difference between Mutable and Immutable objects
Definitions
Mutable object: Object that can be changed after creating it.
Immutable object: Object that cannot be changed after creating it.
In Python if you change the value of the immutable object it will create a new object.
Mutable Objects
Here are the objects in Python that are of mutable type:
list
Dictionary
Set
bytearray
user defined classes
Immutable Objects
Here are the objects in Python that are of immutable type:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Some Unanswered Questions
Question: Is string an immutable type?
Answer: yes it is, but can you explain this:
Proof 1:
a = "Hello"
a +=" World"
print a
Output
"Hello World"
In the above example the string got once created as "Hello" then changed to "Hello World". This implies that the string is of the mutable type. But it is not when we check its identity to see whether it is of a mutable type or not.
a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
print "String is Immutable"
Output
String is Immutable
Proof 2:
a = "Hello World"
a[0] = "M"
Output
TypeError 'str' object does not support item assignment
Question: Is Tuple an immutable type?
Answer: yes, it is.
Proof 1:
tuple_a = (1,)
tuple_a[0] = (2,)
print a
Output
'tuple' object does not support item assignment
If you're coming to Python from another language (except one that's a lot like Python, like Ruby), and insist on understanding it in terms of that other language, here's where people usually get confused:
>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!
In Python, assignment is not mutation in Python.
In C++, if you write a = 2, you're calling a.operator=(2), which will mutate the object stored in a. (And if there was no object stored in a, that's an error.)
In Python, a = 2 does nothing to whatever was stored in a; it just means that 2 is now stored in a instead. (And if there was no object stored in a, that's fine.)
Ultimately, this is part of an even deeper distinction.
A variable in a language like C++ is a typed location in memory. If a is an int, that means it's 4 bytes somewhere that the compiler knows is supposed to be interpreted as an int. So, when you do a = 2, it changes what's stored in those 4 bytes of memory from 0, 0, 0, 1 to 0, 0, 0, 2. If there's another int variable somewhere else, it has its own 4 bytes.
A variable in a language like Python is a name for an object that has a life of its own. There's an object for the number 1, and another object for the number 2. And a isn't 4 bytes of memory that are represented as an int, it's just a name that points at the 1 object. It doesn't make sense for a = 2 to turn the number 1 into the number 2 (that would give any Python programmer way too much power to change the fundamental workings of the universe); what it does instead is just make a forget the 1 object and point at the 2 object instead.
So, if assignment isn't a mutation, what is a mutation?
Calling a method that's documented to mutate, like a.append(b). (Note that these methods almost always return None). Immutable types do not have any such methods, mutable types usually do.
Assigning to a part of the object, like a.spam = b or a[0] = b. Immutable types do not allow assignment to attributes or elements, mutable types usually allow one or the other.
Sometimes using augmented assignment, like a += b, sometimes not. Mutable types usually mutate the value; immutable types never do, and give you a copy instead (they calculate a + b, then assign the result to a).
But if assignment isn't mutation, how is assigning to part of the object mutation? That's where it gets tricky. a[0] = b does not mutate a[0] (again, unlike C++), but it does mutate a (unlike C++, except indirectly).
All of this is why it's probably better not to try to put Python's semantics in terms of a language you're used to, and instead learn Python's semantics on their own terms.
Whether an object is mutable or not depends on its type. This doesn't depend on whether or not it has certain methods, nor on the structure of the class hierarchy.
User-defined types (i.e. classes) are generally mutable. There are some exceptions, such as simple sub-classes of an immutable type. Other immutable types include some built-in types such as int, float, tuple and str, as well as some Python classes implemented in C.
A general explanation from the "Data Model" chapter in the Python Language Reference":
The value of some objects can change. Objects whose value can change
are said to be mutable; objects whose value is unchangeable once they
are created are called immutable.
(The value of an immutable container
object that contains a reference to a mutable object can change when
the latter’s value is changed; however the container is still
considered immutable, because the collection of objects it contains
cannot be changed. So, immutability is not strictly the same as having
an unchangeable value, it is more subtle.)
An object’s mutability is
determined by its type; for instance, numbers, strings and tuples are
immutable, while dictionaries and lists are mutable.
A mutable object has to have at least a method able to mutate the object. For example, the list object has the append method, which will actually mutate the object:
>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']
but the class float has no method to mutate a float object. You can do:
>>> b = 5.0
>>> b = b + 0.1
>>> b
5.1
but the = operand is not a method. It just make a bind between the variable and whatever is to the right of it, nothing else. It never changes or creates objects. It is a declaration of what the variable will point to, since now on.
When you do b = b + 0.1 the = operand binds the variable to a new float, wich is created with te result of 5 + 0.1.
When you assign a variable to an existent object, mutable or not, the = operand binds the variable to that object. And nothing more happens
In either case, the = just make the bind. It doesn't change or create objects.
When you do a = 1.0, the = operand is not wich create the float, but the 1.0 part of the line. Actually when you write 1.0 it is a shorthand for float(1.0) a constructor call returning a float object. (That is the reason why if you type 1.0 and press enter you get the "echo" 1.0 printed below; that is the return value of the constructor function you called)
Now, if b is a float and you assign a = b, both variables are pointing to the same object, but actually the variables can't comunicate betweem themselves, because the object is inmutable, and if you do b += 1, now b point to a new object, and a is still pointing to the oldone and cannot know what b is pointing to.
but if c is, let's say, a list, and you assign a = c, now a and c can "comunicate", because list is mutable, and if you do c.append('msg'), then just checking a you get the message.
(By the way, every object has an unique id number asociated to, wich you can get with id(x). So you can check if an object is the same or not checking if its unique id has changed.)
A class is immutable if each object of that class has a fixed value upon instantiation that cannot SUBSEQUENTLY be changed
In another word change the entire value of that variable (name) or leave it alone.
Example:
my_string = "Hello world"
my_string[0] = "h"
print my_string
you expected this to work and print hello world but this will throw the following error:
Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment
The interpreter is saying : i can't change the first character of this string
you will have to change the whole string in order to make it works:
my_string = "Hello World"
my_string = "hello world"
print my_string #hello world
check this table:
source
It would seem to me that you are fighting with the question what mutable/immutable actually means. So here is a simple explenation:
First we need a foundation to base the explenation on.
So think of anything that you program as a virtual object, something that is saved in a computers memory as a sequence of binary numbers. (Don't try to imagine this too hard, though.^^) Now in most computer languages you will not work with these binary numbers directly, but rather more you use an interpretation of binary numbers.
E.g. you do not think about numbers like 0x110, 0xaf0278297319 or similar, but instead you think about numbers like 6 or Strings like "Hello, world". Never the less theses numbers or Strings are an interpretation of a binary number in the computers memory. The same is true for any value of a variable.
In short: We do not program with actual values but with interpretations of actual binary values.
Now we do have interpretations that must not be changed for the sake of logic and other "neat stuff" while there are interpretations that may well be changed. For example think of the simulation of a city, in other words a program where there are many virtual objects and some of these are houses. Now may these virtual objects (the houses) be changed and can they still be considered to be the same houses? Well of course they can. Thus they are mutable: They can be changed without becoming a "completely" different object.
Now think of integers: These also are virtual objects (sequences of binary numbers in a computers memory). So if we change one of them, like incrementing the value six by one, is it still a six? Well of course not. Thus any integer is immutable.
So: If any change in a virtual object means that it actually becomes another virtual object, then it is called immutable.
Final remarks:
(1) Never mix up your real-world experience of mutable and immutable with programming in a certain language:
Every programming language has a definition of its own on which objects may be muted and which ones may not.
So while you may now understand the difference in meaning, you still have to learn the actual implementation for each programming language. ... Indeed there might be a purpose of a language where a 6 may be muted to become a 7. Then again this would be quite some crazy or interesting stuff, like simulations of parallel universes.^^
(2) This explenation is certainly not scientific, it is meant to help you to grasp the difference between mutable and immutable.
The goal of this answer is to create a single place to find all the good ideas about how to tell if you are dealing with mutating/nonmutating (immutable/mutable), and where possible, what to do about it? There are times when mutation is undesirable and python's behavior in this regard can feel counter-intuitive to coders coming into it from other languages.
As per a useful post by #mina-gabriel:
Books to read that might help: "Data Structures and Algorithms in Python"
Excerpt from that book that lists mutable/immutable types:
mutable/imutable types image
Analyzing the above and combining w/ a post by #arrakëën:
What cannot change unexpectedly?
scalars (variable types storing a single value) do not change unexpectedly
numeric examples: int(), float(), complex()
there are some "mutable sequences":
str(), tuple(), frozenset(), bytes()
What can?
list like objects (lists, dictionaries, sets, bytearray())
a post on here also says classes and class instances but this may depend on what the class inherits from and/or how its built.
by "unexpectedly" I mean that programmers from other languages might not expect this behavior (with the exception or Ruby, and maybe a few other "Python like" languages).
Adding to this discussion:
This behavior is an advantage when it prevents you from accidentally populating your code with mutliple copies of memory-eating large data structures. But when this is undesirable, how do we get around it?
With lists, the simple solution is to build a new one like so:
list2 = list(list1)
with other structures ... the solution can be trickier. One way is to loop through the elements and add them to a new empty data structure (of the same type).
functions can mutate the original when you pass in mutable structures. How to tell?
There are some tests given on other comments on this thread but then there are comments indicating these tests are not full proof
object.function() is a method of the original object but only some of these mutate. If they return nothing, they probably do. One would expect .append() to mutate without testing it given its name. .union() returns the union of set1.union(set2) and does not mutate. When in doubt, the function can be checked for a return value. If return = None, it does not mutate.
sorted() might be a workaround in some cases. Since it returns a sorted version of the original, it can allow you to store a non-mutated copy before you start working on the original in other ways. However, this option assumes you don't care about the order of the original elements (if you do, you need to find another way). In contrast .sort() mutates the original (as one might expect).
Non-standard Approaches (in case helpful):
Found this on github published under an MIT license:
github repository under: tobgu named: pyrsistent
What it is: Python persistent data structure code written to be used in place of core data structures when mutation is undesirable
For custom classes, #semicolon suggests checking if there is a __hash__ function because mutable objects should generally not have a __hash__() function.
This is all I have amassed on this topic for now. Other ideas, corrections, etc. are welcome. Thanks.
One way of thinking of the difference:
Assignments to immutable objects in python can be thought of as deep copies,
whereas assignments to mutable objects are shallow
The simplest answer:
A mutable variable is one whose value may change in place, whereas in an immutable variable change of value will not happen in place. Modifying an immutable variable will rebuild the same variable.
Example:
>>>x = 5
Will create a value 5 referenced by x
x -> 5
>>>y = x
This statement will make y refer to 5 of x
x -------------> 5 <-----------y
>>>x = x + y
As x being an integer (immutable type) has been rebuild.
In the statement, the expression on RHS will result into value 10 and when this is assigned to LHS (x), x will rebuild to 10. So now
x--------->10
y--------->5
Mutable means that it can change/mutate. Immutable the opposite.
Some Python data types are mutable, others not.
Let's find what are the types that fit in each category and see some examples.
Mutable
In Python there are various mutable types:
lists
dict
set
Let's see the following example for lists.
list = [1, 2, 3, 4, 5]
If I do the following to change the first element
list[0] = '!'
#['!', '2', '3', '4', '5']
It works just fine, as lists are mutable.
If we consider that list, that was changed, and assign a variable to it
y = list
And if we change an element from the list such as
list[0] = 'Hello'
#['Hello', '2', '3', '4', '5']
And if one prints y it will give
['Hello', '2', '3', '4', '5']
As both list and y are referring to the same list, and we have changed the list.
Immutable
In some programming languages one can define a constant such as the following
const a = 10
And if one calls, it would give an error
a = 20
However, that doesn't exist in Python.
In Python, however, there are various immutable types:
None
bool
int
float
str
tuple
Let's see the following example for strings.
Taking the string a
a = 'abcd'
We can get the first element with
a[0]
#'a'
If one tries to assign a new value to the element in the first position
a[0] = '!'
It will give an error
'str' object does not support item assignment
When one says += to a string, such as
a += 'e'
#'abcde'
It doesn't give an error, because it is pointing a to a different string.
It would be the same as the following
a = a + 'f'
And not changing the string.
Some Pros and Cons of being immutable
• The space in memory is known from the start. It would not require extra space.
• Usually, it makes things more efficiently. Finding, for example, the len() of a string is much faster, as it is part of the string object.
Every time we change value of a immutable variable it basically destroy the previous instance and create a new instance of variable class
var = 2 #Immutable data
print(id(var))
var += 4
print(id(var))
list_a = [1,2,3] #Mutable data
print(id(list_a))
list_a[0]= 4
print(id(list_a))
Output:
9789024
9789088
140010877705856
140010877705856
Note:Mutable variable memory_location is change when we change the value
I haven't read all the answers, but the selected answer is not correct and I think the author has an idea that being able to reassign a variable means that whatever datatype is mutable. That is not the case. Mutability has to do with passing by reference rather than passing by value.
Lets say you created a List
a = [1,2]
If you were to say:
b = a
b[1] = 3
Even though you reassigned a value on B, it will also reassign the value on a. Its because when you assign "b = a". You are passing the "Reference" to the object rather than a copy of the value. This is not the case with strings, floats etc. This makes list, dictionaries and the likes mutable, but booleans, floats etc immutable.
In Python, there's a easy way to know:
Immutable:
>>> s='asd'
>>> s is 'asd'
True
>>> s=None
>>> s is None
True
>>> s=123
>>> s is 123
True
Mutable:
>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False
And:
>>> s=abs
>>> s is abs
True
So I think built-in function is also immutable in Python.
But I really don't understand how float works:
>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256
It's so weird.
For immutable objects, assignment creates a new copy of values, for example.
x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot
#effect the value of y
print(x,y)
For mutable objects, the assignment doesn't create another copy of values. For example,
x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy
x[2]=5
print(x,y) # both x&y holds the same list

Strange behaviour when passing objects into classes [duplicate]

I'm confused on what an immutable type is. I know the float object is considered to be immutable, with this type of example from my book:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
Is this considered to be immutable because of the class structure / hierarchy?, meaning float is at the top of the class and is its own method call. Similar to this type of example (even though my book says dict is mutable):
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Whereas something mutable has methods inside the class, with this type of example:
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
Also, for the last class(SortedKeyDict_a), if I pass this type of set to it:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
without calling the example method, it returns a dictionary. The SortedKeyDict with __new__ flags it as an error. I tried passing integers to the RoundFloat class with __new__ and it flagged no errors.
What? Floats are immutable? But can't I do
x = 5.0
x += 7.0
print x # 12.0
Doesn't that "mut" x?
Well you agree strings are immutable right? But you can do the same thing.
s = 'foo'
s += 'bar'
print s # foobar
The value of the variable changes, but it changes by changing what the variable refers to. A mutable type can change that way, and it can also change "in place".
Here is the difference.
x = something # immutable type
print x
func(x)
print x # prints the same thing
x = something # mutable type
print x
func(x)
print x # might print something different
x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing
x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different
Concrete examples
x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo
x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]
def func(val):
val += 'bar'
x = 'foo'
print x # foo
func(x)
print x # foo
def func(val):
val += [3, 2, 1]
x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]
You have to understand that Python represents all its data as objects. Some of these objects like lists and dictionaries are mutable, meaning you can change their content without changing their identity. Other objects like integers, floats, strings and tuples are objects that can not be changed.
An easy way to understand that is if you have a look at an objects ID.
Below you see a string that is immutable. You can not change its content. It will raise a TypeError if you try to change it. Also, if we assign new content, a new object is created instead of the contents being modified.
>>> s = "abc"
>>> id(s)
4702124
>>> s[0]
'a'
>>> s[0] = "o"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>> id(s)
4800100
>>> s += "uvw"
>>> id(s)
4800500
You can do that with a list and it will not change the objects identity
>>> i = [1,2,3]
>>> id(i)
2146718700
>>> i[0]
1
>>> i[0] = 7
>>> id(i)
2146718700
To read more about Python's data model you could have a look at the Python language reference:
Python 2 datamodel
Python 3 datamodel
Common immutable type:
numbers: int(), float(), complex()
immutable sequences: str(), tuple(), frozenset(), bytes()
Common mutable type (almost everything else):
mutable sequences: list(), bytearray()
set type: set()
mapping type: dict()
classes, class instances
etc.
One trick to quickly test if a type is mutable or not, is to use id() built-in function.
Examples, using on integer,
>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)
using on list,
>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)
First of all, whether a class has methods or what it's class structure is has nothing to do with mutability.
ints and floats are immutable. If I do
a = 1
a += 5
It points the name a at a 1 somewhere in memory on the first line. On the second line, it looks up that 1, adds 5, gets 6, then points a at that 6 in memory -- it didn't change the 1 to a 6 in any way. The same logic applies to the following examples, using other immutable types:
b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')
For mutable types, I can do thing that actallly change the value where it's stored in memory. With:
d = [1, 2, 3]
I've created a list of the locations of 1, 2, and 3 in memory. If I then do
e = d
I just point e to the same list d points at. I can then do:
e += [4, 5]
And the list that both e and d points at will be updated to also have the locations of 4 and 5 in memory.
If I go back to an immutable type and do that with a tuple:
f = (1, 2, 3)
g = f
g += (4, 5)
Then f still only points to the original tuple -- you've pointed g at an entirely new tuple.
Now, with your example of
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Where you pass
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
(which is a tuple of tuples) as val, you're getting an error because tuples don't have a .clear() method -- you'd have to pass dict(d) as val for it to work, in which case you'll get an empty SortedKeyDict as a result.
Difference between Mutable and Immutable objects
Definitions
Mutable object: Object that can be changed after creating it.
Immutable object: Object that cannot be changed after creating it.
In Python if you change the value of the immutable object it will create a new object.
Mutable Objects
Here are the objects in Python that are of mutable type:
list
Dictionary
Set
bytearray
user defined classes
Immutable Objects
Here are the objects in Python that are of immutable type:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Some Unanswered Questions
Question: Is string an immutable type?
Answer: yes it is, but can you explain this:
Proof 1:
a = "Hello"
a +=" World"
print a
Output
"Hello World"
In the above example the string got once created as "Hello" then changed to "Hello World". This implies that the string is of the mutable type. But it is not when we check its identity to see whether it is of a mutable type or not.
a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
print "String is Immutable"
Output
String is Immutable
Proof 2:
a = "Hello World"
a[0] = "M"
Output
TypeError 'str' object does not support item assignment
Question: Is Tuple an immutable type?
Answer: yes, it is.
Proof 1:
tuple_a = (1,)
tuple_a[0] = (2,)
print a
Output
'tuple' object does not support item assignment
If you're coming to Python from another language (except one that's a lot like Python, like Ruby), and insist on understanding it in terms of that other language, here's where people usually get confused:
>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!
In Python, assignment is not mutation in Python.
In C++, if you write a = 2, you're calling a.operator=(2), which will mutate the object stored in a. (And if there was no object stored in a, that's an error.)
In Python, a = 2 does nothing to whatever was stored in a; it just means that 2 is now stored in a instead. (And if there was no object stored in a, that's fine.)
Ultimately, this is part of an even deeper distinction.
A variable in a language like C++ is a typed location in memory. If a is an int, that means it's 4 bytes somewhere that the compiler knows is supposed to be interpreted as an int. So, when you do a = 2, it changes what's stored in those 4 bytes of memory from 0, 0, 0, 1 to 0, 0, 0, 2. If there's another int variable somewhere else, it has its own 4 bytes.
A variable in a language like Python is a name for an object that has a life of its own. There's an object for the number 1, and another object for the number 2. And a isn't 4 bytes of memory that are represented as an int, it's just a name that points at the 1 object. It doesn't make sense for a = 2 to turn the number 1 into the number 2 (that would give any Python programmer way too much power to change the fundamental workings of the universe); what it does instead is just make a forget the 1 object and point at the 2 object instead.
So, if assignment isn't a mutation, what is a mutation?
Calling a method that's documented to mutate, like a.append(b). (Note that these methods almost always return None). Immutable types do not have any such methods, mutable types usually do.
Assigning to a part of the object, like a.spam = b or a[0] = b. Immutable types do not allow assignment to attributes or elements, mutable types usually allow one or the other.
Sometimes using augmented assignment, like a += b, sometimes not. Mutable types usually mutate the value; immutable types never do, and give you a copy instead (they calculate a + b, then assign the result to a).
But if assignment isn't mutation, how is assigning to part of the object mutation? That's where it gets tricky. a[0] = b does not mutate a[0] (again, unlike C++), but it does mutate a (unlike C++, except indirectly).
All of this is why it's probably better not to try to put Python's semantics in terms of a language you're used to, and instead learn Python's semantics on their own terms.
Whether an object is mutable or not depends on its type. This doesn't depend on whether or not it has certain methods, nor on the structure of the class hierarchy.
User-defined types (i.e. classes) are generally mutable. There are some exceptions, such as simple sub-classes of an immutable type. Other immutable types include some built-in types such as int, float, tuple and str, as well as some Python classes implemented in C.
A general explanation from the "Data Model" chapter in the Python Language Reference":
The value of some objects can change. Objects whose value can change
are said to be mutable; objects whose value is unchangeable once they
are created are called immutable.
(The value of an immutable container
object that contains a reference to a mutable object can change when
the latter’s value is changed; however the container is still
considered immutable, because the collection of objects it contains
cannot be changed. So, immutability is not strictly the same as having
an unchangeable value, it is more subtle.)
An object’s mutability is
determined by its type; for instance, numbers, strings and tuples are
immutable, while dictionaries and lists are mutable.
A mutable object has to have at least a method able to mutate the object. For example, the list object has the append method, which will actually mutate the object:
>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']
but the class float has no method to mutate a float object. You can do:
>>> b = 5.0
>>> b = b + 0.1
>>> b
5.1
but the = operand is not a method. It just make a bind between the variable and whatever is to the right of it, nothing else. It never changes or creates objects. It is a declaration of what the variable will point to, since now on.
When you do b = b + 0.1 the = operand binds the variable to a new float, wich is created with te result of 5 + 0.1.
When you assign a variable to an existent object, mutable or not, the = operand binds the variable to that object. And nothing more happens
In either case, the = just make the bind. It doesn't change or create objects.
When you do a = 1.0, the = operand is not wich create the float, but the 1.0 part of the line. Actually when you write 1.0 it is a shorthand for float(1.0) a constructor call returning a float object. (That is the reason why if you type 1.0 and press enter you get the "echo" 1.0 printed below; that is the return value of the constructor function you called)
Now, if b is a float and you assign a = b, both variables are pointing to the same object, but actually the variables can't comunicate betweem themselves, because the object is inmutable, and if you do b += 1, now b point to a new object, and a is still pointing to the oldone and cannot know what b is pointing to.
but if c is, let's say, a list, and you assign a = c, now a and c can "comunicate", because list is mutable, and if you do c.append('msg'), then just checking a you get the message.
(By the way, every object has an unique id number asociated to, wich you can get with id(x). So you can check if an object is the same or not checking if its unique id has changed.)
A class is immutable if each object of that class has a fixed value upon instantiation that cannot SUBSEQUENTLY be changed
In another word change the entire value of that variable (name) or leave it alone.
Example:
my_string = "Hello world"
my_string[0] = "h"
print my_string
you expected this to work and print hello world but this will throw the following error:
Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment
The interpreter is saying : i can't change the first character of this string
you will have to change the whole string in order to make it works:
my_string = "Hello World"
my_string = "hello world"
print my_string #hello world
check this table:
source
It would seem to me that you are fighting with the question what mutable/immutable actually means. So here is a simple explenation:
First we need a foundation to base the explenation on.
So think of anything that you program as a virtual object, something that is saved in a computers memory as a sequence of binary numbers. (Don't try to imagine this too hard, though.^^) Now in most computer languages you will not work with these binary numbers directly, but rather more you use an interpretation of binary numbers.
E.g. you do not think about numbers like 0x110, 0xaf0278297319 or similar, but instead you think about numbers like 6 or Strings like "Hello, world". Never the less theses numbers or Strings are an interpretation of a binary number in the computers memory. The same is true for any value of a variable.
In short: We do not program with actual values but with interpretations of actual binary values.
Now we do have interpretations that must not be changed for the sake of logic and other "neat stuff" while there are interpretations that may well be changed. For example think of the simulation of a city, in other words a program where there are many virtual objects and some of these are houses. Now may these virtual objects (the houses) be changed and can they still be considered to be the same houses? Well of course they can. Thus they are mutable: They can be changed without becoming a "completely" different object.
Now think of integers: These also are virtual objects (sequences of binary numbers in a computers memory). So if we change one of them, like incrementing the value six by one, is it still a six? Well of course not. Thus any integer is immutable.
So: If any change in a virtual object means that it actually becomes another virtual object, then it is called immutable.
Final remarks:
(1) Never mix up your real-world experience of mutable and immutable with programming in a certain language:
Every programming language has a definition of its own on which objects may be muted and which ones may not.
So while you may now understand the difference in meaning, you still have to learn the actual implementation for each programming language. ... Indeed there might be a purpose of a language where a 6 may be muted to become a 7. Then again this would be quite some crazy or interesting stuff, like simulations of parallel universes.^^
(2) This explenation is certainly not scientific, it is meant to help you to grasp the difference between mutable and immutable.
The goal of this answer is to create a single place to find all the good ideas about how to tell if you are dealing with mutating/nonmutating (immutable/mutable), and where possible, what to do about it? There are times when mutation is undesirable and python's behavior in this regard can feel counter-intuitive to coders coming into it from other languages.
As per a useful post by #mina-gabriel:
Books to read that might help: "Data Structures and Algorithms in Python"
Excerpt from that book that lists mutable/immutable types:
mutable/imutable types image
Analyzing the above and combining w/ a post by #arrakëën:
What cannot change unexpectedly?
scalars (variable types storing a single value) do not change unexpectedly
numeric examples: int(), float(), complex()
there are some "mutable sequences":
str(), tuple(), frozenset(), bytes()
What can?
list like objects (lists, dictionaries, sets, bytearray())
a post on here also says classes and class instances but this may depend on what the class inherits from and/or how its built.
by "unexpectedly" I mean that programmers from other languages might not expect this behavior (with the exception or Ruby, and maybe a few other "Python like" languages).
Adding to this discussion:
This behavior is an advantage when it prevents you from accidentally populating your code with mutliple copies of memory-eating large data structures. But when this is undesirable, how do we get around it?
With lists, the simple solution is to build a new one like so:
list2 = list(list1)
with other structures ... the solution can be trickier. One way is to loop through the elements and add them to a new empty data structure (of the same type).
functions can mutate the original when you pass in mutable structures. How to tell?
There are some tests given on other comments on this thread but then there are comments indicating these tests are not full proof
object.function() is a method of the original object but only some of these mutate. If they return nothing, they probably do. One would expect .append() to mutate without testing it given its name. .union() returns the union of set1.union(set2) and does not mutate. When in doubt, the function can be checked for a return value. If return = None, it does not mutate.
sorted() might be a workaround in some cases. Since it returns a sorted version of the original, it can allow you to store a non-mutated copy before you start working on the original in other ways. However, this option assumes you don't care about the order of the original elements (if you do, you need to find another way). In contrast .sort() mutates the original (as one might expect).
Non-standard Approaches (in case helpful):
Found this on github published under an MIT license:
github repository under: tobgu named: pyrsistent
What it is: Python persistent data structure code written to be used in place of core data structures when mutation is undesirable
For custom classes, #semicolon suggests checking if there is a __hash__ function because mutable objects should generally not have a __hash__() function.
This is all I have amassed on this topic for now. Other ideas, corrections, etc. are welcome. Thanks.
One way of thinking of the difference:
Assignments to immutable objects in python can be thought of as deep copies,
whereas assignments to mutable objects are shallow
The simplest answer:
A mutable variable is one whose value may change in place, whereas in an immutable variable change of value will not happen in place. Modifying an immutable variable will rebuild the same variable.
Example:
>>>x = 5
Will create a value 5 referenced by x
x -> 5
>>>y = x
This statement will make y refer to 5 of x
x -------------> 5 <-----------y
>>>x = x + y
As x being an integer (immutable type) has been rebuild.
In the statement, the expression on RHS will result into value 10 and when this is assigned to LHS (x), x will rebuild to 10. So now
x--------->10
y--------->5
Mutable means that it can change/mutate. Immutable the opposite.
Some Python data types are mutable, others not.
Let's find what are the types that fit in each category and see some examples.
Mutable
In Python there are various mutable types:
lists
dict
set
Let's see the following example for lists.
list = [1, 2, 3, 4, 5]
If I do the following to change the first element
list[0] = '!'
#['!', '2', '3', '4', '5']
It works just fine, as lists are mutable.
If we consider that list, that was changed, and assign a variable to it
y = list
And if we change an element from the list such as
list[0] = 'Hello'
#['Hello', '2', '3', '4', '5']
And if one prints y it will give
['Hello', '2', '3', '4', '5']
As both list and y are referring to the same list, and we have changed the list.
Immutable
In some programming languages one can define a constant such as the following
const a = 10
And if one calls, it would give an error
a = 20
However, that doesn't exist in Python.
In Python, however, there are various immutable types:
None
bool
int
float
str
tuple
Let's see the following example for strings.
Taking the string a
a = 'abcd'
We can get the first element with
a[0]
#'a'
If one tries to assign a new value to the element in the first position
a[0] = '!'
It will give an error
'str' object does not support item assignment
When one says += to a string, such as
a += 'e'
#'abcde'
It doesn't give an error, because it is pointing a to a different string.
It would be the same as the following
a = a + 'f'
And not changing the string.
Some Pros and Cons of being immutable
• The space in memory is known from the start. It would not require extra space.
• Usually, it makes things more efficiently. Finding, for example, the len() of a string is much faster, as it is part of the string object.
Every time we change value of a immutable variable it basically destroy the previous instance and create a new instance of variable class
var = 2 #Immutable data
print(id(var))
var += 4
print(id(var))
list_a = [1,2,3] #Mutable data
print(id(list_a))
list_a[0]= 4
print(id(list_a))
Output:
9789024
9789088
140010877705856
140010877705856
Note:Mutable variable memory_location is change when we change the value
I haven't read all the answers, but the selected answer is not correct and I think the author has an idea that being able to reassign a variable means that whatever datatype is mutable. That is not the case. Mutability has to do with passing by reference rather than passing by value.
Lets say you created a List
a = [1,2]
If you were to say:
b = a
b[1] = 3
Even though you reassigned a value on B, it will also reassign the value on a. Its because when you assign "b = a". You are passing the "Reference" to the object rather than a copy of the value. This is not the case with strings, floats etc. This makes list, dictionaries and the likes mutable, but booleans, floats etc immutable.
In Python, there's a easy way to know:
Immutable:
>>> s='asd'
>>> s is 'asd'
True
>>> s=None
>>> s is None
True
>>> s=123
>>> s is 123
True
Mutable:
>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False
And:
>>> s=abs
>>> s is abs
True
So I think built-in function is also immutable in Python.
But I really don't understand how float works:
>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256
It's so weird.
For immutable objects, assignment creates a new copy of values, for example.
x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot
#effect the value of y
print(x,y)
For mutable objects, the assignment doesn't create another copy of values. For example,
x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy
x[2]=5
print(x,y) # both x&y holds the same list

Immutable vs Mutable types

I'm confused on what an immutable type is. I know the float object is considered to be immutable, with this type of example from my book:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
Is this considered to be immutable because of the class structure / hierarchy?, meaning float is at the top of the class and is its own method call. Similar to this type of example (even though my book says dict is mutable):
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Whereas something mutable has methods inside the class, with this type of example:
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
Also, for the last class(SortedKeyDict_a), if I pass this type of set to it:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
without calling the example method, it returns a dictionary. The SortedKeyDict with __new__ flags it as an error. I tried passing integers to the RoundFloat class with __new__ and it flagged no errors.
What? Floats are immutable? But can't I do
x = 5.0
x += 7.0
print x # 12.0
Doesn't that "mut" x?
Well you agree strings are immutable right? But you can do the same thing.
s = 'foo'
s += 'bar'
print s # foobar
The value of the variable changes, but it changes by changing what the variable refers to. A mutable type can change that way, and it can also change "in place".
Here is the difference.
x = something # immutable type
print x
func(x)
print x # prints the same thing
x = something # mutable type
print x
func(x)
print x # might print something different
x = something # immutable type
y = x
print x
# some statement that operates on y
print x # prints the same thing
x = something # mutable type
y = x
print x
# some statement that operates on y
print x # might print something different
Concrete examples
x = 'foo'
y = x
print x # foo
y += 'bar'
print x # foo
x = [1, 2, 3]
y = x
print x # [1, 2, 3]
y += [3, 2, 1]
print x # [1, 2, 3, 3, 2, 1]
def func(val):
val += 'bar'
x = 'foo'
print x # foo
func(x)
print x # foo
def func(val):
val += [3, 2, 1]
x = [1, 2, 3]
print x # [1, 2, 3]
func(x)
print x # [1, 2, 3, 3, 2, 1]
You have to understand that Python represents all its data as objects. Some of these objects like lists and dictionaries are mutable, meaning you can change their content without changing their identity. Other objects like integers, floats, strings and tuples are objects that can not be changed.
An easy way to understand that is if you have a look at an objects ID.
Below you see a string that is immutable. You can not change its content. It will raise a TypeError if you try to change it. Also, if we assign new content, a new object is created instead of the contents being modified.
>>> s = "abc"
>>> id(s)
4702124
>>> s[0]
'a'
>>> s[0] = "o"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> s = "xyz"
>>> id(s)
4800100
>>> s += "uvw"
>>> id(s)
4800500
You can do that with a list and it will not change the objects identity
>>> i = [1,2,3]
>>> id(i)
2146718700
>>> i[0]
1
>>> i[0] = 7
>>> id(i)
2146718700
To read more about Python's data model you could have a look at the Python language reference:
Python 2 datamodel
Python 3 datamodel
Common immutable type:
numbers: int(), float(), complex()
immutable sequences: str(), tuple(), frozenset(), bytes()
Common mutable type (almost everything else):
mutable sequences: list(), bytearray()
set type: set()
mapping type: dict()
classes, class instances
etc.
One trick to quickly test if a type is mutable or not, is to use id() built-in function.
Examples, using on integer,
>>> i = 1
>>> id(i)
***704
>>> i += 1
>>> i
2
>>> id(i)
***736 (different from ***704)
using on list,
>>> a = [1]
>>> id(a)
***416
>>> a.append(2)
>>> a
[1, 2]
>>> id(a)
***416 (same with the above id)
First of all, whether a class has methods or what it's class structure is has nothing to do with mutability.
ints and floats are immutable. If I do
a = 1
a += 5
It points the name a at a 1 somewhere in memory on the first line. On the second line, it looks up that 1, adds 5, gets 6, then points a at that 6 in memory -- it didn't change the 1 to a 6 in any way. The same logic applies to the following examples, using other immutable types:
b = 'some string'
b += 'some other string'
c = ('some', 'tuple')
c += ('some', 'other', 'tuple')
For mutable types, I can do thing that actallly change the value where it's stored in memory. With:
d = [1, 2, 3]
I've created a list of the locations of 1, 2, and 3 in memory. If I then do
e = d
I just point e to the same list d points at. I can then do:
e += [4, 5]
And the list that both e and d points at will be updated to also have the locations of 4 and 5 in memory.
If I go back to an immutable type and do that with a tuple:
f = (1, 2, 3)
g = f
g += (4, 5)
Then f still only points to the original tuple -- you've pointed g at an entirely new tuple.
Now, with your example of
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Where you pass
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
(which is a tuple of tuples) as val, you're getting an error because tuples don't have a .clear() method -- you'd have to pass dict(d) as val for it to work, in which case you'll get an empty SortedKeyDict as a result.
Difference between Mutable and Immutable objects
Definitions
Mutable object: Object that can be changed after creating it.
Immutable object: Object that cannot be changed after creating it.
In Python if you change the value of the immutable object it will create a new object.
Mutable Objects
Here are the objects in Python that are of mutable type:
list
Dictionary
Set
bytearray
user defined classes
Immutable Objects
Here are the objects in Python that are of immutable type:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Some Unanswered Questions
Question: Is string an immutable type?
Answer: yes it is, but can you explain this:
Proof 1:
a = "Hello"
a +=" World"
print a
Output
"Hello World"
In the above example the string got once created as "Hello" then changed to "Hello World". This implies that the string is of the mutable type. But it is not when we check its identity to see whether it is of a mutable type or not.
a = "Hello"
identity_a = id(a)
a += " World"
new_identity_a = id(a)
if identity_a != new_identity_a:
print "String is Immutable"
Output
String is Immutable
Proof 2:
a = "Hello World"
a[0] = "M"
Output
TypeError 'str' object does not support item assignment
Question: Is Tuple an immutable type?
Answer: yes, it is.
Proof 1:
tuple_a = (1,)
tuple_a[0] = (2,)
print a
Output
'tuple' object does not support item assignment
If you're coming to Python from another language (except one that's a lot like Python, like Ruby), and insist on understanding it in terms of that other language, here's where people usually get confused:
>>> a = 1
>>> a = 2 # I thought int was immutable, but I just changed it?!
In Python, assignment is not mutation in Python.
In C++, if you write a = 2, you're calling a.operator=(2), which will mutate the object stored in a. (And if there was no object stored in a, that's an error.)
In Python, a = 2 does nothing to whatever was stored in a; it just means that 2 is now stored in a instead. (And if there was no object stored in a, that's fine.)
Ultimately, this is part of an even deeper distinction.
A variable in a language like C++ is a typed location in memory. If a is an int, that means it's 4 bytes somewhere that the compiler knows is supposed to be interpreted as an int. So, when you do a = 2, it changes what's stored in those 4 bytes of memory from 0, 0, 0, 1 to 0, 0, 0, 2. If there's another int variable somewhere else, it has its own 4 bytes.
A variable in a language like Python is a name for an object that has a life of its own. There's an object for the number 1, and another object for the number 2. And a isn't 4 bytes of memory that are represented as an int, it's just a name that points at the 1 object. It doesn't make sense for a = 2 to turn the number 1 into the number 2 (that would give any Python programmer way too much power to change the fundamental workings of the universe); what it does instead is just make a forget the 1 object and point at the 2 object instead.
So, if assignment isn't a mutation, what is a mutation?
Calling a method that's documented to mutate, like a.append(b). (Note that these methods almost always return None). Immutable types do not have any such methods, mutable types usually do.
Assigning to a part of the object, like a.spam = b or a[0] = b. Immutable types do not allow assignment to attributes or elements, mutable types usually allow one or the other.
Sometimes using augmented assignment, like a += b, sometimes not. Mutable types usually mutate the value; immutable types never do, and give you a copy instead (they calculate a + b, then assign the result to a).
But if assignment isn't mutation, how is assigning to part of the object mutation? That's where it gets tricky. a[0] = b does not mutate a[0] (again, unlike C++), but it does mutate a (unlike C++, except indirectly).
All of this is why it's probably better not to try to put Python's semantics in terms of a language you're used to, and instead learn Python's semantics on their own terms.
Whether an object is mutable or not depends on its type. This doesn't depend on whether or not it has certain methods, nor on the structure of the class hierarchy.
User-defined types (i.e. classes) are generally mutable. There are some exceptions, such as simple sub-classes of an immutable type. Other immutable types include some built-in types such as int, float, tuple and str, as well as some Python classes implemented in C.
A general explanation from the "Data Model" chapter in the Python Language Reference":
The value of some objects can change. Objects whose value can change
are said to be mutable; objects whose value is unchangeable once they
are created are called immutable.
(The value of an immutable container
object that contains a reference to a mutable object can change when
the latter’s value is changed; however the container is still
considered immutable, because the collection of objects it contains
cannot be changed. So, immutability is not strictly the same as having
an unchangeable value, it is more subtle.)
An object’s mutability is
determined by its type; for instance, numbers, strings and tuples are
immutable, while dictionaries and lists are mutable.
A mutable object has to have at least a method able to mutate the object. For example, the list object has the append method, which will actually mutate the object:
>>> a = [1,2,3]
>>> a.append('hello') # `a` has mutated but is still the same object
>>> a
[1, 2, 3, 'hello']
but the class float has no method to mutate a float object. You can do:
>>> b = 5.0
>>> b = b + 0.1
>>> b
5.1
but the = operand is not a method. It just make a bind between the variable and whatever is to the right of it, nothing else. It never changes or creates objects. It is a declaration of what the variable will point to, since now on.
When you do b = b + 0.1 the = operand binds the variable to a new float, wich is created with te result of 5 + 0.1.
When you assign a variable to an existent object, mutable or not, the = operand binds the variable to that object. And nothing more happens
In either case, the = just make the bind. It doesn't change or create objects.
When you do a = 1.0, the = operand is not wich create the float, but the 1.0 part of the line. Actually when you write 1.0 it is a shorthand for float(1.0) a constructor call returning a float object. (That is the reason why if you type 1.0 and press enter you get the "echo" 1.0 printed below; that is the return value of the constructor function you called)
Now, if b is a float and you assign a = b, both variables are pointing to the same object, but actually the variables can't comunicate betweem themselves, because the object is inmutable, and if you do b += 1, now b point to a new object, and a is still pointing to the oldone and cannot know what b is pointing to.
but if c is, let's say, a list, and you assign a = c, now a and c can "comunicate", because list is mutable, and if you do c.append('msg'), then just checking a you get the message.
(By the way, every object has an unique id number asociated to, wich you can get with id(x). So you can check if an object is the same or not checking if its unique id has changed.)
A class is immutable if each object of that class has a fixed value upon instantiation that cannot SUBSEQUENTLY be changed
In another word change the entire value of that variable (name) or leave it alone.
Example:
my_string = "Hello world"
my_string[0] = "h"
print my_string
you expected this to work and print hello world but this will throw the following error:
Traceback (most recent call last):
File "test.py", line 4, in <module>
my_string[0] = "h"
TypeError: 'str' object does not support item assignment
The interpreter is saying : i can't change the first character of this string
you will have to change the whole string in order to make it works:
my_string = "Hello World"
my_string = "hello world"
print my_string #hello world
check this table:
source
It would seem to me that you are fighting with the question what mutable/immutable actually means. So here is a simple explenation:
First we need a foundation to base the explenation on.
So think of anything that you program as a virtual object, something that is saved in a computers memory as a sequence of binary numbers. (Don't try to imagine this too hard, though.^^) Now in most computer languages you will not work with these binary numbers directly, but rather more you use an interpretation of binary numbers.
E.g. you do not think about numbers like 0x110, 0xaf0278297319 or similar, but instead you think about numbers like 6 or Strings like "Hello, world". Never the less theses numbers or Strings are an interpretation of a binary number in the computers memory. The same is true for any value of a variable.
In short: We do not program with actual values but with interpretations of actual binary values.
Now we do have interpretations that must not be changed for the sake of logic and other "neat stuff" while there are interpretations that may well be changed. For example think of the simulation of a city, in other words a program where there are many virtual objects and some of these are houses. Now may these virtual objects (the houses) be changed and can they still be considered to be the same houses? Well of course they can. Thus they are mutable: They can be changed without becoming a "completely" different object.
Now think of integers: These also are virtual objects (sequences of binary numbers in a computers memory). So if we change one of them, like incrementing the value six by one, is it still a six? Well of course not. Thus any integer is immutable.
So: If any change in a virtual object means that it actually becomes another virtual object, then it is called immutable.
Final remarks:
(1) Never mix up your real-world experience of mutable and immutable with programming in a certain language:
Every programming language has a definition of its own on which objects may be muted and which ones may not.
So while you may now understand the difference in meaning, you still have to learn the actual implementation for each programming language. ... Indeed there might be a purpose of a language where a 6 may be muted to become a 7. Then again this would be quite some crazy or interesting stuff, like simulations of parallel universes.^^
(2) This explenation is certainly not scientific, it is meant to help you to grasp the difference between mutable and immutable.
The goal of this answer is to create a single place to find all the good ideas about how to tell if you are dealing with mutating/nonmutating (immutable/mutable), and where possible, what to do about it? There are times when mutation is undesirable and python's behavior in this regard can feel counter-intuitive to coders coming into it from other languages.
As per a useful post by #mina-gabriel:
Books to read that might help: "Data Structures and Algorithms in Python"
Excerpt from that book that lists mutable/immutable types:
mutable/imutable types image
Analyzing the above and combining w/ a post by #arrakëën:
What cannot change unexpectedly?
scalars (variable types storing a single value) do not change unexpectedly
numeric examples: int(), float(), complex()
there are some "mutable sequences":
str(), tuple(), frozenset(), bytes()
What can?
list like objects (lists, dictionaries, sets, bytearray())
a post on here also says classes and class instances but this may depend on what the class inherits from and/or how its built.
by "unexpectedly" I mean that programmers from other languages might not expect this behavior (with the exception or Ruby, and maybe a few other "Python like" languages).
Adding to this discussion:
This behavior is an advantage when it prevents you from accidentally populating your code with mutliple copies of memory-eating large data structures. But when this is undesirable, how do we get around it?
With lists, the simple solution is to build a new one like so:
list2 = list(list1)
with other structures ... the solution can be trickier. One way is to loop through the elements and add them to a new empty data structure (of the same type).
functions can mutate the original when you pass in mutable structures. How to tell?
There are some tests given on other comments on this thread but then there are comments indicating these tests are not full proof
object.function() is a method of the original object but only some of these mutate. If they return nothing, they probably do. One would expect .append() to mutate without testing it given its name. .union() returns the union of set1.union(set2) and does not mutate. When in doubt, the function can be checked for a return value. If return = None, it does not mutate.
sorted() might be a workaround in some cases. Since it returns a sorted version of the original, it can allow you to store a non-mutated copy before you start working on the original in other ways. However, this option assumes you don't care about the order of the original elements (if you do, you need to find another way). In contrast .sort() mutates the original (as one might expect).
Non-standard Approaches (in case helpful):
Found this on github published under an MIT license:
github repository under: tobgu named: pyrsistent
What it is: Python persistent data structure code written to be used in place of core data structures when mutation is undesirable
For custom classes, #semicolon suggests checking if there is a __hash__ function because mutable objects should generally not have a __hash__() function.
This is all I have amassed on this topic for now. Other ideas, corrections, etc. are welcome. Thanks.
One way of thinking of the difference:
Assignments to immutable objects in python can be thought of as deep copies,
whereas assignments to mutable objects are shallow
The simplest answer:
A mutable variable is one whose value may change in place, whereas in an immutable variable change of value will not happen in place. Modifying an immutable variable will rebuild the same variable.
Example:
>>>x = 5
Will create a value 5 referenced by x
x -> 5
>>>y = x
This statement will make y refer to 5 of x
x -------------> 5 <-----------y
>>>x = x + y
As x being an integer (immutable type) has been rebuild.
In the statement, the expression on RHS will result into value 10 and when this is assigned to LHS (x), x will rebuild to 10. So now
x--------->10
y--------->5
Mutable means that it can change/mutate. Immutable the opposite.
Some Python data types are mutable, others not.
Let's find what are the types that fit in each category and see some examples.
Mutable
In Python there are various mutable types:
lists
dict
set
Let's see the following example for lists.
list = [1, 2, 3, 4, 5]
If I do the following to change the first element
list[0] = '!'
#['!', '2', '3', '4', '5']
It works just fine, as lists are mutable.
If we consider that list, that was changed, and assign a variable to it
y = list
And if we change an element from the list such as
list[0] = 'Hello'
#['Hello', '2', '3', '4', '5']
And if one prints y it will give
['Hello', '2', '3', '4', '5']
As both list and y are referring to the same list, and we have changed the list.
Immutable
In some programming languages one can define a constant such as the following
const a = 10
And if one calls, it would give an error
a = 20
However, that doesn't exist in Python.
In Python, however, there are various immutable types:
None
bool
int
float
str
tuple
Let's see the following example for strings.
Taking the string a
a = 'abcd'
We can get the first element with
a[0]
#'a'
If one tries to assign a new value to the element in the first position
a[0] = '!'
It will give an error
'str' object does not support item assignment
When one says += to a string, such as
a += 'e'
#'abcde'
It doesn't give an error, because it is pointing a to a different string.
It would be the same as the following
a = a + 'f'
And not changing the string.
Some Pros and Cons of being immutable
• The space in memory is known from the start. It would not require extra space.
• Usually, it makes things more efficiently. Finding, for example, the len() of a string is much faster, as it is part of the string object.
Every time we change value of a immutable variable it basically destroy the previous instance and create a new instance of variable class
var = 2 #Immutable data
print(id(var))
var += 4
print(id(var))
list_a = [1,2,3] #Mutable data
print(id(list_a))
list_a[0]= 4
print(id(list_a))
Output:
9789024
9789088
140010877705856
140010877705856
Note:Mutable variable memory_location is change when we change the value
I haven't read all the answers, but the selected answer is not correct and I think the author has an idea that being able to reassign a variable means that whatever datatype is mutable. That is not the case. Mutability has to do with passing by reference rather than passing by value.
Lets say you created a List
a = [1,2]
If you were to say:
b = a
b[1] = 3
Even though you reassigned a value on B, it will also reassign the value on a. Its because when you assign "b = a". You are passing the "Reference" to the object rather than a copy of the value. This is not the case with strings, floats etc. This makes list, dictionaries and the likes mutable, but booleans, floats etc immutable.
In Python, there's a easy way to know:
Immutable:
>>> s='asd'
>>> s is 'asd'
True
>>> s=None
>>> s is None
True
>>> s=123
>>> s is 123
True
Mutable:
>>> s={}
>>> s is {}
False
>>> {} is {}
Flase
>>> s=[1,2]
>>> s is [1,2]
False
>>> s=(1,2)
>>> s is (1,2)
False
And:
>>> s=abs
>>> s is abs
True
So I think built-in function is also immutable in Python.
But I really don't understand how float works:
>>> s=12.3
>>> s is 12.3
False
>>> 12.3 is 12.3
True
>>> s == 12.3
True
>>> id(12.3)
140241478380112
>>> id(s)
140241478380256
>>> s=12.3
>>> id(s)
140241478380112
>>> id(12.3)
140241478380256
>>> id(12.3)
140241478380256
It's so weird.
For immutable objects, assignment creates a new copy of values, for example.
x=7
y=x
print(x,y)
x=10 # so for immutable objects this creates a new copy so that it doesnot
#effect the value of y
print(x,y)
For mutable objects, the assignment doesn't create another copy of values. For example,
x=[1,2,3,4]
print(x)
y=x #for immutable objects assignment doesn't create new copy
x[2]=5
print(x,y) # both x&y holds the same list

tuple vs list objects in python

Can someone explain me this?
>>> [] is []
False
>>> () is ()
True
>>> (1,) is (1,)
False
I understand that I should use "==" instead of "is"to compare the values, I am just wondering why it is this way?
is is based on object identity. I.E., are the left and right the same object?
In all these cases, the objects would ordinarily be different (since you have six separate literals). However, the empty tuples are the same object due to implementation-dependent interning. As you noted, you should never rely on this behavior.
Note that mutable objects can not be interned, which means the first must be false.
Be careful when comparing by id. If an object is GC'd the id can be reused!
>>> id([])==id([])
True
or even
>>> id([1,2,3])==id(["A","B","C"])
True
Think of it this way: In your first case, for immutable objects like tuples, it's safe for the python implementation to share them if they're identical:
>>> a = ()
>>> b = ()
>>> a is b
True
Now consider:
>>> a = []
>>> b = []
>>> a.append("foo")
>>> print a,b
['foo'] []
It's not possible for a and b to be the same object, because modifying a shouldn't modify b.
In your final example, you're back to immutable tuples. The Python implementation is allowed to make them the same object, but isn't required to, and in this case it doesn't (it's basically a space/time tradeoff - if you used a lot of (1,) in your program you could save memory if they were interned, but it would cost runtime to determine if any given tuple was a (1,) that could share the object).

What's the difference between dict() and {}?

So let's say I wanna make a dictionary. We'll call it d. But there are multiple ways to initialize a dictionary in Python! For example, I could do this:
d = {'hash': 'bang', 'slash': 'dot'}
Or I could do this:
d = dict(hash='bang', slash='dot')
Or this, curiously:
d = dict({'hash': 'bang', 'slash': 'dot'})
Or this:
d = dict([['hash', 'bang'], ['slash', 'dot']])
And a whole other multitude of ways with the dict() function. So obviously one of the things dict() provides is flexibility in syntax and initialization. But that's not what I'm asking about.
Say I were to make d just an empty dictionary. What goes on behind the scenes of the Python interpreter when I do d = {} versus d = dict()? Is it simply two ways to do the same thing? Does using {} have the additional call of dict()? Does one have (even negligible) more overhead than the other? While the question is really completely unimportant, it's a curiosity I would love to have answered.
>>> def f():
... return {'a' : 1, 'b' : 2}
...
>>> def g():
... return dict(a=1, b=2)
...
>>> g()
{'a': 1, 'b': 2}
>>> f()
{'a': 1, 'b': 2}
>>> import dis
>>> dis.dis(f)
2 0 BUILD_MAP 0
3 DUP_TOP
4 LOAD_CONST 1 ('a')
7 LOAD_CONST 2 (1)
10 ROT_THREE
11 STORE_SUBSCR
12 DUP_TOP
13 LOAD_CONST 3 ('b')
16 LOAD_CONST 4 (2)
19 ROT_THREE
20 STORE_SUBSCR
21 RETURN_VALUE
>>> dis.dis(g)
2 0 LOAD_GLOBAL 0 (dict)
3 LOAD_CONST 1 ('a')
6 LOAD_CONST 2 (1)
9 LOAD_CONST 3 ('b')
12 LOAD_CONST 4 (2)
15 CALL_FUNCTION 512
18 RETURN_VALUE
dict() is apparently some C built-in. A really smart or dedicated person (not me) could look at the interpreter source and tell you more. I just wanted to show off dis.dis. :)
As far as performance goes:
>>> from timeit import timeit
>>> timeit("a = {'a': 1, 'b': 2}")
0.424...
>>> timeit("a = dict(a = 1, b = 2)")
0.889...
#Jacob: There is a difference in how the objects are allocated, but they are not copy-on-write. Python allocates a fixed-size "free list" where it can quickly allocate dictionary objects (until it fills). Dictionaries allocated via the {} syntax (or a C call to PyDict_New) can come from this free list. When the dictionary is no longer referenced it gets returned to the free list and that memory block can be reused (though the fields are reset first).
This first dictionary gets immediately returned to the free list, and the next will reuse its memory space:
>>> id({})
340160
>>> id({1: 2})
340160
If you keep a reference, the next dictionary will come from the next free slot:
>>> x = {}
>>> id(x)
340160
>>> id({})
340016
But we can delete the reference to that dictionary and free its slot again:
>>> del x
>>> id({})
340160
Since the {} syntax is handled in byte-code it can use this optimization mentioned above. On the other hand dict() is handled like a regular class constructor and Python uses the generic memory allocator, which does not follow an easily predictable pattern like the free list above.
Also, looking at compile.c from Python 2.6, with the {} syntax it seems to pre-size the hashtable based on the number of items it's storing which is known at parse time.
Basically, {} is syntax and is handled on a language and bytecode level. dict() is just another builtin with a more flexible initialization syntax. Note that dict() was only added in the middle of 2.x series.
Update: thanks for the responses. Removed speculation about copy-on-write.
One other difference between {} and dict is that dict always allocates a new dictionary (even if the contents are static) whereas {} doesn't always do so (see mgood's answer for when and why):
def dict1():
return {'a':'b'}
def dict2():
return dict(a='b')
print id(dict1()), id(dict1())
print id(dict2()), id(dict2())
produces:
$ ./mumble.py
11642752 11642752
11867168 11867456
I'm not suggesting you try to take advantage of this or not, it depends on the particular situation, just pointing it out. (It's also probably evident from the disassembly if you understand the opcodes).
dict() is used when you want to create a dictionary from an iterable, like :
dict( generator which yields (key,value) pairs )
dict( list of (key,value) pairs )
Funny usage:
def func(**kwargs):
for e in kwargs:
print(e)
a = 'I want to be printed'
kwargs={a:True}
func(**kwargs)
a = 'I dont want to be printed'
kwargs=dict(a=True)
func(**kwargs)
output:
I want to be printed
a
In order to create an empty set we should use the keyword set before it
i.e set() this creates an empty set where as in dicts only the flower brackets can create an empty dict
Lets go with an example
print isinstance({},dict)
True
print isinstance({},set)
False
print isinstance(set(),set)
True

Categories

Resources