# Tips and tricks every Python developer should know Python has become a popular programming language because it is clear, versatile, easy to learn, and has many useful libraries for various tasks. Python programmers are in high demand from web development to data science and cybersecurity.

But, as with all programming languages, in Python everything depends on you, the programmer. You decide whether your code looks professional or ugly.

Fortunately, Python has a rich set of built-in functions that can help you write elegant, concise, and extensible code — characteristics you would expect from a professional programmer.

Here are some of Ideamotive’s developers favorite tricks that they think every Python developer should know.

## #1. Make a list of concepts

Understanding lists is one of the key features of Python that helps you write more concise and elegant code. Let’s say you want to create an array containing numbers from 1 to 100. A convenient way to do this is to use the range() function:

`numbers = list(range(1, 101))`

But what if you want to do something more complex, like create a list of squares from 1 to 100? In this case, the classic way would be to use a for loop:

`numbers = []`
`for i inrange(1, 101):`
`numbers.append(i**2)`

This is the standard way supported by most programming languages. Fortunately, in Python, comprehension of lists makes things a lot easier. This is what the same code would look like when written in list comprehension mode:

`numbers = [i**2for i inrange(1, 101)]`

You can use composite parts of a list to parenthesize multiple statements and expressions that define a list. They are much shorter and more elegant than the for loop. And you can do a lot more while keeping your code clean. For example, suppose you have an is_prime() function that checks an input number and returns True if it is a prime number. The following code snippet creates a list of squares of prime numbers from 1 to 100, adding the is_prime() condition to the understanding.

## #2. Counting objects

Often, you need to know how many times a particular value appears in a list. For example, suppose we have compiled a list of 1-10 ratings from an online survey. To simulate this, we’ll generate a list of 1000 random numbers from 1 to 10 using the randint() function.

`fromrandomimport randint`
`ratings = [randint(1, 10) for _ inrange(1,1001)]`

Now we want to know how many items of each rating are included in the list. One way to do this is to use the built-in list counting feature. count() takes a value and returns how many times this value appears in the list.

`for i inrange(1, 11):`
`print("{}: {} occurences".format(i, ratings.count(i)))`

This code gives the following output:

• 1: 95 cases
• 2: 115 cases
• 3: 111 cases
• 4: 109 cases
• 5: 81 case
• 6: 110 cases
• 7:80 cases
• 8: 94 cases
• 9: 98 cases
• 10: 107 cases

However, this only works if you know ahead of time what the range of values ​​is in your list. If you don’t know the possible values, you can use a set that creates a list of unique elements contained in another list. For example, if you have a list of names and want to know how many times each name appears, you can use the following code.

`for name inset(names):`
`print("{}: {} occurences".format(name, names.count(name)))`

Alternatively, you can use the Counter class, which specializes in counting values ​​in lists.

`fromcollectionsimport Counter`
`ratings_count = Counter(ratings)`
`for rating in ratings_count:`
`print("{}: {} occurences".format(rating, ratings_count[rating]))`

Counter provides some additional functionality, such as the most_common() function, which gives you the most common values ​​in a list. For example, the following code will print the three most popular values:

`for rating in ratings_count.most_common(3):     `
`print("{}: {} occurences".format(*rating)) `

## #3. Archiving

Another Python function that can come in handy from time to time is the zip() function. zip concatenates two or more lists into one variable. Let’s say you’ve put together a list of customers, their ages, and their favorite cocktail flavor.

`customers = ['John', 'Natasha', 'Eric', 'Sally']`
`ages = [26, 31, 39, 22]`
`flavors = ['cherry', 'chocolate', 'strawberry', 'lemon']`

Using zip(), you can combine all three lists into one list, where each entry contains a tuple with the name, age, and preferred taste of one customer.

`combined = zip(customers, ages, flavors)`
`customers_ice_cream = list(combined)`

This is what your customers_cocktail list looks like after archiving the data:

```[('John', 26, 'cherry'),
('Natasha', 31, 'chocolate'),
('Eric', 39, 'strawberry'),
('Sally', 22, 'lemon')] ```

And here’s how the zipped list can be used in a loop:

