# Python tips

### Built-in Method: sum, max, min

sum method will return the sum of iterable data type (List is one of iterable data type in Python)

print(sum([2, 7, 1]))
Output:
10

max method will return the highest value of iterable data type

print(max([2, 7, 1]))
Output:
7

min method will return the lowest value of iterable data type

print(min([2, 7, 1]))
Output:
1

### Merge List

List support operator * and + for merging the elements. The example below will show both operator could have the same results.

names = ['Anna', 'John', 1, 10.5, {'store': 'dictionary'}]

print([*names, *other_list])
Output:
['Anna', 'John', 1, 10.5, {'store': 'dictionary'}, 2, 'Asada', 'Max']

print(names + other_list)
Output:
['Anna', 'John', 1, 10.5, {'store': 'dictionary'}, 2, 'Asada', 'Max']

### Create New List

• List comprehension
names = ["Anna", "John", 1, 10.5, {"store": "dictionary"}]
new_list = [name for name in names]
print(new_list)

Output:
['Anna', 'John', 1, 10.5, {'store': 'dictionary'}]

• Create list of numbers using range range is python built-in function and returns a sequence of numbers Range Syntax range(start, stop, step) Parameter Description
• start (optional parameter) An integer parameter for position to start. Default is 0
• stop (required parameter) An integer parameter for position to stop.
• step (optional parameter) An integer parameter for the the incrementation.
# Create List with 10 elements of number (0 to 4)
# using: range(stop)
print(list(range(5)))
Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Create List with 10 elements of number (0 to 4)
# using: range(start, stop)
print(list(range(0, 5)))
Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Create List with 5 elements of number
# using: range(start, stop, step)
print(list(range(0, 10, 2)))
Output:
[0, 2, 4, 6, 8]

• Create List of Tuples using zip
names = ["Ana", "John", "Edward"]

print(list(zip(names, other_names)))
Output:
[('Ana', 'Asada'), ('John', 'Max'), ('Edward', 'Tulip')]

### Accessing Index and Value on For loop

names = ["Anna", "John", 1, 10.5, {"store": "dictionary"}]

for index, value in enumerate(names):
print(index, value)

Output:
0 Anna
1 John
2 1
3 10.5
4 {'store': 'dictionary'}

### Use a cloud-based python performance tool.

When you’re working locally, you can use profiling tools that will give you insight into the bottlenecks in your application. If your application will be deployed to the web, however, things are different. Stackify will allow you to see how well your application performs under production load. It also provides code profiling, error tracking, and server metrics. Jump over to the Python section to find out how this could work with your application.

The Python list datatype implements as an array. That means adding an element to the start of the list is a costly operation, as every item has to be moved forward. A linked list is a datatype that may come in handy. It differs from arrays, as each item has a link to the next item in the list—hence the name! An array needs the memory for the list allocated up front. That allocation can be expensive and wasteful, especially if you don’t know the size of the array in advance. A linked list lets you allocate the memory when you need it. Each item can be stored in different parts of memory, and the links join the items. The gotcha here is that lookup times are slower. You’ll need to do some thorough profiling to work out whether this is a better method for you.

### Don’t construct a set for a conditional.

Sometimes you might find yourself wanting to optimize your code with something like this:

if animal in set(animals):

This idea seems to make sense. There might be a lot of animals, and de-duplicating them feels like it might be faster.

if animal in animals:

Even though there may be significantly more animals in the list to check, the interpreter is optimized so much that applying the set function is likely to slow things down. Checking “in” a long list is almost always a faster operation without using the set function.

### Use keys for sorts.

If you search for some examples of sorting, a lot of the code examples you find will work but could be outdated. Often these examples create a custom sort and cost time in the setup and in performing the sort. The best way to sort items is to use keys and the default sort() method whenever possible. I’ve mentioned already that the built-in functions are generally faster, and this is one of those times.

import operator
my_list = [("Josh", "Grobin", "Singer"), ("Marco", "Polo", "General"), ("Ada", "Lovelace", "Scientist")]
my_list.sort(key=operator.itemgetter(0))
my_list

This will sort the list by the first keys:

('Josh', 'Grobin', 'Singer'),
('Marco', 'Polo', 'General')]

You can easily sort by the second key, like so:

my_list.sort(key=operator.itemgetter(1))
my_list

This will return the list below. You can see it’s sorted by the second names.

[('Josh', 'Grobin', 'Singer'),
('Marco', 'Polo', 'General')]

In each case, the list is sorted according to the index you select as part of the key argument. This approach works with numbers and strings, and it’s readable and fast.

### Use list comprehensions.

When you’re working in Python, loops are common. You’ve probably come across list comprehensions before. They’re a concise and speedy way to create new lists. For example, let’s say you wanted to find the cubes of all the odd numbers in a given range. Using a for loop, that task might look like this:

cube_numbers = []
for n in range(0,10):
if n % 2 == 1:
cube_numbers.append(n**3)

In contrast, a list comprehension approach would just be one line:

cube_numbers = [n**3 for n in range(1,10) if n%2 == 1]

The list comprehension approach is shorter and more concise, of course. More important, it’s notably faster when running in code. As with all these tips, in small code bases that have small ranges, using this approach may not make much of a difference. But in other situations, it may make all the difference when you’re trying to save some time.

### Try decorator caching.

Memoization is a specific type of caching that optimizes software running speeds. Basically, a cache stores the results of an operation for later use. The results could be rendered web pages or the results of complex calculations. You can try this yourself with calculating the 100th Fibonacci number. If you haven’t come across these numbers, each one is the sum of the previous two numbers. Fibonacci was an Italian mathematician who discovered that these numbers cropped up in lots of places. From the number of petals on a flower to legs on insects or branches on a tree, these numbers are common in nature. The first few are 1, 1, 2, 3, 5. One algorithm to calculate these is:

def fibonacci(n):
if n == 0: # There is no 0'th number
return 0
elif n == 1: # We define the first number as 1
return 1
return fibonacci(n - 1) + fibonacci(n-2)

When I used this algorithm to find the 36th Fibonacci number, fibonacci(36), my computer sounded like it was going to take off! The calculation took five seconds, and (in case you’re curious) the answer was 14,930,352. When you introduce caching from the standard library, however, things change. It takes only a few lines of code.

import functools

@functools.lru_cache(maxsize=128)
def fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
return fibonacci(n - 1) + fibonacci(n-2)

In Python, a decorator function takes another function and extends its functionality. We denote these functions with the @ symbol. In the example above, I’ve used the decorator functools.lru_cache function provided by the functools module. I’ve passed the maximum number of items to store in my cache at the same time as an argument. There are other forms of decorator caching, including writing your own, but this is quick and built-in. How quick? Well, this time the calculation took 0.7 seconds, and reassuringly, the answer was the same.