Learn Python- those pits those years, we stepped on

Those of us who stepped on the pit

Pit 1-- integer comparison of the pit

In Python everything is an object, the object is an integer, when comparing two integers have two operators ==and istheir difference is:

  • isCompare the two Integer object id values ​​are equal, that is, compare two references represent the same address in memory.
  • ==Compare the contents of two integer objects are equal, to use ==when in fact, is called object __eq__()method.

Know isand ==difference After that, we can take a look at the code below to learn Python integer comparison in which pit:

def main():
	x = y = -1
	while True:
		x += 1
		y += 1
		if x is y:
			print('%d is %d' % (x, y))
		else:
			print('Attention! %d is not %d' % (x, y))
			break
			
	x = y = 0
	while True:
		x -= 1
		y -= 1
		if x is y:
			print('%d is %d' % (x, y))
		else:
			print('Attention! %d is not %d' % (x, y))
			break


if __name__ == '__main__':
	main()

Partly result of the above operation code as shown below, this result occurs Python is done in consideration of the performance of an optimization. For integer objects, some Python integer frequently used objects cached, saved to a named small_intslist of, in Python entire life cycle, need to refer to any of these places integer objects are no longer re-create a new object, It is a direct reference to the object cache. The value of the integer Python objects frequently used set at [-5, 256] this interval, if the integer range of needs, directly from small_intsobtaining references instead of creating a new temporary object. Since within the range of greater than 256 or less than -5 is not an integer, so even if two integers are the same, but they are different objects.

Results of Figure 1. The upper portion of the program

Of course, just so the pit was not worth a mention, if you understand the above rules, we will look at the following code.

a = 257


def main():
	b = 257  # 第6行
	c = 257  # 第7行
	print(b is c)  # True
	print(a is b)  # False
	print(a is c)  # False


if __name__ == "__main__":
	main()

Results of the implementation has been written comments on the code. Enough pit it! It looks a, band cvalues are the same, but the isresult of the operation is not the same. Why is there such a result, it said that first of all we block Python program. Code block is called a minimum basic execution unit program, a file module, a body function, a class, interactive command a single line of code are called code blocks. The above code is composed of two code blocks, a = 257a code block, mainthe function is another block. Internal Python To further improve performance, all Integer object created in a code block, if the value is not small_intsin the buffer range, but has a value identical thereto Integer object exists in the same code block, then a direct reference to the object otherwise, create a new object out of this rule are not in small_intsnegative range does not apply, does not apply to negative floating-point value, but for non-negative floating-point numbers and strings are applicable, which readers can prove themselves . So  b is che returned True, but aand bnot in the same code block, although the value is 257, but it is two different objects, isthe result of the calculation is naturally Falsea. In order to verify just concluded, we can borrow dismodule (listen to know the name of the module is disassembled) from the perspective of the bytecode to look at this code. If you do not understand what is bytecode, you can take a look at "Python program to talk about the operating principle," the article. It can be used to import disimport the dismodule and modify the code in the manner as shown below.

import dis

dis.dis(main)

Execution result code as shown in FIG. It can be seen that the code line 6 and the line 7, that is, mainthe function 257 is loaded from the same location, so the object is the same; and the code on line 9 ais clearly different from the place of loading, and therefore reference They are different objects.

2. FIG decompile Python code module dis

If you want to dig further on this issue, I recommend reading "Python integer object implements the principle of" the article.

Pit 2 - pit nested list

Python has a built-in data type called list, it is a container that can be used to carry other objects (accurate to say that refer to other objects), the list of objects can be called elements of the list, it is clear that we can as the list of elements in the list, this is called a nested list. Nested list can simulate reality in the form of a matrix, 2D maps of the game (such as Zombies garden), the board (such as Chess, Reversi) and so on. However, when using nested lists to be careful, otherwise it is likely to face a very awkward situation, here is a small example.

names = ['关羽', '张飞', '赵云', '马超', '黄忠']
subjs = ['语文', '数学', '英语']
scores = [[0] * 3] * 5
for row, name in enumerate(names):
    print('请输入%s的成绩' % name)
    for col, subj in enumerate(subjs):
        scores[row][col] = float(input(subj + ': '))
        print(scores)

We want to enter a list of five student achievement three courses, then define a list of five elements, and each element of the list is a list consisting of three elements, such a list with just a table is the same, the equivalent of five rows and three columns, then we enter circulation every student achievement through three courses of nested for-in. After the program execution is completed, we found that every student achievement 3 course is exactly the same, but the student is entering the final score.