`for cust in customers_cocktail:`
`print("{} is {} years old and likes {}".format(*cust))`

The result looks like this:

• John is 26 years old and loves cherries;
• Natasha is 31 years old, she loves chocolate;
• Eric is 39 years old, he loves strawberries;
• Sally is 22 and she loves lemon.

## #4. Expansion of parameters

Let’s say you have a function that processes employee information:

`defprocess_employee_info(first_name, last_name, fav_topic, score):`
`print(first_name, last_name, fav_topic, score)`

In many cases, the values ​​you want to pass to a function are included in a list or dictionary object that was populated from a database or text file. In such cases, calling the function will be a little awkward:

`process_employee_info(employee, employee, employee, employee)`

Fortunately, Python has a “parameter expansion” function that lets you pass an entire list directly to a function. By adding * at the beginning of the list name, you expand it to individual values ​​before sending it to the function.

`process_employee_info(*employee)`

Expansion of parameters with lists works as long as the number of parameters and their sequence are similar to the parameters of the objective function. In case of inconsistency, it will generate an error.

You can also use parameter expansion with dictionaries, in which case the order of the values ​​does not matter. You only need the keys that match the parameters of your function. Parameter expansion for dictionaries requires the ** operator before the object.

`employee = {'last_name': 'doe', 'score': 89, 'first_name': 'john', 'fav_topic': 'calculus'}`
`process_employee_info(**employee)`

One of the advantages of using a dictionary extension is that if your function has default parameters, omitting them in the dictionary will not result in an error.

## #5. Enumeration

Sometimes you want to keep track of the number of items as you iterate over a list. Let’s say you have a list of customer names and you want to list them along with their sequential number. Here’s one way to do it:

`for i inrange(len(customers)):`
`print("{}: {}".format(i+1, customers[i]))`

The result will be something like this:

• 1: Samantha
• 2: Mara
• 3: Eric
• 4: James
• 5: George
• 6: Tony
• 7: Margaret
• 8: Stephen

While this code works, it is not very elegant. Notice a mismatch between index and counter? Fortunately, Python has an enumerate() function that makes your index tracking code clearer and more pleasing to the eye. enumerate() takes two arguments, the list you want to enumerate and the starting counter number, and gives two outputs in each round of the loop:

• the count value;
• the list item.

Here’s what solves the same problem with enumerate.

`for i, customer inenumerate(customers, 1):`
`print("{}: {}".format(i, customer))`

Much better. Don’t you think so?

## #6. Swapping two numbers in place

Python provides an intuitive way to do assignments and replacements on a single line. See example below.

`x, y = 10, 20`
`print(x, y)`
`x, y = y, x`
`print(x, y)`
`#1 (10, 20)`
`#2 (20, 10)`

The assignment to the right creates a new tuple. Whereas the left one instantly unpacks this (unreferenced) tuple into the names <a> and <b>.

Once the assignment is complete, the new tuple is dereferenced and marked for garbage collection. Eventually, the change of variables also occurs.

## #7. Enter annotations

Python is a dynamically typed language, which means that if you try to mix variables with different data types, it usually finds a way to fix the difference, or throws an exception if it can’t. But this flexibility can also lead to unpredictable behavior.

Let’s say you have a function that multiplies two variables.

`def mul(a, b):`
`return a * b`

if you call mul() on two integers or floating point numbers – the intended use of the function – the result is predictable.

`a = 5`
`b = 6`
`print(mul(a, b))`
`Output: 30`

But what if one of your variables is a list?

`a = [1, 2, 4, 5]`
`b = 3`
`print(mul(a, b))`
`Output: [1, 2, 4, 5, 1, 2, 4, 5, 1, 2, 4, 5]`

The function creates a list of three merged copies of the list. This is clearly not what you wanted to do. Python 3.6 and higher provides “type annotations”, a function that allows you to define the type of data that each argument to a function must accept. This is what the annotated mul() function looks like.

`def mul(a: int, b: int): `
`return a * b`

This format explicitly states that mul() accepts two integer values. For clarity, type annotation will not prevent you from using the function in an unintended way. But there are some good reasons to use it anyway.

