Anti-pattern in Python programming (1)

Source: Internet
Author: User

Anti-pattern in Python programming (1)

This article collects the nonstandard but occasionally subtle issues I have seen in the code written by new Python developers. This article aims to help novice developers write ugly Python code. In order to take care of the target readers, this article makes some simplification, for example, ignoring the generator and powerful iteration tools itertools when discussing the iterator ).

There are always some reasons for new developers to use the anti-pattern. I have tried to give these reasons where possible. However, these anti-pattern causes the code to be unreadable, bug-prone, and not conform to the Python code style. For more information, I strongly recommend The Python Tutorial or Dive into Python.

Iteration
  • Use of range

A beginner in Python programming prefers to use range to implement simple iteration. Within the length range of the iterator, it gets every element in the iterator:

 
 
  1. for i in range(len(alist)):  
  2.     print alist[I] 

It should be noted that range is not used to implement simple iteration of sequences. Compared with the for loop defined by numbers, although the for loop implemented by range is quite natural, it is easy to produce bugs in the iteration of sequences, and it is better to directly construct the iterator to look clear:

 
 
  1. for item in alist:  
  2.     print item 

Misuse of range can easily lead to an unexpected one (off-by-one) error, this is usually because the new programmer forgets that the object generated by range includes the first parameter of range, but does not include the second parameter. It is similar to the substring in java and many other functions of this type. Programmers who believe that there is no more than the end of the sequence will create bugs:

 
 
  1. # How To iterate the entire sequence error
  2. Alist = ['her', 'name', 'is ', 'Rio']
  3. For I in range (0, len (alist)-1): # one Off by one )!
  4. Print I, alist [I]

Common Reasons for improper use of range:
1. Indexes need to be used in the loop. This is not a reasonable reason. You can use the following method to replace indexes:

 
 
  1. for index, value in enumerate(alist):  
  2.     print index, value 

2. Two loops need to be iterated at the same time, and two values must be obtained using the same index. In this case, you can use zip to implement:

 
 
  1. for word, number in zip(words, numbers):  
  2.     print word, number 

3. Part of the iteration sequence is required. In this case, only iterative sequence slicing is required. Note that the following Annotations indicate the purpose:

 
 
  1. For word in words [1:]: # The first element is not included.
  2. Print word

One exception is that when you iterate a large sequence, the overhead caused by slice operations is relatively large. If there are only 10 elements in the sequence, there is no problem. If there are 10 million elements, or when slice is performed in a performance-sensitive inner loop, overhead becomes very important. In this case, you can use xrange instead of range [1].

In addition to iterative sequences, an important usage of range is when you really want to generate a digital sequence instead of an index:

 
 
  1. # Print foo(x) for 0<=x<5  
  2. for x in range(5):  
  3.     print foo(x) 
  • Use List parsing correctly

If you have a loop like this:

 
 
  1. # An ugly, slow way to build a list  
  2. words = ['her', 'name', 'is', 'rio']  
  3. alist = []  
  4. for word in words:  
  5.     alist.append(foo(word)) 

You can use list parsing to rewrite the statement:

 
 
  1. words = ['her', 'name', 'is', 'rio']  
  2. alist = [foo(word) for word in words] 

Why? On the one hand, you can avoid errors that may occur when the list is correctly initialized. On the other hand, you can write code to make it look clean and tidy. For those with functional programming backgrounds, using map functions may be more familiar, but in my opinion this approach is not Python-based.

Other common reasons for not using list Resolution:

1. nested loops are required. At this time, you can nest the entire list parsing, or use multiple rows in the list parsing to use the loop:

 
 
  1. words = ['her', 'name', 'is', 'rio']  
  2. letters = []  
  3. for word in words:  
  4.     for letter in word:  
  5.         letters.append(letter) 

Use List parsing:

 
 
  1. words = ['her', 'name', 'is', 'rio']  
  2. letters = [letter for word in words  
  3.                   for letter in word] 

Note: In list resolution with multiple loops, the loops are in the same order as you did not use list resolution.

2. You need a condition judgment inside the loop. You only need to add the condition judgment to list parsing:

 
 
  1. words = ['her', 'name', 'is', 'rio', '1', '2', '3']  
  2. alpha_words = [word for word in words if isalpha(word)] 

A reasonable reason for not using list resolution is that you cannot use exception handling in list resolution. If some elements in the iteration may cause exceptions, you need to transfer the possible exception handling through function call in list parsing, or simply do not use list parsing.

Performance Defects
  • Check content in linear time

In terms of syntax, it seems similar to checking whether the list or set/dict contains an element, but it is completely different on the surface. If you need to repeat whether a data structure contains an element, you 'd better use set instead of list. If you want to associate a value with the element to be checked, you can use dict; this can also achieve constant check time .)

 
 
  1. # Starting with list
  2. Lyrics_list = ['her', 'name', 'is', 'Rio ']
  3. # Avoid writing the following statements
  4. Words = make_wordlist () # assume that many words to be tested are returned.
  5. For word in words:
  6. If word in lyrics_list: # linear check time
  7. Print word, "is in the lyrics"
  8. # It is best to write it like this
  9. Lyrics_set = set (lyrics_list) # create a set in linear time
  10. Words = make_wordlist () # assume that many words to be tested are returned.
  11. For word in words:
  12. If word in lyrics_set: # constant check time
  13. Print word, "is in the lyrics"

[Note: The set elements and dict key values in Python can be hashed, so the time complexity for searching is O (1).]

Remember: Creating a set introduces a one-time overhead. the creation process takes linear time even if the member check takes constant time. Therefore, if you need to check the members in the loop, it is best to take the time to create the set, because you only need to create it once.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.