Python
Table of Contents
1 TODO
1.1 TODO define a static method of a class? so that I can avoid calling of self
1.2 TODO define an inline function to avoid passing constant parameter: the scope of variable?
1.3 TODO python debugger for emacs
1.4 TODO a tree reader for leetcode
2 Language
The ultimate reference:
For python 3
atom
is the most basic expression, while the enclosure
is interesting.
atom ::= identifier | literal | enclosure enclosure ::= parenth_form | list_display | dict_display | set_display | generator_expression | yield_atom
The display
is a special syntax for python to create lists and dicts, using comprehension.
list_display ::= "[" [starred_list | comprehension] "]" set_display ::= "{" (starred_list | comprehension) "}" dict_display ::= "{" [key_datum_list | dict_comprehension] "}" key_datum_list ::= key_datum ("," key_datum)* [","] key_datum ::= expression ":" expression | "**" or_expr dict_comprehension ::= expression ":" expression comp_for
And the comprehension grammar:
comprehension ::= expression comp_for comp_for ::= [ASYNC] "for" target_list "in" or_test [comp_iter] comp_iter ::= comp_for | comp_if comp_if ::= "if" expression_nocond [comp_iter]
The comp_for
non-terminal contains one or more for
clause, and zero or more if
clause.
The evaluation of these displays will evaluate from left to right, so the last assignment will prevail in the case of set and dict. The comprehension is executed by nesting the for and if clauses from left to right.
So some examples:
((a,b) for a in range(2) for b in range(3)) [(a,b) for a in range(2) for b in range(3)] {(a,b) for a in range(2) for b in range(3)} {a:b for a in (1,2) for b in (3,4)}
Note the out-most braces are required, which also creates a scope.
3 Emacs support
Install the elpy
package. It provides:
C-c C-c
runs the shell and send the current bufferC-c C-d
runselpy-doc
C-c C-t
runselpy-test
, which runs the unittest discover
To enable linter python in emacs, use pylint. It will use pylint
executable. And it also needs the configure file. Generate it:
pylint --generate-rcfile > ~/.pylintrc
4 Unit Test
class MyTest(unittest.TestCase): def test_me(self): self.assertEqual(1,2) unittest.main()
python unit test can support automatic test discovery. To use that,
the file must be named test_xxx.py
, and run the python -m unittest discover
.
5 Concept
5.1 Scoping
There're four levels:
- current scope
- parent scope
- module scope (global)
- built-in scope
nonlocal
keyword specify this variable should be referenced to the parent scope.
But, this will not reach global.
Instead, the global
keyword declares the listed variables to be in the module level scope.
The nonlocal statement causes the listed identifiers to refer to previously bound variables in the nearest enclosing scope excluding globals.
As an example:
var = 0 # global def outer(): var = 1 # parent def inner(): nonlocal var var = 2 # local global var var =3 inner() # var = 2 outer() # global var = 3
5.2 Collection
5.2.1 String
5.2.1.1 Concatenation
- concatenate two strings directly by
+
. - need to convert integer to string before concatenate:
s + str(35)
- "".join(lst) works
5.2.1.2 split
str.split(sep=None)
- default by white space
str.strip()
- strip out white space at both begin and end
str.replace(old, new)
- replace all.
str.startswith(s)
str.endswith(s)
5.2.1.3 Slicing
String is an immutable object. It can use slicing. E.g. reversing a
string is as easy as "hello"[::-1]
!
However, notice that when using a negative step, the slicing should be
lst[end:begin:-1]
. This is because x = i + n*k
:
with a third “step” parameter: a[i:j:k] selects all items of a with index x where x = i + n*k, n >= 0 and i <= x < j.
Also, the negative step does not always work as expect. E.g. the i index is included and j is not; the j can not be negative, then how can I include the first one in the list??
Thus if want to get a reverse of a sub-string, I would get sub-string first and then reverse it.
5.2.2 TODO tuple
5.2.3 List
5.2.3.1 Slicing
The slicing syntax is l[start:end:step]
.
The slicing will return a new list. Change to that list will not change the original one.
l[4] l[4:] l[::2] l[:-1]
However, assign to the slicing itself will change the original one:
l[1:2] = [4,5,6]
Also, assign to a new variable only assign the reference:
a = [1,2,3] b = a # only a reference
5.2.3.2 create a list
range(stop)
range(start, stop[, step])
Creating a matrix:
newmat=[[-1 for x in range(height)] for y in range(width)]
5.2.3.3 Modify a list
- list.append
- list.pop
5.2.4 Dictionary
Create:
x = {'a': 1, 'b': 2}
Dictionary is not sorted. Use collections.OrderedDict
if you want this feature.
Basically it remember the order when the elements are inserted.
import collections od = collections.OrderedDict(sorted(d.items()))
Merge two dictionary (x
and y
):
z = x.copy()
z.update(y)
5.2.5 Set
s = set() s.add(x) if x in s: pass
5.3 Algorithm
5.3.1 TODO sort
sort a dictionary by value:
sorted(dict1, key=dict1.get) # => list sorted(dict1, key=dict1.get, reverse=True)
5.4 Function
5.4.1 variadic parameter
use *args
syntax, and args
will be a tuple:
def foo(*args): for a in args: print a
use **args
to capture all keyword arguments.
def bar(**kwargs): for a in kwargs: print a, kwargs[a]
Combine them together:
def foobar(kind, *args, **kwargs): pass
Also, there's a concept for the reverse thing: unpack argument list from a list, with *list
:
def foo(a,b): pass l = [1,2] foo(*l)
on python3, this syntax can appear on left side
first, *rest = [1,2,3,4] first,*l,last = [1,2,3,4]
5.5 Exception
To give a quick feel:
try: pass except TypeError as e: # capture the exception into a variable pass except AnotherError: # does not capture pass except: # all exception pass else: # if doesn't raise an exception pass finally: pass
5.6 Lambda
lambda x : x+2 lambda x: x%2==0
The usage of lambda is often in map and filter.
map(lambda_exp, mylist)
will execute the lambda expression on each element of the list, and return a list containing the results.
5.7 Packaging
Exposing API: the following only expose foo
but not bar
.
__all__ = ['foo'] def foo(): pass def bar(): pass
5.7.1 importing
The local structure directory must contain the __init__.py
file to be able to import.
|-- main.py |-- mypackage |-- __init__.py |-- a.py |-- b.py |-- subdir |-- __init__.py |-- c.py
The import statements should be:
from mypackage import a from mypackage.b import foo as myfoo from mypackage.subdir import c
5.8 Thread
from threading import Thread class MyThread(Thread): def __init__(self, arg): Thread.__init__(self) self.arg = arg def run(self): pass t = MyThread(arg) t.start()
6 Type
6.1 Boolean
not True
6.2 Integer
i += 1
6.3 conversion
- string to integer:
int('45')
- integer to string:
str(45)
- ASCII to char:
chr(100)
returns 'd' - char to ASCII:
ord('d')
returns 100
7 Black Tech
If else or:
var = d.get('key') or 0 # is equal to: var = d.get('key') if d.get('key') else 0
list comprehension
even_squares = [x**2 for x in l if x%2 == 0]
8 Pep8
Indent:
- function and class should be separated by 2 lines
- In a class, function should be separated by 1 line
- 1 space before and after variable assignment
Naming
- function, variable, attribute:
func_var_attr
- protected instance attributes:
_protected_field
- private instance attributes:
__private_field
- class and exception:
ClassExceptionName
- module level constants:
CONSTANT
- instance method of class should use
self
as first parameter, refer to the object - class method should use
cls
as first parameter, refer to the class
Expression
use | DONT use |
---|---|
a is not b |
not a is b |
if not list |
if len(list) == 0 |
Import
- always use absolute path
- if must use relative, use
from . import foo
instead ofimport foo
8.1 document
One can use one line or multi-line document.
The doc string can be retrieved by func.__doc__
.
def func(): """one line doc""" def func(): """The outline The above empty line is required. Here's the detailed documentation. """
9 IO
print('xxx', end='')
f = open('text.txt') f.read() # return all content f = open('text.txt') for line in f: print(line) with open('a.txt') as f: for line in f: print(line)
read from stdin:
for line in sys.stdin: print(line)
get command line argument: sys.argv
10 Operating System
10.1 Work filesystem:
import os for root,dirs,files in os.walk('.'): for f in files: print f
os.path.abspath('relative/path/to/file')
os.path.exists("/path/to/file")
os.rename('old', 'new')
os.path.isfile
10.2 Shell command
os.system
- simply run command
os.system("some command")
os.popen
- access to input output
stream = os.popen("some command") stream.read()
subprocess.Popen
p = subprocess.Popen("echo Hello World", shell=True, stdout=subprocess.PIPE) p.stdout.read() s = subprocess.check_output('wc -l', stdin=p.stdout)
subprocess.call
- this is the same as
subprocess.Popen
except that it waits and gives return code.
return_code = subprocess.call("echo Hello World", shell=True, stdout=subprocess.DEVNULL)
11 Standard Library
11.1 math
- math.pow
- math.log
12 Third party libraries
12.1 argparse
import argparse parser = argparse.ArgumentParser() parser.add_argument('-q', '--query', help='query github api', require=True) parser.add_argument('-d', '--download', help='do download', action='store_true') args = parser.parse_args()
12.2 urllib
from urllib import request import json url = 'https://api.github.com' api = '/search/repositories' query = 'language:C&stars:>10&per_page='+size response = request.urlopen(url+api+"?q="+query) s = response.read().decode('utf8') j = json.loads(s) # j will be a mix of list and dict
12.3 XML
import xml.etree.ElementTree as ET root = ET.fromstring(s) # XPath nodes = root.findall('{http://www.sdml.info/srcML/src}function') for node in nodes: # do with node pass
APIs
node.find(XPath)
node.findall(XPath)
node.get(Attribute)
node.text