First, datatype definition is a form of documentation that makes it easier for other developers looking at your code to understand what datatype you expect from your function (compare annotated versus unannotated versions of a function).

But more importantly, some code editors handle type annotations and help you with features like autocomplete and type errors.

Screenshot of Spyder IDE showing autocomplete for typed variables.

## #8. Using the Ternary operator for conditional assignment

Ternary operators are shorthand for the if-else statement, also known as conditional statements.

`[on_true] if [expression]`
`else [on_false]`

Here are some examples that you can use to keep your code compact and concise.

The statement below does exactly what it is intended to do, that is, “assign 10 x if y is 9, otherwise assign 20 x”. However, if necessary, we can extend the operator chain.

`x = 10 if (y == 9) else 20`

Likewise, we can do the same for class objects.

`x = (classA if y == 1 else classB)(param1, param2)`

In the above example, classA and classB are two classes and one of the class’s constructors will be called.

Below is another example with a number. conditions that combine to evaluate the smallest number.

`def small(a, b, c):`
`return a if a <= b and a <= c else (b if b <= a and b <= c else c)`
`print(small(1, 0, 1))`
`print(small(1, 2, 2))`
`print(small(2, 2, 3))`
`print(small(5, 4, 3))`
`#Output`
`#0 #1 #2 #3`

We can even use the ternary operator with a list comprehension.

`[m**2 if m > 10 else m**4 for m in range(50)]`
`#=> [0, 1, 16, 81, 256, 625, 1296, 2401, 4096, 6561, 10000, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401]`

## #9. Type check 2.0

Checking the type of a variable is a task that you will do over and over to gain knowledge. The isinstance() function in Python returns a boolean value depending on whether the given object is an instance of the specified class. It takes two parameter objects and the class itself. It can also be used for general type checking.

## #10. Shorter names

One of the biggest features of Python is the sheer number of libraries. The problem arises when you have to use them over and over again in your program because some of them have larger and non-English friendly names. Python offers an easier way to shorten the library name using the as keywords.

`## Normal Way`
`import numpy `
`import speech_recognition`
`## Shorten Name`
`import numpy as np`
`import speech_recognition as sr`

## #11. Professional iteration of multiple lists

In most cases, when you collect data from the Internet, you store it in another list. This trick allows you to print each list item corresponding to each item in the other list.

## #12. Use the Get method instead of square brackets

Most Python developers tend to use square brackets when accessing an element from a data structure such as dictionaries. There is no problem with square brackets, but when it comes to a value that doesn’t come out, a terrible error is displayed. Now, to save yourself from this error, you can use the get method.

`data_dict = {a:1, b:2,c:3}`
`print(data_dict['d']) ## KeyError: 'd'`
`print(data_dict.get('d')) ## None `

## #13. Handling exceptions at runtime

An exception is a condition that occurs during program execution for any reason and interrupts execution. To handle exceptions in Python, we use a try and except block. The try block contains the code that needs to be executed, and the except block contains the code that will be executed if any error occurs in the try block.

`''' Exception '''`
`a = 5`
`b = 0`
`print(a/b) ## ZeroDivisionError: division by zero`
`''' Exception Handling '''`
`try:`
`a = 5`
`b = 0`
`print(a/b)`
`except:`
`print("Can't Divide Number With 0")`
`Can't Divide Number With 0`

## #14. Converting a normal method to a static method

A static method is a type of method in Python classes that is bound to a specific state of the class. They cannot access or update the state of the class. You can convert normal method or instance method to static method using staticmethod (function)

`class ABC:`
`def abc(num1,num2):`
`print(num1+numn2)`
`# changing torture_students into static method`
`ABC.abc = staticmethod(ABC.abc)`
`ABC.abc(4,5) ## 9`

The normal print statement works fine in most situations, but when the output is in the form of tables, JSON, or contains multiple results, you need to add some functionality to it or use some external package.

```''' pprint (pretty print)'''
from pprint import pprint
import json
f = open('data.json',)
pprint(data)
f.close()```

——————OUTPUT—————-

