Python @ DjangoSpin

50+ Know-How(s) Every Pythonista Must Know

Buffer this pageShare on FacebookPrint this pageTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUpon
Reading Time: 21 minutes

Page #3


Importing Modules: 4 types of imports

A Module(or package as they are referred as in other languages) is a collection of code accessible using an import statement. Simply put, a module is a file containing Python code. It may have variables, functions, classes, print statements etc. Modules allow you to logically organize your code, putting related stuff in a single module. This makes the code easier to comprehend and easier to work with. You can import a module in 4 different ways:

  1. import some_module
  2. import some_module as alias
  3. from some_module import *
  4. from some_module import some_func

Expand the following code snippet for more details.

############################## 1. import some_module ##########################
# Say, you have come up with an elementary yet handy function that tells whether the number supplied to it is odd or even. It should look something like this:

def oddOrEven(number):
    if number % 2 == 0:
        print(number,"is even.")
    else:
        print(number, "is odd.")
		
# Now, you wish to use the above function in some other program without having to type it again. So you decide to put it inside a .py file, say myModule.py. Place it anywhere on your computer. In the same folder, create another file, say, main.py, and open it with IDLE.

import myModule
 
myModule.oddOrEven(31)
 
myModule.oddOrEven(18)
 

### OUTPUT ###
31 is odd.
18 is even.

# This is the basic import statement in action i.e. import some_module. The basic import statement is executed in two steps:
# -> find the said module, load the code in it
# -> define a name or names in the local namespace for the scope where the “import” statement occurs.
# The 'local namespace' contains all the identifiers of the program. So the import statement brings the identifiers of the module in the namespace of the program in which the import statement is written.

# In order to import multiple modules in a single statement:
>>> import module1, module2, module3
# The above will execute the aforementioned dual steps for each module separately, just as if they were written in different import statements one after the other.


############################## 2. import some_module as alias ##############################
# Python allows us to refer to the imported module by giving it a convenient name. The name thus given is known as the alias of the module in the current program.

import myModule as specialFunctions
 
specialFunctions.oddOrEven(31)
specialFunctions.oddOrEven(18)
 
 
### OUTPUT ###
31 is odd.
18 is even.

############################## 3. from some_module import * ##############################
# This type of import statement is used when we do not want to qualify the imported functions i.e. if we are trying to call oddOrEven() imported from module myModule, we will call it by oddOrEven(num) and not by myModule.oddOrEven(num).

from myModule import *
 
oddOrEven(31)
oddOrEven(18)
 
 
### OUTPUT ###
31 is odd.
18 is even.

############################## 4. from some_module import some_func ##############################
# To import a specific function from a module, from some_module import * is used. This variant is handy when only few selected portions of code are to be imported from a large module.

from myModule import oddOrEven
 
oddOrEven(31)
oddOrEven(18)
 
 
### OUTPUT ###
31 is odd.
18 is even.

Terminating your program

In order to exit from a Python script/Interactive Interpreter Session/Command Prompt Session, any of the following functions can be used: exit(), quit(), sys.exit(). While calling these functions, you can provide an exit_code as the first argument. These exit codes can be used in bash scripting, where the special variable $? returns the last exit status.


Asserting values using assert keyword

It's hard to argue with the fact that all practical programs have bugs. It is better to find them beforehand and strangle them before they bother the testing team. A developer tries to minimises the occurrence of these defects, by writing self-checks to ensure that things are going as he plans. The assert statement helps to achieve this purpose. The assert statement takes an expression and if it is true, it continues the program flow. Else, it raises an AssertionError. Let's take a look at an example.

>>> def squareIt(number):
	assert type(number) is int
	return number * number

>>> squareIt(9)
81
>>> squareIt('a')
Traceback (most recent call last):
    squareIt('a')
    assert type(number) is int
AssertionError

Assertions serve as safety nets, providing a way to check that the state of the program is as per the expectations of the developer. The developer might have some assumptions as he is writing the code, which can be made explicitly obvious with assert statements. This is in conformance with the Zen of Python, which states that "Explicit is better than implicit."

The assert statement takes an optional second option, which can be used to give an elaborate explanation of the failure detected. This can also include cleanup code.

