Home > Article > Backend Development > Some programming advice for Python beginners
Python is a very expressive language. It provides us with a huge standard library and many built-in modules to help us get our work done quickly. However, many people may get lost in the features it provides, fail to take full advantage of the standard library, place too much emphasis on one-line scripts, and misunderstand the basic structure of Python. This article is a non-exhaustive list of some of the pitfalls new Python developers can fall into.
1. Don’t know the Python version
This is a recurring question on StackOverflow. Many people can write code that works perfectly on one version, but they have a different version of Python installed on their system. Make sure you know which version of Python you are using.
You can check the Python version through the code below:
[pythontab@testServer]$ python --version Python 2.7.10 [pythontab@testServer]$ python --V Python 2.7.10
Both of the above methods are possible
2. Do not use a version manager
pyenv is an excellent tool for managing different Python versions, but Unfortunately, it only works on *nix systems. On Mac systems, you can simply install it via brew install pyenv, and on Linux, there is an automatic installer as well.
3. Addicted to one-line programs
Many people are keen on the excitement brought by one-line programs. Even if their one-line solution is less efficient than a multi-line solution, they'll brag about it.
A one-liner in Python essentially means a complex derivation with multiple expressions. For example:
l = [m for a, b in zip(this, that) if b.method(a) != b for m in b if not m.method(a, b) and reduce(lambda x, y: a + y.method(), (m, a, b))]
To be honest, I made up the above example. But I see a lot of people writing similar code. Code like this becomes unintelligible after a week. If you want to do something slightly more complex, such as simply adding an element to a list or set based on a condition, you're probably going to make a mistake.
Singles of code are not an achievement, yes they may look flexible, but they are not an achievement. Imagine it's like you're cleaning your house and stuffing everything into your closet. Good code should be clean, easy to read and efficient.
4. Initializing a collection in the wrong way
This is a more subtle problem that may catch you off guard. Set comprehensions are a lot like list comprehensions.
>>> { n for n in range(10) if n % 2 == 0 } {0, 8, 2, 4, 6} >>> type({ n for n in range(10) if n % 2 == 0 })
The above is an example of set derivation. A collection is like a list and a container. The difference is that there cannot be any duplicate values in a set and it is unordered. People who see set derivation often mistakenly think that {} initializes an empty set. But it doesn't, it initializes an empty dictionary.
>>> {} {} >>> type({})
If you want to initialize an empty collection, you can simply call the set() method.
>>> set() set() >>> type(set())
Note that an empty set is represented by set(), but a set containing some elements must be represented by curly braces surrounding the elements.
>>> s = set() >>> s set() >>> s.add(1) >>> s {1} >>> s.add(2) >>> s {1, 2}
This is counter-intuitive because you expect something similar to set([1, 2]).
5. Misunderstanding GIL
GIL (global interpreter lock) means that in a Python program, only one thread can be running at any point in time. This means that when we create a thread and want it to run in parallel, it doesn't do that. The actual job of the Python interpreter is to quickly switch between different running threads. But this is a very simple explanation of what actually happens, which is much more complex. There are many examples of running in parallel, for example using various libraries that are essentially C extensions. But when you run Python code, most of the time it doesn't execute in parallel. In other words, threads in Python are not like threads in Java or C++.
Many people will try to defend Python by saying these are real threads. This is certainly true, but it doesn't change the fact that Python handles threads differently than you might expect. The same situation exists with the Ruby language (Ruby also has an interpreter lock).
The specified solution is to use the multiprocessing module. The multiprocessing module provides the Process class, which is a good overlay for fork. However, a fork process is much more expensive than a thread, so you may not see a performance improvement every time because a lot of work needs to be done between different processes to coordinate with each other.
However, this problem does not exist in every implementation of Python. For example, one implementation of Python, PyPy-stm, attempts to get rid of the GIL (it is still unstable). Python implementations built on other platforms, such as the JVM (Jython) or the CLR (IronPython), also have no GIL issues.
In short, be careful when using the Thread class, what you get may not be what you want.
6. Use old-style classes
在Python 2中,有两种类型的类,分别为“旧式”类和“新式”类。如果你使用Python 3,那么你默认使用“新式”类。为了确保在Python2中使用“新式”类,你需要让你新创建的每一个类都继承object类,且类不能已继承了内置类型,例如int或list。换句话说,你的基类、类如果不继承其他类,就总是需要继承object类。
class MyNewObject(object): # stuff here
这些“新式”类解决一些老式类的根本缺陷,想要详细了解新式类和旧式类请参见《python新式类和旧式类区别》《python2中的__new__与__init__,新式类和经典类》。
7.按错误的方式迭代
对于这门语言的新手来说,下边的代码是非常常见的:
for name_index in range(len(names)): print(names[name_index])
在上边的例子中,没有必须调用len函数,因为列表迭代实际上要简单得多:
for name in names: print(name)
此外,还有一大堆其他的工具帮助你简化迭代。例如,可以使用zip同时遍历两个列表:
for cat, dog in zip(cats, dogs): print(cat, dog)
如果你想同时考虑列表变量的索引和值,可以使用enumerate:
for index, cat in enumerate(cats): print(cat, index)
在itertools中也有很多有用的函数供你选择。然而请注意,使用itertools函数并不总是正确的选择。如果itertools中的一个函数为你试图解决的问题提供了一个非常方便的解决办法,例如铺平一个列表或根据给定的列表创建一个其内容的排列,那就用它吧。但是不要仅仅因为你想要它而去适应你代码的一部分。
滥用itertools引发的问题出现的过于频繁,以至于在StackOverflow上一个德高望重的Python贡献者已经贡献他们资料的重要组成部分来解决这些问题。
8.使用可变的默认参数
我多次见到过如下的代码:
def foo(a, b, c=[]): # append to c # do some more stuff
永远不要使用可变的默认参数,可以使用如下的代码代替:
def foo(a, b, c=None): if c is None: c = [] # append to c # do some more stuff
与其解释这个问题是什么,不如展示下使用可变默认参数的影响:
>>> def foo(a, b, c=[]): ... c.append(a) ... c.append(b) ... print(c) ... >>> foo(1, 1) [1, 1] >>> foo(1, 1) [1, 1, 1, 1] >>> foo(1, 1) [1, 1, 1, 1, 1, 1]
同一个变量c在函数调用的每一次都被反复引用。这可能有一些意想不到的后果。
总结
这些只是相对来说刚接触Python的人可能会遇到的一些问题。然而请注意,可能会遇到的问题远非就这么些。然而另一些缺陷是人们像使用Java或C++一样使用Python,并且试图按他们熟悉的方式使用Python。