Python @ DjangoSpin

50+ Tips & Tricks for Python Developers

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

Page #9


Using builtin function issubclass()

The builtin function issubclass(subClass, superClass) returns True if the class subClass is a subclass of the class superClass, else it returns False.

>>> help(issubclass)
Help on built-in function issubclass in module builtins:

issubclass(...)
    issubclass(C, B) -> bool
    
    Return whether class C is a subclass (i.e., a derived class) of class B.
    When using a tuple as the second argument issubclass(X, (A, B, ...)),
    is a shortcut for issubclass(X, A) or issubclass(X, B) or ... (etc.).
	
### EXAMPLE ###
>>> class Person(object): pass
>>> class Man(Person): pass
>>> class Woman(Person): pass

>>> issubclass(Man, Person)
True

>>> issubclass(Man, object)
True

>>> issubclass(Woman, Man)
False

If you are uncertain about the exact parent class of a subclass, you can insert all the likely classes in the form of a tuple. The issubclass() function will return True if the class specified is a subclass of either of the specified classes.

>>> issubclass( Man, (Person, Woman) )
True
>>> issubclass( Person, (Man, Woman) )
False

Keep in mind that all builtin-classes, data types, user-defined classes inherit from the class called object.


Using a buffer while manipulating files

A buffer stores a chunk of data from the Operating System's file stream until it is consumed, at which point more data is brought into the buffer. The reason that is good practice to use buffers is that interacting with the raw stream might have high latency i.e. considerable time is taken to fetch data from it and also to write to it. Let's take an example.

Let's say you want to read 100 characters from a file every 2 minutes over a network. Instead of trying to read from the raw file stream every 2 minutes, it is better to load a portion of the file into a buffer in memory, and then consume it when the time is right. Then, next portion of the file will be loaded in the buffer and so on.

The following code snippet reads a file containing 196 bytes, with a buffer of 20 bytes, and writes to a file, 20 bytes at a time.

# A practical example will have large-scale values of buffer and file size.
buffersize = 20			                    # maximum number of bytes to be read in one instance
inputFile = open('fileToBeReadFrom.txt', 'r')       
outputFile = open('fileToBeWrittenInto.txt', 'a')   # opening a file in append mode; creates a file if it doesn't exist
buffer = inputFile.read(buffersize)		    # buffer contains data till the specified cursor position

# Writing the contents of a buffer another file 20 bytes at a time
counter = 0		                            # a counter variable for us to see the instalments of 20 bytes						
while len(buffer):
    counter = counter + 1
    outputFile.write(buffer)
    print( str(counter) + " ")
    buffer = inputFile.read(buffersize)		    # next set of 20 bytes from the input file

outputFile.close()
inputFile.close()

To learn more about buffers, check out this link.


Reloading a module

There are occasions when you have changed the code of a module, and you want the changes to reflect without having to relaunch the interpreter or restart the server. Python doesn't support this by default. However, the reload() function of importlib standard library helps you to do just that.

# CONTENTS OF foo.py
def spam():
    print("SPAM!")

# A SESSION IN THE INTERACTIVE INTERPRETER
>>> import foo
>>> foo.spam()
SPAM!

# CHANGED CONTENTS OF foo.py
def spam():
    print("SPAM! SPAM!")

# SAME SESSION IN THE INTERACTIVE INTERPRETER
>>> foo.spam()						
SPAM!										# Changes have not reflected yet.
>>> import importlib
>>> importlib.reload(foo)
<module 'foo' from 'complete_path_to_foo.py'>
>>> foo.spam()
SPAM! SPAM!



#### Common Practice to Handle Frequently Modified Modules ####
import moduleOne
import moduleTwo
from importlib import reload

reload(moduleOne)
reload(moduleTwo)

from moduleOne import *
from moduleTwo import *

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.

Making a variable global: global keyword

There will be instances where you are declaring an object inside a confined piece of code, and you will need the object outside it as well. You can use the global keyword for this.

## BEFORE
>>> def storeMyName():
        name = "Ethan"
  
>>> storeMyName()
>>> name
Traceback (most recent call last):
  # Traceback Info
    name
NameError: name 'name' is not defined
 
## AFTER
>>> def storeMyName():
        global name
        name = "Ethan"
  
>>> storeMyName()
>>> name
'Ethan'

Creating random objects of subclasses of a superclass

Using the random module and Generators, we can have Python make random objects of subclasses of a superclass.

>>> import random
>>> class Crop(object):
	def sow(self):
		print("Sowing...")
	def irrigate(self):
		print("Irrigating...")
	def harvest(self):
		print("Harvesting...")

		
>>> class Wheat(Crop): pass

>>> class Corn(Crop): pass

>>> class Tomato(Crop): pass

>>> def cropGenerator(numberOfInstancesToCreate):
    crops = Crop.__subclasses__()
    for number in range(numberOfInstancesToCreate):
        yield random.choice(crops)()

        
>>> cropGeneratorObject = cropGenerator(5)
>>> for cropObject in cropGeneratorObject:
	print(cropObject)

	
<__main__.Corn object at 0x02E7E950>
<__main__.Corn object at 0x02E65BB0>
<__main__.Wheat object at 0x02B09EB0>
<__main__.Tomato object at 0x02E65BB0>
<__main__.Corn object at 0x02B09EB0>

Removing duplicate items from lists

A simple way to remove duplicate items from a list is to cast it to a set, and then back to a list using the constructors of builtin set and list classes.

>>> aList = [1, 2, 3, 1, 2, 3, 4, 5]
>>> list( set(aList) )
[1, 2, 3, 4, 5]

Implementing Caesar Cipher in Python