To fill this hole, we must first distinguish between objects and object references these two concepts, and to distinguish between these two concepts have to first talk about the memory stack and heap. We often hear people talking about the "stack" the word, but in fact "heap" and "stack" are two different concepts. As we all know, need to take up some memory space is running a program to store data and code, then these memory logically and can be further divided. Most understand the underlying language (such as C) programmer knows, from the memory part of the program logic to five can be used, from high to low according to the address is: Stack (Stack), the heap (heap) , the data segment (data segment), read-only data segment (static area), and code segments (code segment). Wherein the stack is used to store a local, temporary variables, and saving and restoring the function call site need to use the data field, this memory is automatically allocated when the code block starts execution, the automatic execution of the code block is released, usually by a compiler automatic management; heap size is not fixed, you can dynamically allocate and recover, so if the program has a lot of data to be processed, these data are usually placed on the heap if the heap is not properly release memory leak causes problems , and like Python, Java and other programming languages use garbage collection mechanism to achieve automatic memory management (automatic recovery of heap space no longer in use). So the following code, the variable ais not a real object, it is a reference to an object, the object is equivalent to the address recorded in the heap space, through which we can access the address corresponding to the object; Similarly, the variable bis a reference to the list of containers it cited a list of containers on the heap space, while the list of container and real object is not saved, it is only to save the referenced object.

a = object()
b = ['apple', 'pitaya', 'grape']

Knowing this, we can just go back and look at the program, we list [[0] * 3] * 5the operation, just the [0, 0, 0]address of the list were copied, and did not create a new list object, container, although there are five elements, but these five elements refer to the same list of objects, which can idfunction checks scores[0]and scores[1]confirmed address. Therefore, the correct code should be modified in the following manner.

names = ['关羽', '张飞', '赵云', '马超', '黄忠']
subjs = ['语文', '数学', '英语']
scores = [[]] * 5
for row, name in enumerate(names):
    print('请输入%s的成绩' % name)
    scores[row] = [0] * 3
    for col, subj in enumerate(subjs):
        scores[row][col] = float(input(subj + ': '))
        print(scores)

or

names = ['关羽', '张飞', '赵云', '马超', '黄忠']
subjs = ['语文', '数学', '英语']
scores = [[0] * 3 for _ in range(5)]
for row, name in enumerate(names):
    print('请输入%s的成绩' % name)
    scores[row] = [0] * 3
    for col, subj in enumerate(subjs):
        scores[row][col] = float(input(subj + ': '))
        print(scores)

If memory usage is not very understanding, you can look PythonTutor website code provided on the visualization of executive function, through visualization and execution, we can see how memory is allocated in order to avoid might encounter when using nested lists or copy objects pit.

Figure 3. Create a nested list of wrong practices

Figure 4. Create nested list right way

 

Pit 3 - access modifier pit

Python done using object-oriented programming person knows, Python class provides two access control permission, one is disclosed a private (before the property or method in double underline). And are used to Java or C # programming languages ​​such people know, the class attribute (data abstraction) are usually private, whose purpose is to protect the data together; and methods in the class (abstract behavior) usually It is public, because the object is to provide services to the outside world. But Python does not ensure the privacy of private members from the grammatical level, because it's just kind of so-called private members named were transformed, if you know the name of the rule can still directly access private members, see the following code.

class Student(object):

    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    def __str__(self):
        return self.__name + ': ' + str(self.__age)


stu = Student('骆昊', 38)
print(stu._Student__name)
print(stu._Student__age)

Why Python to make such a setting it? With a widespread maxim to explain the problem: "We are all consenting adults here" (We are all adults). This sentence expresses a lot of Python programmers a common point of view, it is better open than closed, we should be responsible for their own behavior and not to restrict access to data or methods from language level.

In Python, so we really do not need the class property or method treatment with name beginning with a double underscore to private members because it does not have any practical significance. If you want to protect property or method, we recommend that protected members of a single leading underscore, though it can not really protect the property or method, but it is equivalent to the caller a hint, let the caller know that this is not supposed to direct property or method of access, and doing so does not affect the subclass to inherit these things.

Need to remind you to note that those magic Python class method, such as __str__, __repr__etc. These methods are not private members Oh, though they start with a double underscore, but they also end with a double underline that this is not a private member named the name, which is really pit for beginners.

Published 348 original articles · won praise 235 · views 700 000 +

Guess you like

Origin blog.csdn.net/GUDUzhongliang/article/details/104941928