More

So far we have covered a majority of the various aspects of Python that you will use. In this chapter, we will cover some more aspects that will make our knowledge of Python more well-rounded.

Passing tuples around

Ever wished you could return two different values from a function? You can. All you have to do is use a tuple.

>>>defget_error_details():...return (2,'details')...>>>errnum, errstr = get_error_details()>>>errnum2>>>errstr'details'

Notice that the usage ofa, b = <some expression> interprets the result of the expression as a tuple with two values.

This also means the fastest way to swap two variables in Python is:

>>>a =5; b =8>>>a, b(5,8)>>>a, b = b, a>>>a, b(8,5)

Special Methods

There are certain methods such as the__init__ and__del__ methods which have special significance in classes.

Special methods are used to mimic certain behaviors of built-in types. For example, if you want to use thex[key] indexing operation for your class (just like you use it for lists and tuples), then all you have to do is implement the__getitem__() method and your job is done. If you think about it, this is what Python does for thelist class itself!

Some useful special methods are listed in the following table. If you want to know about all the special methods,see the manual.

  • __init__(self, ...)

    • This method is called just before the newly created object is returned for usage.
  • __del__(self)

    • Called just before the object is destroyed (which has unpredictable timing, so avoid using this)
  • __str__(self)

    • Called when we use theprint function or whenstr() is used.
  • __lt__(self, other)

    • Called when theless than operator (<) is used. Similarly, there are special methods for all the operators (+, >, etc.)
  • __getitem__(self, key)

    • Called whenx[key] indexing operation is used.
  • __len__(self)

    • Called when the built-inlen() function is used for the sequence object.

Single Statement Blocks

We have seen that each block of statements is set apart from the rest by its own indentation level. Well, there is one caveat. If your block of statements contains only one single statement, then you can specify it on the same line of, say, a conditional statement or looping statement. The following example should make this clear:

>>>flag =True>>>if flag:print('Yes')...Yes

Notice that the single statement is used in-place and not as a separate block. Although, you can use this for making your programsmaller, I strongly recommend avoiding this short-cut method, except for error checking, mainly because it will be much easier to add an extra statement if you are using proper indentation.

Lambda Forms

Alambda statement is used to create new function objects. Essentially, thelambda takes a parameter followed by a single expression. Lambda becomes the body of the function. The value of this expression is returned by the new function.

Example (save asmore_lambda.py):

points = [{'x':2,'y':3},          {'x':4,'y':1}]points.sort(key=lambda i: i['y'])print(points)

Output:

$ python more_lambda.py[{'y': 1, 'x': 4}, {'y': 3, 'x': 2}]

How It Works

Notice that thesort method of alist can take akey parameter which determines how the list is sorted (usually we know only about ascending or descending order). In our case, we want to do a custom sort, and for that we need to write a function. Instead of writing a separatedef block for a function that will get used in only this one place, we use a lambda expression to create a new function.

List Comprehension

List comprehensions are used to derive a new list from an existing list. Suppose you have a list of numbers and you want to get a corresponding list with all the numbers multiplied by 2 only when the number itself is greater than 2. List comprehensions are ideal for such situations.

Example (save asmore_list_comprehension.py):

listone = [2,3,4]listtwo = [2*ifor iin listoneif i >2]print(listtwo)

Output:

$ python more_list_comprehension.py[6, 8]

How It Works

Here, we derive a new list by specifying the manipulation to be done (2*i) when some condition is satisfied (if i > 2). Note that the original list remains unmodified.

The advantage of using list comprehensions is that it reduces the amount of boilerplate code required when we use loops to process each element of a list and store it in a new list.

Receiving Tuples and Dictionaries in Functions

There is a special way of receiving parameters to a function as a tuple or a dictionary using the* or** prefix respectively. This is useful when taking variable number of arguments in the function.

>>>defpowersum(power, *args):...'''Return the sum of each argument raised to the specified power.'''...    total =0...for iin args:...        total +=pow(i, power)...return total...>>>powersum(2,3,4)25>>>powersum(2,10)100

Because we have a* prefix on theargs variable, all extra arguments passed to the function are stored inargs as a tuple. If a** prefix had been used instead, the extra parameters would be considered to be key/value pairs of a dictionary.

The assert statement

Theassert statement is used to assert that something is true. For example, if you are very sure that you will have at least one element in a list you are using and want to check this, and raise an error if it is not true, thenassert statement is ideal in this situation. When the assert statement fails, anAssertionError is raised.Thepop() method removes and returns the last item from the list.

>>>mylist = ['item']>>>assertlen(mylist) >=1>>>mylist.pop()'item'>>>assertlen(mylist) >=1Traceback (most recent call last):  File"<stdin>", line1,in <module>AssertionError

Theassert statement should be used judiciously. Most of the time, it is better to catch exceptions, either handle the problem or display an error message to the user and then quit.

Decorators

Decorators are a shortcut to applying wrapper functions. This is helpful to "wrap" functionality with the same code over and over again. For example, I created aretry decorator for myself that I can just apply to any function and if any exception is thrown during a run, it is retried again, till a maximum of 5 times and with a delay between each retry. This is especially useful for situations where you are trying to make a network call to a remote computer:

from timeimport sleepfrom functoolsimport wrapsimport logginglogging.basicConfig()log = logging.getLogger("retry")defretry(f):    @wraps(f)defwrapper_function(*args, **kwargs):        MAX_ATTEMPTS =5for attemptinrange(1, MAX_ATTEMPTS +1):try:return f(*args, **kwargs)except Exception:                log.exception("Attempt %s/%s failed : %s",                              attempt,                              MAX_ATTEMPTS,                              (args, kwargs))                sleep(10 * attempt)        log.critical("All %s attempts failed : %s",                     MAX_ATTEMPTS,                     (args, kwargs))return wrapper_functioncounter =0@retrydefsave_to_database(arg):print("Write to a database or make a network call or etc.")print("This will be automatically retried if exception is thrown.")global counter    counter +=1# This will throw an exception in the first call# And will work fine in the second call (i.e. a retry)if counter <2:raise ValueError(arg)if __name__ =='__main__':    save_to_database("Some bad value")

Output:

$ python more_decorator.pyWrite to a database or make a network call or etc.This will be automatically retried if exception is thrown.ERROR:retry:Attempt 1/5 failed : (('Some bad value',), {})Traceback (most recent call last):  File "more_decorator.py", line 14, in wrapper_function    return f(*args, **kwargs)  File "more_decorator.py", line 39, in save_to_database    raise ValueError(arg)ValueError: Some bad valueWrite to a database or make a network call or etc.This will be automatically retried if exception is thrown.

How It Works

See:

Differences between Python 2 and Python 3

See:

Summary

We have covered some more features of Python in this chapter and yet we haven't covered all the features of Python. However, at this stage, we have covered most of what you are ever going to use in practice. This is sufficient for you to get started with whatever programs you are going to create.

Next, we will discuss how to explore Python further.

results matching ""

    No results matching ""