Selection @pythonetc, October 2018
This is the fifth collection of Python tips and programming from my author’s @pythonetc channel.
Previous selections:
Separator --
Each decent command-line utility should take arguments in the form of options (for example, -h or --help ), options with parameters ( --log-level 2 ), or positional parameters ( cp file1 file2 ).
Options differ from positional parameters by having one or two dashes at the beginning. When positional arguments begin with a dash, problems arise: if you want to delete a file named -rf , the rm -rf command will not help you with this.
The easy way out is to use two dashes as a delimiter. Arguments after are not considered options:
$ echo test > -rf
$ cat -rf
cat: invalid option -- 'r'
Try 'cat --help'for more information.
$ cat -- -rf
test
$ rm -- -rf
$ cat -- -rf
cat: -rf: No such file or directory
Two dashes are supported by the argparse module out of the box.
Sorting stability
Standard sorting in Python is robust, the sorted function does not change the order of equal objects:
In : a = [2, -1, 0, 1, -2]
In : sorted(a, key=lambda x: x**2)
Out: [0, -1, 1, 2, -2]
The min and max functions are also consistent with sorted. max works as sorted (a, reverse = True) [0] , and min - sorted (a) [0] . This means that both functions return the leftmost possible answer:
In : max([2, -2], key=lambda x: x**2)
Out: 2
In : max([-2, 2], key=lambda x: x**2)
Out: -2
In : min([2, -2], key=lambda x: x**2)
Out: 2
In : min([-2, 2], key=lambda x: x**2)
Out: -2
Default cache argument
Perhaps the most common mistake among novice Pythonists is specifying a variable object as the default argument of a function. Splitting this object between function calls can lead to the strangest results:
defappend_length(lst=[]):
lst.append(len(lst))
return lst
print(append_length([1, 2])) # [1, 2, 2]
print(append_length()) # [0]
print(append_length()) # [0, 1]
However, such sharing will even be useful if you use the object to create a shared cache:
deffact(x, cache={0: 1}):if x notin cache:
cache[x] = x * fact(x - 1)
return cache[x]
print(fact(5))
In this example, we place the calculated factorial values inside the default argument value. Such values can even be extracted:
>>> fact.__defaults__
({0: 1, 1: 1, 2: 2, 3: 6, 4: 24, 5: 120},)
Work with FS
You can work with file system paths using the os.path module . The module contains many functions that perceive strings as file paths and perform various useful operations on them, such as concatenation:
>>> import os.path
>>> os.path.join('/usr', 'local')
'/usr/local'>>> os.path.dirname('/var/log')
'/var'
Starting with version 3.4, Python includes the pathlib module , which offers an object-oriented approach:
>>> from pathlib import Path
>>> Path('/usr') / Path('local')
PosixPath('/usr/local')
>>> Path('/usr') / 'local'
PosixPath('/usr/local')
>>> Path('/var/log').parent
PosixPath('/var')
>>> Path('/var/log').parent.name
'var'
Called Objects
In Python, you can create a callee not only by creating functions (using def syntax or lambda syntaxes ). An object becomes invoked if it has a __call__ method :
classTruncater:def__init__(self, length):
self._length = length
def__call__(self, s):return s[0:self._length]
print(Truncater(4)('abcdabcd')) # abcd
Since the decorator is essentially a higher order function, it can also be expressed by the called object and not by the function:
classcached:def__init__(self, func):
self._func = func
self._cache = {}
def__call__(self, arg):if arg notin self._cache:
self._cache[arg] = self._func(arg)
return self._cache[arg]
@cacheddefsqr(x):return x * x