Julius Caesar was a Roman dictator who came up with a clever way of passing confidential information to his generals without having to worry about it falling into the wrong hands. He shifted each letter in the message by a fixed shift value i.e. if the shift value was 3, a became d, f became i and so on. He would leave the numbers and other characters untouched. His generals would only need the shift value to decode their emperor's message. Later on, this cryptography technique came to be known as Caesar Cipher.

You can implement Caesar Cipher in Python using the builtin ord(), chr() functions, a for loop, a couple of if-else constructs.

The ord() function returns the Unicode value of the character supplied to it. It is inverse of builtin chr() function which returns the character in the Unicode character set, denoted by the number provided to it.

Expand the following code snippet for the script. You can run it online here.

## Implement a Caesar Cipher that shifts all the letters in a given message by an given number of places.
 
## Example of Caesar Cipher: 'Hello' becomes 'Khoor' when characters are shifted by 3 places. 'Can you read this?' becomes 'Kiv gwc zmil bpqa?' when characters are shifted by 8 places. 'Can you read this?' becomes 'Zxk vlr obxa qefp?' when characters are shifted by 3 places in the backwards direction.
 
## THOUGHT PROCESS: Prompt the user for the message to encrypted and the number of places each character should be shifted by in the encrypted message -> initialize the encrypted message to an empty string -> begin a for loop to process each character in the entered message -> branch the control into three code blocks, to process uppercase, lowercase and non-alphabet characters separately -> for uppercase and lowercase characters, calculate the position of the character by subtracting Unicode value of the first letter i.e. 'a' or 'A' from the Unicode value of the character -> calculate its new positon by adding the shift value and obtaining the remainder on dividing by 26 -> convert the new position into character form using the builtin chr() function -> append the new character to the encrypted message -> for non-alphabet characters, append them to the encrypted message without shifting -> output the encrypted message.
 
## INPUT
message = input("Enter the message you want to encrypt: ")
shiftValue = int(input("Enter the places you want the characters to be shifted by: "))
 
## PSEUDO CODE / ALGORITHM:
# Initialize the newMessage to an empty string
# Using a for loop, process each letter in the following way:
#     Determine whether it's lowercase or uppercase using an if statement, proceed accordingly:
#         using ord(), determine its position in the alphabet(0-25)
#         calculate its new offset by adding the shiftValue and getting the remainder on dividing by 26(for taking care of shiftValue > 26)
#         convert the position to character by using chr()
#         append the new character to the newMessage
#     If the character is not an alphabet, append it to newMessage as it is, without shifting.
newMessage = ""
for character in message:
    if character >= "a" and character <= "z":
        position = ord(character) - ord("a")
        position = (position + shiftValue) % 26
        newCharacter = chr(position + ord("a"))
        newMessage = newMessage + newCharacter
    elif character >= "A" and character <= "Z":
        position = ord(character) - ord("A")
        position = (position + shiftValue) % 26
        newCharacter = chr(position + ord("A"))
        newMessage = newMessage + newCharacter
    else:
        newMessage = newMessage + character
 
## OUTPUTTING RESULT
print("\nHere is the encypted message: \n\n" + newMessage)

High-level file operations using shutil module

The standard library module shutil facilitates basic operations on files and directories. You can copy files and directories, move them, remove them, pretty much everything you would like to do with them. Following is a list of frequently used functions of the shutil module:

shutil.copy(source,destination) 						# Creates a copy of file at source path to destination path.
shutil.copymode(source,destination)						# Sets file permissions of destination file/directory to that of source file/directory.
shutil.copystat(source, destination)					# Copies permissions, statistics such as last access time, last modification time, flags of source file/directory to destination file/directory
shutil.copy2(source, destination)						# Copies the file data, permissions, metadata such as file creation & modification time etc. of source file/directory to destination file/directory
shutil.disk_usage(path)									# Returns a three-element tuple denoting total, use and free space of given path, in bytes.
shutil.move(source, destination)						# Moves the file/directory at source path to destination path. Renames the file if executed in the same directory.
shutil.copytree(source, destination)					# Copies the entire directory at source path to destination path by creating a new directory specified in destination argument.
shutil.rmtree(path)										# Removes the entire directory at given path.

Regular Assignment, Shallow copy & Deep Copy

There are three ways to copy objects in Python: assignment, shallow copy & deep copy.

  1. Regular assignment points the new variable towards the original object. Let's use the builtin id() function prove this. The id() function returns the object's memory address.
  2. objOne = [1, 2, 3]
    objTwo = [4, 5, 6]
    objThree = [objOne, objTwo]
    
    objFour = objThree
    
    print( id(objThree) == id(objFour) )			# True as objThree & objFour are the same object
    print( id(objThree[0]) == id(objFour[0]) )		# True as objThree[0] & objFour[0] are the same object
    
  3. Shallow copy

    The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances):

    A shallow copy constructs a new compound object and then (to the extent possible) inserts references into it to the objects found in the original.
    A deep copy constructs a new compound object and then, recursively, inserts copies into it of the objects found in the original.

    Python Documentation

  4. import copy
    
    objFour = copy.copy(objThree)
    
    print( id(objThree) == id(objFour) )          # False as objFour is a new object
    print( id(objThree[0]) == id(objFour[0]) )    # True as objFour[0] is the same object as objThree[0]
    
  5. Deep Copy
  6. objFour = copy.deepcopy(objThree)
    
    print( id(objThree) == id(objFour) )          # False as objFour is a new object
    print( id(objThree[0]) == id(objFour[0]) )    # False as objFour[0] is a new object
    

    See also: 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

Leave a Reply