>>> def squareIt(number):
	assert type(number) is int, "Please input a number"
	return number * number

>>> squareIt('a')
Traceback (most recent call last):
    squareIt('a')
    assert type(number) is int, "Please input a number"
AssertionError: Please input a number

Bear in mind that assertions are not a substitute for the raise keyword. The user has an option to ignore the assertions by executing the Python script with -O flag in the command prompt.


Number System Interconversion: int(), bin(), oct() & hex()

Python provides handy builtin functions bin(), hex() & oct() to convert decimal values to strings of corresponding number systems.

>>> a = 4
>>> bin(a)
'0b100'
>>> hex(a)
'0x4'
>>> oct(a)
'0o4'

To convert these strings back into decimal system, use the builtin int() function with appropriate base value.

>>> int('0b100', 2)
4
>>> int('0x4', 16)
4
>>> int('0o4', 8)
4

You can use the combination of these methods to convert one non-decimal system to another. For example, converting a binary value to its hexadecimal equivalent:

>>> hex(   int('0b100', 2)   )
'0x4'

Serialization in Python: pickle, shelve & json modules

The process of converting native language objects into a sequence of bytes or objects of an interchange format, which are either stored in a file or stored in a string, for the purpose of loading the data in a different session, or for transmitting the data over the network, is known as Serialization. Saving the state of a game when you exit it, and loading it when you launch the game next time, is one such example where serialization is implemented. We’ll discuss 3 modern-day Python modules which implement serialization: pickle, shelve and json.

Expand the following code snippet to view basic examples of serialization using these 3 modules. For further details, have a look at this post.

####### pickle MODULE #######
### Serialization: pickle.dump(obj, file, protocol=None, *, fix_imports=True)
>>> import pickle
>>> saveGameDetails = {
    'playerName': 'Ethan',
    'level': 3,
    'arrowCount': 12
    }
>>> with open('saveGame01.robinhood', 'wb') as pickleFileHandler:
    pickle.dump(saveGameDetails, pickleFileHandler)
     
### Contents of 'saveGame01.robinhood' are in binary format.
 
### Deserialization: pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict")
>>> with open('saveGame01.robinhood', 'rb') as pickleFileHandler:
    loadGameDetails = pickle.load(pickleFileHandler)
>>> loadGameDetails
{'level': 3, 'playerName': 'Ethan', 'arrowCount': 12}
 
### Pickling without a file: loads() and dumps()
>>> saveGameDetails = {
    'playerName': 'Ethan',
    'level': 3,
    'arrowCount': 12
    }
 
>>> saveGameDetailsBinary = pickle.dumps(saveGameDetails)
>>> saveGameDetailsBinary
b'\x80\x03}q\x00(X\n\x00\x00\x00arrowCountq\x01K\x0cX\n\x00\x00\x00playerNameq
\x02X\x05\x00\x00\x00Ethanq\x03X\x05\x00\x00\x00levelq\x04K\x03u.'
 
>>> loadGameDetails = pickle.loads(saveGameDetailsBinary)
>>> loadGameDetails
{'level': 3, 'playerName': 'Ethan', 'arrowCount': 12}
 
 
 
 
 
 
####### shelve MODULE #######
### Serialization ###
>>> import shelve
>>> saveGameOneDetails = {'playerName': 'Ethan', 'level': 3, 'arrowCount': 12}
>>> saveGameTwoDetails= {'playerName': 'Ethan', 'level': 5, 'arrowCount': 6}
 
>>> with shelve.open('save_games.robinhood') as saveGames:                         # as good as saveGames = shelve.open('save_games.robinhood')
    saveGames['saveGame001'] = saveGameOneDetails
     
>>> with shelve.open('save_games.robinhood') as saveGames:
    saveGames['saveGame002'] = saveGameTwoDetails
     
### creates 2 files: save_games.robinhood.dat(containing serialized bytes, like the output file of a pickle) and save_games.robinhood.dir(containing records of individual pickles, like a register.) ###
# contents of .dir:
'saveGame002', (512, 70)
'saveGame001', (0, 70)
 
### Deserialization ###
>>> with shelve.open('save_games.robinhood') as saveGames:
    loadGameOneDetails = saveGames['saveGame001']
    print(loadGameOneDetails)
 
     
{'level': 3, 'arrowCount': 12, 'playerName': 'Ethan'}
 
