Python tips & best practices for developers:

  1. Learn to Use Python Dictionary

Dictionary data structure in Python is a way to store data; moreover, it is powerful and easy to use. Dictionaries are found in other languages as “associative memories” or “associative arrays”. In Python, a dictionary is an unordered set of key: value pairs, with the requirement that each key is unique.

Let’s examine some common use cases with accompanying code examples. Let’s say you use many if/else clauses in your code:

if name == "John": 
   print "This is John, he is an artist"
elif name == "Ted":
   print "This is Ted, he is an engineer"
elif name == "Kennedy":
   print "This is Kennedy, he is a teacher"

By using a dictionary, we can write the same code like this:

name_job_dict = {
   "Josh": "This is John, he is an artist",
   "Ted": "This is Ted, he is an engineer",   
   "Kenedy": "This is Kennedy, he is a teacher",
}
print name_job_dict[name]

The second use case is when we need a default value for a key:

def count_duplicates(numbers):
   result = {}
   for number in numbers:
       if number not in result:  # No need for if here
           result[key] = 0
       result[number] += 1return result

By using setdefault, we get cleaner code:

 >>> def count_duplicates(numbers):
   result = {}
   for number in numbers:
       result.setdefault(number, 0)  # this is clearer
       result[number] += 1return result

We can also use the dictionary to manipulate lists:

 >>> characters = {'a': 1, 'b': 2}
>>> characters.items() // return a copy of a dictionary’s list of (key, value) pairs (https://docs.python.org/2/library/stdtypes.html#dict.items)
[('a', 1), ('b', 2)]


>>> characters = [['a', 1], ['b', 2], ['c', 3]]
>>> dict(characters) // return a new dictionary initialized from a list (https://docs.python.org/2/library/stdtypes.html#dict)
{'a': 1, 'b': 2, 'c': 3}

If necessary, it is easy to change a dictionary form by switching the keys and values – changing {key: value} to a new dictionary {value: key} – also known as inverting the dictionary:

>>> characters = {'a': 1, 'b': 2, 'c': 3}
>>> invert_characters = {v: k for k, v in characters.iteritems()}
>>> invert_characters
{1: 'a', 2: 'b', 3: 'c'}


The final tip is related to exceptions. Developers should watch out for exceptions. One of the most annoying is the KeyError exception. To handle this, developers must first check whether or not a key exists in the dictionary.


>>> character_occurrences = {'a': [], ‘b’: []}
>>> character_occurrences[‘c’]
KeyError: 'c'
>>> if ‘c’ not in character_occurrences:
        character_occurrences[‘c’] = []
>>> character_occurrences[‘c’]
[]
>>> try:
        print character_occurrences[‘d’]
    except: 
        print “There is no character `d` in the string”


However, to achieve clean and easily testable code, avoiding exceptions catch and conditions is a must. So, this is cleaner and easier to understand if the defaultdict, in collections, is used.


>>> from collections import defaultdict
>>> character_occurrences = defaultdict(list)
>>> character_occurrences['a']
[]
>>> character_occurrences[‘b’].append(10)
>>> character_occurrences[‘b’].append(11)
>>> character_occurrences[‘b’]
[10, 11]

2. Be Consistent About Indentation in the Same Python File.

Indentation level in Python is really important, and mixing tabs and spaces is not a smart, nor recommended practice. To go even further, Python 3 will simply refuse to interpret mixed file, while in Python 2 the interpretation of tabs is as if it is converted to spaces using 8-space tab stops. So while executing, you may have no clue at which indentation level a specific line is being considered.

Tips: it can be a good idea to avoid tabs altogether, because the semantics of tabs are not very well-defined in the computer world, and they can be displayed completely differently on different types of systems and editors.

3. Practice writing Unit Tests and Doctests.Avoiding the writing of automated tests just for the sake of shipping quickly is a bad practice.

4. Learn to Deal with Hash Table Based Operations?

Many people are confused with the fact that almost all hash table based operations in Python are done in place, without returning an object itself. As an example, they usually remember dict.update() and almost all operation on sets:


>>> a = {1,2,3}
>>> a.update({5,6,7})  # returns None
>>> a
set([1, 2, 3, 5, 6, 7])  # object changed in place
>>> a.add(8)  # returns None
>>> a
set([1, 2, 3, 5, 6, 7, 8])  # object changed in place
>>> d = {"foo": "bar"}
>>> d.update({"zzz": "derp"})  # returns None
>>> d
{'foo': 'bar', 'zzz': 'derp'}  # object changed in place


Thinking of a more practical example, you can’t write something like this:


requests = [
    web.Request(
        body=json.dumps(
            item.update({"foo": "bar"})
        )
    ) for item in my_long_iterable
]

