is
vs ==
__str__
and __repr__
Some Notes on Python language features, with examples...
Motivation: here I provide some notes made whilst reviewing the book "Python tricks" by Dan Bader, which is a very useful highly recommended book available here. Python has become the third most popular programming language behind Java and C, and it continues to become more popular. It is an easy to learn high-level language, that is fun to use and learn. Some of the more advanced and interesting language features are discussed here.
The Zen of Python
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Variable name | Description |
---|---|
_var | Hints to a programmer that the variable is intended for internal use, these variables will not be imported with a wildcard e.g. from my_module import * (although this is bad practice to use wildcard imports "explicit is better than implict"). |
var_ | Useful when the name var is already in use and as an alternative to _var |
__var | Names starting with a dunder will be are rewritten to avoid conflicts in a process called name wrangling, such that the class name is added for example _ClassName__var . Name mangling is helpful for letting subclasses override methods without breaking intraclass method calls see here. |
__var__ | For such variables name mangling is not applied, but these are reserved for special use in the language called 'magic' methods. This naming convention is best avoided to avoid any future collisions with the Python Language. |
_ | A temporary variable may be used to indicate a standalone or insignificant, temporary variable. This is by convention only, the _ is also used REPL to access the last variable, which is very handy. |
assert
statement exists in almost every programming language. It helps detect problems early in a program, where the cause is clear, rather than later as a side-effect of some other operation.assert condition
... you're telling the program to test that condition, and immediately trigger an error if the condition is false.python -O script.py
. Since they can be disabled do not use assert
for data validation.assert False, "Oh no! This assertion failed!"
assert
like a function. It is a statement. If you do assert(condition, message)
you'll be running the assert
with a (condition, message)
tuple as first parameter which always evaluates to True.$ cat /proc/sys/fs/file-max
1188554
open()
without a close()
statement.hello.txt
will always be closed:with open('hello.txt', 'w') as f:
f.write('hello, world!')
try/finally
statements in context-managers. This ensures the safe acquisition and release of system resources, acquiring in the with context and leaving releasing when execution leaves the with context.is
vs ==
==
checks for equality, the is
operator compares identities.>>> def dispatch_if(operator, x, y):
... if operator == 'add':
... return x + y
... elif operator == 'sub':
... return x - y
... elif operator == 'mul':
... return x * y
... elif operator == 'div':
... return x / y
with
>>> def dispatch_dict(operator, x, y):
... return {
... 'add': lambda: x + y,
... 'sub': lambda: x - y,
... 'mul': lambda: x * y,
... 'div': lambda: x / y,
... }.get(operator, lambda: None)()
zs = {**xs, **ys}
where duplicate entries are overwritten by the rightmost object in this case ys
.def get_speak_func(text, volume):
def whisper():
return text.lower() + '...'
def yell():
return text.upper() + '...'
if volume > 0.5:
return yell
else:
return whisper
>>> add = lambda x, y: x + y
>>> add(5, 3)
8
or called on one line
>>> (lambda x, y: x + y)(5, 3)
8
def
but written inline.@
syntax either at definition or at callimport functools
def trace(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print(f'TRACE: calling {func.__name__}() '
f'with {args}, {kwargs}')
original_result = func(*args, **kwargs)
print(f'TRACE: {func.__name__}() '
f'returned {original_result!r}')
return original_result
return wrapper
functools.wraps
to the wrapper closure returned by the decorator carries over the docstring and other metadata of the input function.*args
and **kwargs
let you write functions with a variable number of arguments in Python.*args
collects extra positional arguments as a tuple. **kwargs
collects the extra keyword arguments as a dictionary.*
and **
. Calling them args and kwargs is just a convention (and one you should stick to).None
if a return statement is not written__str__
and __repr__
__str__
and __repr__
dunder class methods__str__
should be readable, and __repr__
unambiguous.__repr__
since the default implemntation of __str__
just calls __repr__
class Car:
def __init__(self, color, mileage):
self.color = color
self.mileage = mileage def __repr__(self):
def __repr__(self):
return (f'{self.__class__.__name__}('
f'{self.color!r}, {self.mileage!r})')
def __str__(self):
return f'a {self.color} car'
class BaseValidationError(ValueError):
pass
class NameTooShortError(BaseValidationError):
pass
class NameToolongError(BaseValidationError):
pass
copy.copy()
copy.deepcopy()
.import copy
xs = [[1, 2, 3], [4, ,5, 6]]
zs = copy.deepcopy(xs)
from abc import ABC, abstractmethod
class Animal(ABC):
def move(self):
pass
class Human(Animal):
def move(self):
print("I can walk and run")
class Snake(Animal):
def move(self):
print("I can crawl")
class Dog(Animal):
def move(self):
print("I can bark")
class Lion(Animal):
def move(self):
print("I can roar")
collection.namedtuple
is a memory-efficient shortcut to manually define an immutable class in Python.>>> from collections import namedtuple
>>> Car = namedtuple('Car' , 'color mileage')
class Dog:
num_legs = 4 # <- Class variable
def __init__(self, name):
self.name = name # <- Instance variable
MyClass.method
, is a regular instance method. It takes one parameter, self
, which points to an instance of MyClass
when the method is called. Through the self parameter, instance methods can freely access attributes and other methods on the same object. This gives them a lot of power when it comes to modifying an object’s state. Not only can they modify object state, instance methods can also access the class itself through the self.__class__
attribute.MyClass.classmethod
, marked with a @classmethod
decorator takes a cls
parameter that points to the class and not the object instance when the method is called. Since the class method only has access to this cls argument, it can’t modify object instance state. That would require access to self . However, class methods can still modify class state that applies across all instances of the class.MyClass.staticmethod
is marked with a @staticmethod
decorator to flag it as a static method. This type of method doesn’t take a self or a cls
parameter, although, of course, it can be made to accept an arbitrary number of other parameters. As a result, a static method cannot modify object state or class state. Static methods are restricted in what data they can access they are primarily a way to namespace your methods.class MyClass:
def method(self):
return 'instance method called', self
@classmethod
def classmethod(cls):
return 'class method called', cls
@staticmethod
def staticmethod():
return 'static method called'
collections.ChainMap
groups dictionaries into a single mapping ChainMap(dict1, dict2)
list
mutable dynamic arraystuple
- immutable containersarray.array('f, [1.0, 8.0]')
space-efficient storage of basic C-style data types, constrained
to a single data type, so are more space efficient than lists or tuples.str
is an immutable store of textual data as unicode charactersbytes
objects are immutable sequences of single bytes, conceptually similar to string objects.bytesarray
- mutable array of single bytesset
an unordered collection of objects that does not allow duplicatesfrozenset
an immutable version of a set (no insert or deletion)multisets
in collections.Counter
implements a multiset that allows elements in the set to have more than one occurancestacks
- last-in, first-out (LIFO) semantics, don't allow for random access.queue
- first-in, first-out (FIFO)deque
- a fast double-ended queue doubly linked lists