>>> loadGameOneDetails == saveGameOneDetails
True
 
 
 
 
####### json MODULE #######
### Serialization: json.dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)
>>> import json
>>> jsonFileHandler = open('saveGame.robinhood', mode = 'w', encoding = 'utf-8')
>>> saveGameDetails = {
    'playerName': 'Ethan',
    'level': 3,
    'livesSpared': 0.88,
    'easyDifficultyLevel': False,
    'intermediateDifficultyLevel': True,
    'hardDifficultyLevel': False,
    'visitsToHolyLand': None,
    'merryMen': {
        'Healer': 'Maid Marian',
        'SwordsMan': 'Will Scarlet',
        'FistFighter': 'Little John'
        },
    'locations': [
        'Nottinghamshire', 'Yorkshire', 'Sherwood'
        ]
    }
>>> json.dump(saveGameDetails, jsonFileHandler, indent = 4)
>>> jsonFileHandler.close()
 
### contents of saveGame.robinhood' in text format
{
    "locations": [
        "Nottinghamshire",
        "Yorkshire",
        "Sherwood"
    ],
    "level": 3,
    "intermediateDifficultyLevel": true,
    "merryMen": {
        "FistFighter": "Little John",
        "Healer": "Maid Marian",
        "SwordsMan": "Will Scarlet"
    },
    "easyDifficultyLevel": false,
    "hardDifficultyLevel": false,
    "livesSpared": 0.88,
    "visitsToHolyLand": null,
    "playerName": "Ethan"
}
 
 
### Deserialization: json.load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
>>> jsonFileHandler = open('saveGame.robinhood', mode = 'r', encoding = 'utf-8')
>>> loadGameDetails = json.load(jsonFileHandler)
 
>>> loadGameDetails
{'locations': ['Nottinghamshire', 'Yorkshire', 'Sherwood'], 'easyDifficultyLevel': False, 'hardDifficultyLevel': False, 'visitsToHolyLand': None, 'playerName': 'Ethan', 'intermediateDifficultyLevel': True, 'level': 3, 'merryMen': {'FistFighter': 'Little John', 'SwordsMan': 'Will Scarlet', 'Healer': 'Maid Marian'}, 'livesSpared': 0.88}
 
>>> for key in loadGameDetails:
    print(key, ": ", loadGameDetails[key])
 
     
locations :  ['Nottinghamshire', 'Yorkshire', 'Sherwood']
easyDifficultyLevel :  False
hardDifficultyLevel :  False
visitsToHolyLand :  None
playerName :  Ethan
intermediateDifficultyLevel :  True
level :  3
merryMen :  {'FistFighter': 'Little John', 'SwordsMan': 'Will Scarlet', 'Healer': 'Maid Marian'}
livesSpared :  0.88
 
### Serialization without files using JSON: dumps() and loads()
>>> configDetails = {
    "dbPass": "DEF",
    "dbUser": "ABC",
    "dbSID": "GHI"
    }
>>> configDetailsJSON = json.dumps(configDetails)
>>> configDetailsJSON
'{"dbUser": "ABC", "dbPass": "DEF", "dbSID": "GHI"}'
>>> type(configDetailsJSON)
<class 'str'>
 
>>> configDetailsDeserialized = json.loads(configDetailsJSON)
>>> configDetailsDeserialized
{'dbUser': 'ABC', 'dbPass': 'DEF', 'dbSID': 'GHI'}
 
 
### NOTE: JSON has no support for tuples and bytes object.


Changing Data Types: Type Casting

Python identifiers do not carry any information about their type while declaration. As soon as a value is assigned to an identifier, Python determines the data type of the identifier, and gives it its own set of associated functions depending on the data type. There are instances when you need to explicitly convert one data type into another. For this purpose, Python provides numerous builtin functions. For example, in order to convert a string identifier into an integer, we can use the int() function.

>>> oneTwoThree = '123'
>>> type(oneTwoThree)
<class 'str'>
>>> number123 = int(oneTwoThree)
>>> type(number123)
<class 'int'>

