Page #3
- Naming Convention of Variables/Attributes
- Using builtin chr() & ord() functions
- Interchanging Data Structures: list(), tuple(), dict(), set(), frozenset()
- String Concatenation
- The __init__() magic method
- The __str__() magic method
- Getting size of an object in memory
- Collecting arguments passed to a Python script
- Leveraging the builtin math module
- Fetching last N elements of an iterable
Naming Convention of Variables/Attributes
There are 4 conventions followed while naming variables in Python:
- Dunder attributes/Magic attributes such as __doc__, __name__ etc. are named with double underscores wrapped around the attribute name. It is general consensus to use the dunder attributes that Python is shipped with, and not create new ones.
- Variables/Attributes intended for private use by the class or module are prefixed with a single underscore e.g. _attr. Note that this is merely a convention, naming an attribute this way does not make it unusable by external classes and modules. It is merely a hint for fellow developers.
- Variables/Attributes intended for public use should be named in lower case i.e. variable_name. Note that this is also a convention only, you need not follow it strictly. You can opt for camelCasing as well, like I have done in examples all across the djangoSpin website. The important thing is that you know that this is a popular convention, and while writing professional Python code, you should use lower case variable names with underscores rather than camel casing.
- Variables/Attributes that are intended for private use by the class or module and not open for subclassing are named with double underscores in the beginning i.e. __variable_name. These can be accessed using a special syntax as shown below.
>>> class Man(object): def __init__(self): self.var_one = 1 # public variable self._var_two = 2 # private variable, open for subclassing and external use self.__var_three = 3 # private variable, not open for subclassing and external use self.__var_four__ = 4 # dunder variable >>> ethan = Man() >>> ethan.__dict__ {'_var_two': 2, '__var_four__': 4, 'var_one': 1, '_Man__var_three': 3} >>> _Man__var_three Traceback (most recent call last): _Man__var_three NameError: name '_Man__var_three' is not defined >>> Man._Man__var_three Traceback (most recent call last): Man._Man__var_three AttributeError: type object 'Man' has no attribute '_Man__var_three' >>> ethan._Man__var_three # correct syntax to access a private variable which is not open for subclassing and external use 3
Using builtin chr() & ord() functions
The ord() function takes a single character (special ones too) and returns its Unicode value. Unicode is a collection of codes for more than 1,20,000 characters covering letters, numbers in a variety of languages, including symbols. Unicode values for letters a through z are 97 to 122 & A through Z are 65 to 90. It is inverse of the builtin chr() function.
The chr() function takes a Unicode value and returns the symbol or letter represented by the provided code in the Unicode dictionary. It is inverse of the builtin ord() function.
>>> ord('a') 97 >>> chr(97) 'a'
Interchanging Data Structures: list(), tuple(), dict(), set(), frozenset()
You can make any data structure from any other data structure using the builtin constructors list(), tuple(), dict(), set(), frozenset() of their respective classes. This interchanging operation is incredibly helpful in certain situations e.g. while reversing a tuple, while removing duplicates from a list, extracting keys and values from a dictionary, making a set immutable by initializing a frozenset from it etc. Expand the following for examples.
# list to tuple # transforming a mutable list into an immutable tuple >>> myList = [number for number in range(1, 11)] >>> myTuple = tuple( myList ) >>> print("Type: ", type( myTuple ), ";", "Contents: ", myTuple) Type: <class 'tuple'> ; Contents: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) # tuple to list # sorting a tuple >>> tupleOfNumbers = (5, 4, 2, 3, 1) >>> listOfNumbers = list(tupleOfNumbers) >>> listOfNumbers.sort() >>> listOfNumbers [1, 2, 3, 4, 5] >>> newTupleOfNumbers = tuple(listOfNumbers) >>> newTupleOfNumbers (1, 2, 3, 4, 5) # list to set # removing duplicates >>> myList = [number for number in range(1, 11)] >>> myList2 = [number for number in range(5, 16)] >>> myList + myList2 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] >>> mySet = set( myList + myList2 ) >>> mySet {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} # set to frozenset # making a set immutable >>> mySet = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} >>> mySet.add(16) >>> mySet {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16} >>> myImmutableSet = frozenset( mySet ) >>> myImmutableSet.add(17) # Traceback information AttributeError: 'frozenset' object has no attribute 'add' # dict to list # initializing a new dictionary from the keys of an exisitng dictionary >>> myDictionary = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5} >>> myListOfKeys = list( myDictionary.keys() ) >>> myListOfKeys ['one', 'four', 'five', 'three', 'two'] >>> myNewDictionary = dict.fromkeys( myListOfKeys ) >>> myNewDictionary {'one': None, 'four': None, 'two': None, 'three': None, 'five': None}
String Concatenation
Python allows to concatenate two or more strings using the + operator, or by simply placing the strings adjacent to each other.
>>> a = 'Hello'' ''there!' >>> a 'Hello there!' >>> b = 'Hello' ' ' 'there!' >>> b 'Hello there!' >>> >>> >>> a = 'Hello ' >>> b = 'there!' >>> a + b 'Hello there!'
However, it is not the ideal way to join strings. Best practice is to use the format() function of strings.
>>> "{}{}".format(a, b) 'Hello there!'
The curly braces act as placeholders for the arguments specified in the format() function.
The __init__() magic method
The __init__ method is one of several class methods which are called implicitly on certain events. These methods are called magic methods, or dunder methods, because of the double underscore in front of the method name. These methods need not be defined, but if defined, Python will execute them on certain events. The __init__() method is called when an instance is created.
The init stands for initialization, as it initializes attributes of the instance. It is called the constructor of a class.
# initializing an instance with static data >>> class Man: def __init__(self): self.name = 'Ethan' self.age = 10 self.weight = 60 self.height = 100 def details(self): print("Hi, I am {}. I am {} years old. I weigh {} lbs and I am {} cm tall.". format(self.name, self.age, self.weight, self.height)) >>> ethan = Man() >>> ethan.details() Hi, I am Ethan. I am 10 years old. I weigh 60 lbs and I am 100 cm tall. # initializing an instance with dynamic data >>> class Man: def __init__(self, name, age, weight, height): self.name = name self.age = age self.weight = weight self.height = height def details(self): print("Hi, I am {}. I am {} years old. I weigh {} lbs and I am {} cm tall.". format(self.name, self.age, self.weight, self.height)) >>> ethan = Man('Ethan', 10, 60, 100) >>> ethan.details() Hi, I am Ethan. I am 10 years old. I weigh 60 lbs and I am 100 cm tall.
The __str__() magic method
Like the __init__() method, the __str__() method is one of several class methods which are called implicitly on certain events. These methods are called magic methods, or dunder methods, because of the double underscore in front of the method name. These methods need not be defined, but if defined, Python will execute them on certain events. The __str__ magic method is called when the object is printed, for example, while printing it. The __str__ is defined to return a string representation of the instance.
# When the __str__() is not defined >>> class Man: def __init__(self, name, age, weight, height): self.name = name self.age = age self.weight = weight self.height = height print("1.", self) >>> ethan = Man('Ethan', 10, 60, 100) 1. <__main__.Man object at 0x033D0710> # from print(self) >>> print(ethan) <__main__.Man object at 0x033D0710> # from print(instanceName) >>> >>> >>> >>> >>> # When the __str__() is defined >>> class Man: def __init__(self, name, age, weight, height): self.name = name self.age = age self.weight = weight self.height = height print("1.", self) def __str__(self): return "{} | {} | {} | {}".format(self.name, self.age, self.weight, self.height) >>> ethan = Man('Ethan', 10, 60, 100) 1. Ethan | 10 | 60 | 100 # from print(self) >>> print(ethan) Ethan | 10 | 60 | 100 # from print(instanceName)
Getting size of an object in memory
The getsizeof() function of sys module tells us about the size of an object in memory in bytes. This can be particularly useful while identifying performance bottlenecks.
>>> import sys >>> sys.getsizeof(5) 14 >>> sys.getsizeof('hello') 30 >>> sys.getsizeof( [1, 2, 3, 4] ) 52
Collecting arguments passed to a Python script
The builtin sys module exposes objects used or maintained by the Python interpreter. One of these objects is argv, which is a list that captures the arguments passed to a Python script while calling it.
# anyPythonFile.py import sys print(sys.argv) # From the command prompt $ python path_to_anyPythonFile.py hello there ! # OUTPUT ['anyPythonFile.py', 'hello', 'there', '!']
Note that argv[0] is the name of file itself.
Leveraging the builtin math module
The builtin math module provides functions for mathematical operations such as sin(), cos(), factorial(), log() etc.
>>> import math >>> math.factorial(5) 120 >>> math.cos(0) 1.0
Fetching last N elements of an iterable
In order to fetch the last n items of an iterable, you can use slicing with a negative index. Slicing is a handy way to quickly access parts of an iterable, and is a very fast operation.
Say you have a list of 10 numbers added sequentially, and you need to retrieve the most recently added 5 elements, then you would write listOne[-5:] to serve the purpose. This can be read as "5th from end to end."
>>> listOne = [2, 6, 9, 2, 5, 3, 6, 10] >>> listOne[-5:] [2, 5, 3, 6, 10]
To know more about slicing, click here.
See also: 50+ Know-How(s) Every Pythonista Must Know