```
# For one or two conditions
viewers = 1000
likes = 500
if viewers >= 1000 and likes >= 500:
print(" Good luck ")
#Output
Good luck
```

If you have one or two conditions, you can use the above example programs

```
# For more than ten conditions
viewers = 2000
likes = 700
conditions = [ viewers >= 1000,likes >= 500]
if all(conditions):
print(" Good luck ")
#Output
Good luck
```

Suppose if you have more than ten conditions, you can create a list and use all() to perform AND operation (fulfilled all conditions). If you didn’t get it compare two examples side by side to understand clearly.

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.

How would you print a numbered list of the world's richest people? Maybe you'd consider something like this:

```
# Inefficient way to get numbered list
the_richest = ['Jeff Bezos', 'Bill Gates', 'Warren Buffett', 'Bernard Arnault & family', 'Mark Zuckerberg']
i = 0
for person in the_richest:
print(i, person)
i+=1
```

However, you can do the same with less code using the enumerate() function:

```
# Efficient way to get numbered list
the_richest = ['Jeff Bezos', 'Bill Gates', 'Warren Buffett', 'Bernard Arnault & family', 'Mark Zuckerberg']
for i, person in enumerate(the_richest):
print(i, person)
```

Enumerators can be very useful when you need to iterate through a list while keeping track of the list items' indices.

Enumerate() is the python method that adds a counter to an iterable and returns it in a form of enumerate object. This enumerate object can then be used directly in for loops or be converted into a list of tuples uing list() method. Syntax

```
enumerate(iterable, start=0)
Parameters:
iterable: any object that supports iteration
start: the index value from which the counter
is to be started, by default it is 0
```

Program

```
football_clubs = ['Barcelona', 'Real Madrid', 'Liverpool',
'Manchester United', 'Juventus']
# Classical approach
i = 0
for club in football_clubs:
i += 1
print(i, club)
# Using enumerate()
for i, club in enumerate(football_clubs, 1):
print(i, club)
```

Output

```
1 Barcelona
2 Real Madrid
3 Liverpool
4 Manchester United
5 Juventus
'''
```

Python has a lot of hidden stuff underneath. It only takes a person and his time to find out what all magical operators and stuff are hidden inside. One among all the other stuff is the famous JSON-esque. You can create nested dictionaries without explicitly creating sub-dictionaries. They magically come into existence as we reference them. Example as follows: users = tree() users['harold']['username'] = 'hrldcpr' users['handler']['username'] = 'matthandlersux' Now you can print the above as JSON with:

print(json.dumps(users)) And it will look like this {"harold": {"username": "hrldcpr"}, "handler": {"username": "matthandlersux"}}

Let’s say we have two lists, one list contains names of the students and second contains marks scored by them. Let’s see how we can convert those two lists into a single dictionary. Using the zip function, this can be done using the code below:

In Python you know that tuples are immutable that means you can’t append them to add new values. But this tip and trick will help you to append tuples and add new values to them.

```
tuple1 = (1, 2, 3)lst= list(tuple1)lst.append(4)lst.append(5)tuple1 = tuple(lst)print(tuple1) # (1, 2, 3, 4, 5)
```

To check if membership of a list, it’s generally faster to use the “in” keyword.

```
for name in member_list:
print('{} is a member'.format(name))
```

PEP 465 and Python 3.5 introduced the dedicated infix operator for matrix multiplication @. You can implement it for your class with the methods matmul, rmatmul, and imatmul. This is how elegant the code for multiplying vectors or matrices looks like:

We can also do in-place swapping of two variables numbers so we can use their swapped values in the program. Example: Look at the following Python program: Output:

See also: top 10 python tips