```{'glossary':
{'GlossDiv':
{'GlossDef':
{'GlossSeeAlso': ['GML', 'XML'],'para': 'A meta-markup language, used '
'to create markup languages ''such as DocBook.'},
'GlossSee':
'markup'},
'title': 'example glossary'}}
''' Normal Print '''
import json
f = open('data.json',)
print(data)
f.close()```

————–OUTPUT————–

`{'glossary': {'title': 'example glossary', 'GlossDiv': {'GlossDef': {'para': 'A meta-markup language, used to create markup languages such as DocBook.', 'GlossSeeAlso': ['GML', 'XML']}, 'GlossSee': 'markup'}}}`

## #16. Logging instead of printing for debugging

Logging is the process of recording a stream of code as it runs. It helps a lot to debug the code very easily. One of the main advantages of logging before printing is that even after the application is closed, the logs are saved in a file for later review, which comes with log messages and other entries such as line number and module name. Only printing, saving and displaying data until the application is running. Python provides module name logging for creating and writing logs.

`''' Logging Code For Zero Division Error '''`
`import logging`
`a = 10`
`b = 0`
`try:`
`c = a / b`
`except Exception as e:`
`logging.error("Exception Occurred", exc_info=True)  ## At default it is True`

———————————CONSOLE OUTPUT (Logging)————————

```ERROR:root:Exception Occurred        ## If exc_info=False then
only this message will print```
`Traceback (most recent call last):`
`File "C:\Users\Name\Desktop\logging_code.py", line 5, in <module>`
`c = a / b`
`ZeroDivisionError: division by zero`

——————————– CONSOLE OUTPUT (Print)—————————–

`Traceback (most recent call last):`
`File "main.py", line 3, in <module>`
`print(a/b)`
`ZeroDivisionError: division by zero`

## #17. Smart addition of new features

A decorator is a Python function that allows you to add new functionality to existing code without explicitly modifying it. A great use of a decorator is to add middle functionality to a function that calculates addition and percentage without changing the function.

`''' Adding Average Functionality to a Function That Calculates Percentage and Total With The Help Of Decorator'''`
`import functools`
`def decorator(func):`
`@functools.wraps(func)`
`def wrapper(*args, **kwargs):`
`numbers = list(args)`
`print("Percentage: ",((sum(numbers)*100)/len(numbers)))`
`result = func(*args,**kwargs)`
`print("Total: ",sum(numbers))`
`return result`
`return wrapper`
`@decorator`
`def average(*numbers):`
`return sum(list(numbers))/len(list(numbers))`
`result = average(77,89,93,96)`
`print("Average: ", result)`

———————-OUTPUT————————

`Percentage:  8875.0`
`Total:  355`
`Average:  88.75`

## #18. Determining Python version at runtime

Sometimes we may not want to execute our program if the current Python engine is less than the supported version. You can use the below code snippet for this. It also prints the current version of Python in human readable format.

`import sys`
`#Detect the Python version currently in use.`
`if not hasattr(sys, "hexversion") or sys.hexversion != 50660080:`
`print("Sorry, you aren't running on Python 3.5\n")`
` print("Please upgrade to 3.5.\n")`
`sys.exit(1)`
`#Print Python version in a readable format.`
`print("Current Python version: ", sys.version)`

Alternatively, you can use mys.version_info> = (3, 5) to replace sys.hexversion! = 50660080 in the above code. This was a suggestion from one of the knowledgeable readers.

Output when working in Python 2.7.

`Python 2.7.10 (default, Jul 14 2015, 19:46:27)`
`[GCC 4.8.2] on linux`
`Sorry, you aren't running on Python 3.5`
`Please upgrade to 3.5.`

Output when working in Python 3.5.

`Python 3.5.1 (default, Dec 2015, 13:05:11)`
`[GCC 4.8.2] on linux`
`Current Python version:  3.5.2 (default, Aug 22 2016, 21:11:05) `
`[GCC 5.3.0]`

## Final thoughts

These were eighteen of our favorite Python tricks. Using them will keep your code clean and elegant. As Python is fast becoming the de facto programming language in many fields and institutions, having a good set of best practices will ensure that you can become a productive member of your development team.