The above code will set the body of each request to string null, which may lead to weird bugs or some surprises that are even worse.

Usually, most programmers will rewrite it as a simple loop after some thinking:

requests = []
for item in my_long_iterable:
	body = item.update({"foo": "bar"})
	requests.append(
		web.Request(body=json.dumps(body))
	)


The fun thing here is there is still a possibility to write it as a single list comprehension. Here is how:

requests = [
    web.Request(
        body=json.dumps(
            dict(foo="bar", **item)
        )
    ) for item in my_long_iterable
]

Simple and understandable, right?

5. Most Important to Write Documentation or Inline Comments,practice it well.

Stay assured within a short period of time you’ll hate yourself when you will not remember what and why you did something in the way you did while reading your own code.

6. Feel the Power of the Python Logic Operands.

Python’s logical operations don’t return just Boolean values True or False, they can also return the actual value of the operations.

This power of the Python logic operands can be used to speed up development and to increase code readability. In the following example, object will be fetched from the cache, or if it’s missed in the cache it will be fetched from the database:

# check_in_cache returns object or None
def get_obj(): 
return check_in_cache() or pull_from_db()

A quick explanation of the provided example: it will first try to get an object from cache (check_in_cache() function). If it doesn’t return an object and returns a None instead, it will get it from the database (pull_from_db() function). Written in this way is better than the following code snippet, written in a standard way:

 def get_obj():
result = check_in_cache()
if result is None:
  		result = pull_from_db()
	return result

Here first code example solves a problem in one line of the code, which is better than four lines of code from the second code example. Not to mention the first code example is more expressive and readable.

7.Avoid Using The try: except: pass Pattern

f you really want to pass one or two well-expected exceptions, then make it explicit instead of all-pass. In Python, “explicit is better than implicit”, like in the code example bellow:

 try: 
    subtle_buggy_operation() # most possibly some I/O or DB ops
except ThouShaltPassError:
    pass

8.Use Generator Comprehensions:

By using parentheses () instead of square brackets [] for comprehensions, we tell Python to use a generator rather than to create a list. This can be very useful if the full list is not needed, or if it is expensive to compile due to some combination of the list being long, each object being big, or the conditional is expensive to compute.


My main generator comprehension use case is, at the time of the writing, when I want a single object from group of objects under some conditional, and when I expect many objects will satisfy the conditional but I only need one. Like in the example below:


short_list = range(10)
%%timeit
y = [x for x in short_list if x > 5][0]


1000000 loops, best of 3: 601 ns per loop


The square brackets tell Python to compile the whole list [6, 7, 8, 9] and then pick off the 0th element. With a list this small, no it is not a big deal.


Let’s now take a look at the following example below:

short_list = range(10)
%%timeit
y = (x for x in short_list if x > 5).next()
1000000 loops, best of 3: 910 ns per loop

The parentheses tell Python it is another comprehension, but to instead create a generator for it.

9.Don’t Make Everything a Class: In Python, overusing classes and making everything a class is considered a bad practice. before creating one, developers should think hard. Most likely, they would be much better with a function.

10. In Python-Verse, try: except: else Construct Is a Natural Control Flow

In the Python world, using exceptions for flow control is common and normal. Even the Python core developers use exceptions for flow-control and that style is heavily baked into the language (i.e. the iterator protocol uses StopIteration to signal loop termination). In addition, the try-except-style is used to prevent the race-conditions inherent in some of the “look-before-you-leap” constructs.

11.Use Python Properties Rather Than Explicit Getters and Setters

12.Avoid Using from module import * in Your Projects?

The from module import * wild-card style leads to namespace pollution. You’ll get things in your local namespace that you didn’t expect to get. You may see imported names obscuring module-defined local names. You won’t be able to figure out where certain names come from. Although a convenient shortcut, this should not be in production code.


Let’s show it with the examples. As mentioned, the worst use case would be the following code:

 from module_name import *
# ...
spam = function(foo, bar)


A better use case would be something in line with the following code:


from module_name import function
# ...
spam = function(foo, bar)

The best possible way of using import module is as follows:

 import module_name as mn
spam = mn.function(foo, bar)

13. Should I Use Exceptions of Conditional Handling?

Python best practice is to use exceptions as a better way to handle “exceptional” cases. Unnecessary use of if’s may slow down your code. Although, keep in mind frequent “except” calls are even slower than plain if conditional handling, so you must use it wisely.

To summarize, exceptions are good for rare cases, and conditions are better for frequent use cases


Happy Reading!

Ref: https://www.toptal.com/python/tips-and-practices

要查看或添加评论,请登录

Deepak Chaubey的更多文章

社区洞察

其他会员也浏览了