Similarly, Python provides these functions: str(), float(), complex(), bool(), chr(), bin(), oct() & hex(). You can use the builtin help function to know how to use these.


Creating isolated Python environments using virtualenv

Creating isolated Python environments is a great industrial practice to keep two or more applications separate from each other. These applications have different dependencies, e.g. one may use 1 version of an imported library and the other may use another version of it. To keep both these applications stable and unmangled from each other, it's best to create two different Python environments to avoid the hassle of why-is-this-application-running-and-why-is-this-not.

The Cheese Shop provides a library called virtualenv which helps the developers to create separate Python environments. Using this library, you can create a standalone Python environment for a project with a simple command. This standalone copy of Python has pip with it, which you can use to install libraries you need only for this project. These libraries will not be installed in the global copy of Python you have on your system. In order to recreate the same environment on another system, virtualenv enables us to create a text-file of all the installed libraries which you can provide to the new environment during its creation, and it will install them one-by-one on its own. Furthermore, virtualenv also allows you to choose which version of Python you want to work with by specifying it during environment creation command.

For details on how to do all this, check this post out on Creating isolated Python environments using virtualenv.


Using Lambda Expressions (Anonymous functions)

Lambda expressions(a.k.a. lambda forms) in Python are used to create anonymous functions. In a nutshell, these functions do not have the def keyword, instead have a lambda keyword, take any number of arguments and return a single value in the form of an expression.

# Syntax of a lambda expression:
lambda [arg1 [,arg2,.....argn]]:expression
 
# Example
>>> myLambdaExpr = lambda x: x + 2
>>> myLambdaExpr(5)
7
 
>>> myLambdaExpr
<function <lambda> at 0x02D21978>
 
>>> def myNormalFunc():
    print()
     
>>> myNormalFunc
<function myNormalFunc at 0x02D219C0>
 
# Example
>>> add = lambda num1, num2: num1 + num2
>>> add(3,4)
7

Lambda expressions may not necessarily enhance readability, but they help in making the code compact, as they replace elementary functions which return a single expression.

In actuality, lambda is the basic form of a function definition. Any function, in principle, is a lambda assigned to a variable. The expression "lambda arguments: expression" yields a function object. The unnamed object behaves like a function object defined with

def (arguments):
return expression

Keep in mind that:

  • Lambda expressions cannot contain statements.
  • Lambda expressions have their own local namespace and cannot access variables other than those in their parameter list and those in the global namespace.
  • Lambda expression are extremely useful in GUI Programming. They serve as callback functions.
  • In a broad sense, anything you can do with a lambdas, you can achieve the same with named functions, or lists. However, it’s up to you to choose whether to use lambdas or not. You could decide based on the readability of your code.
  • l = lambda x: x + 2 is the same as def l(x): return x + 2

Using semi-colon (;) to delimit statements in a suite

Python uses new-lines as statement delimiters. This is in contrast to many contemporary languages which use semi-colons to delimit statements. However, Python also allows to use semi-colons. A clause in Python, consists of a header and a suite. For example, the def clause, used for defining functions, will have 'def functionName():' as header while the statements constituting the functionBody will serve as the associated suite. You can put semi-colon delimited statements in suites to put multiple statements on the same line.

>>> def anyFunction(): print(5); print(6); print(7)

>>> anyFunction()
5
6
7

The reason why this is allowed is a design decision on the part of Python developers. While this is not a necessary feature of Python, it is certainly nice to have.


Logging using logging module

The standard library logging helps you to log events of different severities to a file or the standard output in interpreter. This is particularly helpful in large applications where you would like to record events as they occur for future reference. Expand the following snippet for an example of logging. To know more about the logging module, I suggest you view this article.

>>> import logging

>>> logging.basicConfig(level = 10, format = '%(asctime)s %(levelname)s %(message)s')

>>> logging.debug('A debugging message here.')
2017-02-18 04:40:38,420 DEBUG A debugging message here.
>>> logging.info('An informative message here.')
2017-02-18 04:40:41,274 INFO An informative message here.
>>> logging.warning('A warning message here.')
2017-02-18 04:40:42,773 WARNING A warning message here.

See also: 50+ Tips & Tricks for Python Developers


Buffer this pageShare on FacebookPrint this pageTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUpon

Leave a Reply