Python makes a language quite accessible for newbies, but with Python there are many things that are quite confusing and this article will help you understand more about these ambiguities. Here are some pretty cool features in Python (Note this is a feature, not a bug).
1. The for-else structure.
Many programming languages have if-else
constructs for handling conditional statements. However, in Python, you can even use the else
without the if
.
1 2 3 4 5 6 7 8 9 10 11 | animals = ["Dog", "Cat", "Pig"] for animal in animals: if animal == "Chicken": print("Chicken is an animal!") break else: print("Not found Chicken!") # Not found Chicken! |
For example, the code above does not have an if
. But the code block below the else
has been executed successfully!
This is the for-else
syntax in Python.
It’s a weird feature and we should be careful when using it. But its idea is surprisingly simple:
The
else
block will be executed when thefor
loop runs without abreak
.
To demonstrate this, consider the following code:
1 2 3 4 5 6 7 8 9 10 11 | animals = ["Dog", "Cat", "Pig", "Chicken"] for animal in animals: if animal == "Chicken": print("Chicken is an animal!") break else: print("Not found Chicken!") # Chicken is an animal! |
When running the above code, the list animals
contains “Chicken” so the for
loop was break
and the else
was not executed.
2. Changing Tuples in Python?
As is known, tuples are immutable Python objects (i.e. objects that cannot be changed). However, there is a trick that can temporarily be considered as changing tuples, despite the fact that the nature of tuples does not change.
But in the following way, we can temporarily consider modified tuples.
1 2 3 4 5 | tp = ([1, 2, 3], 4, 5) tp[0].append(4) print(tp) # ([1, 2, 3, 4], 4, 5) |
The explanation for this is that tp
is an immutable Python objects (immutable). However, the first element in tp is a mutable list
. At this time, the first element of tp
will point to the memory location of the list
storing the original [1, 2, 3]
value. When we change the value of the first element, tp
does not change, however, we can still consider tp
changed (change in return value). You can look at the example below to see more clearly:
1 2 3 4 5 6 7 8 9 10 | a = [1, 2, 3] tp = (a, 4, 5) print(id(a) ==id(tp[0])) # True a.append(4) print(id(a) == id(tp[0])) print(tp) # True # ([1, 2, 3, 4], 4, 5) |
3. 256 is 256, but sometimes 257 isn’t 257
Surprise, this is a magic feature of python, not a bug at all. When running the example below with python shell
, the results will surprise you.
1 2 3 4 5 6 7 8 9 10 | >>> a=256 >>> b=256 >>> a is b True >>> x = 257 >>> y = 257 >>> print(x is y) False >>> |
Basically, Python preloads all small integers in the range [-5, 256]
to save time and memory overhead. Therefore, when an integer in this range is declared, Python only references the cached integer and will not create any new objects. With each line of code comes a completely different statement, which is parsed and compiled separately, hence the case above.
In a word, a
and b
are the same object, but x
and y
are two different objects.
1 2 3 4 5 6 7 8 9 | >>> id(a) 1696073345424 >>> id(b) 1696073345424 >>> id(x) 1696122928496 >>> id(y) 1696122928752 |
This mechanism in Python is called integer interning
or integer caching
. That is when we write code in python shell, this will happen, but when we write them in the same file, the same context, the compiler, this will not happen. .
4. String interning
String interning makes common string operations save time and space by caching them. Instead of creating a new copy of the string each time, this optimization method requires keeping only one copy of the string for every appropriate immutable distinct value and using pointer references wherever it is called. .
1 2 3 4 | x = "This is a string" y = "This is a string" print(x is y) # prints True |
The is
operator in Python is used to check if two objects refer to the same memory location. If it returns True
, it means the two objects are actually the same object. In the above code, instead of creating a new copy when y
is assigned to a string with the same value as x
, Python points to the same string assigned to x
. This is only true for smaller strings; larger strings will make individual copies as usual.
1 2 3 4 | x = "This is a string" * 300 y = "This is a string" * 300 print(x is y) # False |
This will print False
on the console
and the strings are not interning. And here is the solution:
1 2 3 4 5 | import sys x = sys.intern("This is a string" * 300) y = sys.intern("This is a string" * 300) print(x is y) # True |
5. 0.1+0.2 is not 0.3
In fact, everyone knows that 0.1 + 0.2 = 0.3
, but Python doesn’t think so:
1 2 3 4 5 | print(0.1+0.2==0.3) print(0.1+ 0.2) # False # 0.30000000000000004 |
Practically speaking, this is not Python
‘s fault. No calculator can calculate the float
value correctly.
Computers can only store and process real numbers with a certain precision. So float
operations rely on hardware implementations in the machine’s processor chip, and no programming language can be sure that calculations with float
are always correct.