Advanced Python Tutorial Notes
Rules | Conventions
- Python is case-sensitive, which means, for example, Name and name have different meanings
- Use 4 spaces per indentation level
- All variables should start with a lowercase letter, for example, var = 4
- Functions begin with lowercase
- Classes begins with a capital letter
- The first letter of a variable, function, or class must be one of the letters (a-z) or (A-Z). Numbers or special characters such as & and % are not allowed
- Special characters cannot be used in names
- There are reserved words, such as and, if, else, break, import, and more, which are not allowed in naming
- Limit all lines to a maximum of 79 characters
- Surround top-level function and class definitions with two blank lines
- Method definitions inside a class are surrounded by a single blank line
- Code in the core Python distribution should always use UTF-8, and should not have an encoding declaration
- Imports should usually be on separate lines
-
Imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants.
Imports should be grouped in the following order:- Standard library imports.
- Related third party imports.
- Local application/library specific imports.
You should put a blank line between each group of imports.
- Absolute imports are recommended
- When importing a class from a class-containing module, it’s usually okay to spell this
- Wildcard imports (from <module> import *) should be avoided
- Module level “dunders” (i.e. names with two leading and two trailing underscores) such as __all__, __author__, __version__, etc. should be placed after the module docstring but before any import statements except from __future__ imports
- single-quoted strings and double-quoted strings are the same
- Avoid extraneous whitespace in the following situations
- Immediately inside parentheses, brackets or braces:
# Correct: spam(ham[1], {eggs: 2}) # Wrong: spam( ham[ 1 ], { eggs: 2 } )
- Between a trailing comma and a following close parenthesis:
# Correct: foo = (0,) # Wrong: bar = (0, )
- Immediately before a comma, semicolon, or colon:
# Correct: if x == 4: print(x, y); x, y = y, x # Wrong: if x == 4 : print(x , y) ; x , y = y , x
- However, in a slice the colon acts like a binary operator, and should have equal amounts on either side (treating it as the operator with the lowest priority)
- Immediately before the open parenthesis that starts the argument list of a function call:
# Correct: spam(1) # Wrong: spam (1)
- Immediately before the open parenthesis that starts an indexing or slicing:
# Correct: dct['key'] = lst[index] # Wrong: dct ['key'] = lst [index]
- More than one space around an assignment (or other) operator to align it with another:
# Correct: x = 1 y = 2 long_variable = 3 # Wrong: x = 1 y = 2 long_variable = 3
- Immediately inside parentheses, brackets or braces:
- Avoid trailing whitespace anywhere
- Always surround these binary operators with a single space on either side
- If operators with different priorities are used, consider adding whitespace around the operators with the lowest priority(ies)
# Correct: i = i + 1 submitted += 1 x = x*2 - 1 hypot2 = x*x + y*y c = (a+b) * (a-b) # Wrong: i=i+1 submitted +=1 x = x * 2 - 1 hypot2 = x * x + y * y c = (a + b) * (a - b)
- Function annotations should use the normal rules for colons and always have spaces around the -> arrow if present
# Correct: def munge(input: AnyStr): ... def munge() -> PosInt: ... # Wrong: def munge(input:AnyStr): ... def munge()->PosInt: ...
- Don’t use spaces around the = sign when used to indicate a keyword argument, or when used to indicate a default value for an unannotated function parameter
# Correct: def complex(real, imag=0.0): return magic(r=real, i=imag) # Wrong: def complex(real, imag = 0.0): return magic(r = real, i = imag) # Correct: def munge(sep: AnyStr = None): ... def munge(input: AnyStr, sep: AnyStr = None, limit=1000): ... # Wrong: def munge(input: AnyStr=None): ... def munge(input: AnyStr, limit = 1000): ...
- Compound statements (multiple statements on the same line) are generally discouraged
# Correct: if foo == 'blah': do_blah_thing() do_one() do_two() do_three() # Rather not: # Wrong: if foo == 'blah': do_blah_thing() do_one(); do_two(); do_three()
- While sometimes it’s okay to put an if/for/while with a small body on the same line, never do this for multi-clause statements. Also avoid folding such long lines
- Trailing commas are usually optional, except they are mandatory when making a tuple of one element
- Comments that contradict the code are worse than no comments. Always make a priority of keeping the comments up-to-date when the code changes!
- Block comments generally apply to some (or all) code that follows them, and are indented to the same level as that code
- Use inline comments sparingly
- Write docstrings for all public modules, functions, classes, and methods. Docstrings are not necessary for non-public methods, but you should have a comment that describes what the method does. This comment should appear after the def line
- Names that are visible to the user as public parts of the API should follow conventions that reflect usage rather than implementation.
- Modules should have short, all-lowercase names. Underscores can be used in the module name if it improves readability
- Class names should normally use the CapWords convention.
- Names of type variables introduced in PEP 484 should normally use CapWords preferring short names
- Because exceptions should be classes, the class naming convention applies here
- Function names should be lowercase, with words separated by underscores as necessary to improve readability.
- Variable names follow the same convention as function names.
- Always use self for the first argument to instance methods.
- Always use cls for the first argument to class methods.
- Use the function naming rules: lowercase with words separated by underscores as necessary to improve readability.
- Use one leading underscore only for non-public methods and instance variables.
- To avoid name clashes with subclasses, use two leading underscores to invoke Python’s name mangling rules.
- Constants are usually defined on a module level and written in all capital letters with underscores separating words.
- We can make an instance variable private by adding double underscores (__) before its name
- We can make an instance variable protected by adding single underscores (_) before its name
- All objects share class or static variables
- All variables which are assigned a value in the class declaration are class variables. And variables that are assigned values inside methods are instance variables
- Comments Like this:
def connect_to_next_port(self, minimum: int) -> int:
"""Connects to the next available port.
Args:
minimum: A port value greater or equal to 1024.
Returns:
The new minimum port.
Raises:
ConnectionError: If no available port is found.
"""
if minimum < 1024:
# Note that this raising of ValueError is not mentioned in the doc
# string's "Raises:" section because it is not appropriate to
# guarantee this specific behavioral reaction to API misuse.
raise ValueError(f'Min. port must be at least 1024, not {minimum}.')
port = self._find_next_open_port(minimum)
if port is None:
raise ConnectionError(
f'Could not connect to service on port {minimum} or higher.')
assert port >= minimum, (
f'Unexpected port {port} when minimum was {minimum}.')
return port
Data Types
Mutable
- list
- allows different data types
- allows duplicate elements
- slice -> my_list[start:stop:step]
- start is the first element position to include
- stop is exclusive, meaning that the element at position stop won’t be included.
- step is the step size. more on this later
- start, stop, and step are all optional
- Negative values can be used too
- comprehensions
[ <expression> for item in list if <conditional> ] [x for x in range(1,10) if x % 2 == 0]
- ordered
- dictionaries
- comprehensions
{x: x**2 for x in (2, 4, 6)}
- unordered
- comprehensions
- sets
- no duplicate elements
- unordered
Immutable
- numbers
- booleans
- strings
- ordered
- tuples
- can act as the key in a dictionary
- allows duplicate elements
- ordered
- faster
comparison
Data Type | Ordered | Iterable | Duplicate Elements | Mutable |
---|---|---|---|---|
List | Yes | Yes | Yes | Yes |
Dictionary | No | Yes | Values only | Keys only |
Tuple | Yes | Yes | Yes | No |
Set | No | Yes | No | Yes |
Frozenset | No | Yes | No | No |
Collections
Python’s collections module provides a rich set of specialized container data types carefully designed to approach specific programming problems in a Pythonic and efficient way. The module also provides wrapper classes that make it safer to create custom classes that behave similar to the built-in types dict, list, and str.
Keywords
Global
- A global keyword is a keyword that allows a user to modify a variable outside the current scope
- If a variable is assigned a value anywhere within the function’s body, it’s assumed to be a local unless explicitly declared as global
- Variables that are only referenced inside a function are implicitly global
- We use a global keyword to use a global variable inside a function
- There is no need to use global keywords outside a function
- To access a global variable inside a function, there is no need to use a global keyword
lambda
add10 = lambda x: x + 10
print(add10(5))
def add10_func(x):
return x + 10
map
map(func, seq)
a = [1, 2, 3, 4, 5]
b = map(lambda x: x*2, a)
c = [x*2 for x in a]
filter
filter(func, seq)
a = [1, 2, 3, 4, 5 , 6]
b = map(lambda x: x%2==0, a)
c = [x for x in a if x%2==0]
Class Method VS Static Method
Class Method
The @classmethod decorator is a built-in function decorator that is an expression that gets evaluated after your function is defined. The result of that evaluation shadows your function definition. A class method receives the class as an implicit first argument, just like an instance method receives the instance
Static Method
A static method does not receive an implicit first argument. A static method is also a method that is bound to the class and not the object of the class. This method can’t access or modify the class state. It is present in a class because it makes sense for the method to be present in class.
The difference between the Class method and the static method
- A class method takes cls as the first parameter while a static method needs no specific parameters.
- A class method can access or modify the class state while a static method can’t access or modify it.
- In general, static methods know nothing about the class state. They are utility-type methods that take some parameters and work upon those parameters. On the other hand class methods must have class as a parameter.
- We use @classmethod decorator in python to create a class method and we use @staticmethod decorator to create a static method in python.
When to use the class or static method
- We generally use the class method to create factory methods. Factory methods return class objects ( similar to a constructor ) for different use cases.
- We generally use static methods to create utility functions.
example
# Python program to demonstrate
# use of class method and static method.
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# a class method to create a Person object by birth year.
@classmethod
def fromBirthYear(cls, name, year):
return cls(name, date.today().year - year)
# a static method to check if a Person is adult or not.
@staticmethod
def isAdult(age):
return age > 18
person1 = Person('mayank', 21)
person2 = Person.fromBirthYear('mayank', 1996)
print(person1.age)
print(person2.age)
# print the result
print(Person.isAdult(22))