python-basics
Overview
Here are some basics about python3 that you should know. if your code is written with python2, convert it to python3 with 2to3
tool.
1 | 2to3 python2_file |
You can also run your app with virtual env, so that different python applications can use different python(python2 or python3) libraries
1 | sudo pip3 install virtualenv |
.py, pyc, pyo
- .py: this is normal input source code that you’ve written.
- .pyc: this is the compiled bytecode. If you
import a module(python file)
, python will build a *.pyc file that contains the bytecode for importing to make it easier (and faster). pycache/lib.cpython-39.pyc - .pyo: this is a another form of *.pyc file that was created while optimizations (-O) was on.
When the Python interpreter is invoked with the -O flag, optimized code is generated and stored in ‘.pyo’ files.
.pyo is gone, never use it
A program doesn’t run faster when it is read from a ‘.pyc’ or ‘.pyo’ file than when it is read from a ‘.py’ file,the only thing that’s faster about '.pyc' or '.pyo' files is the speed with which they are loaded
.
When a script is run by giving its name on the command line, the bytecode for the script is never written to a '.pyc' or '.pyo' file automatically
. Thus, the startup time of a script may be reduced by moving most of its code to a module and having a small bootstrap script that imports that module.
1 | generate pyc manually(pyc is generated automatically for module when it's imported by others) |
generic methods for types
Each variable has a type, each type has some common methods and specific methods, here are generic rules you should know
methods for all types(str, list, tuple, range, dict, set)
dir(str)
to get methods of type(str) for help, or detail for a specific onehelp(str.index)
.item in s, item not in s, len(s), max/min(except dict, str), for item in s(s must be iterable)
NOTE:
len(str) DO NOT count '\0'
methods for sequence type(str, list, tuple, range)
- s[i], s[i:j](not include j), s[i:j:k], s + s1, s.count(x)
a, b, c = s (size of s must be 3)
call func(*s), pass each elem to func, like func(s[0], s[1], s[2])
- the first index of sequence is 0
you can’t declare var with explicit type, the type of var depends on its value, can be changed at runtime!!!
naming convention
python uses underscores to write multiword names
like get_name
, no capital letter.
Files
- python follows a convention where source
files are all lower case with underscore separating multiple words
, client_log.py - Compound file names are separated with
_
Functions and Methods
- private functions like this
_do_work()
- built-in function like this
__init__()
- If a name consists of multiple words, should write like this
get_name()
. - function names are case-sensitive (
car, Car and CAR
are three different variables).
Variables
- should not include the name of your type in the name of your variable’s name,
tet_list
- Generally, use relatively simple (short) name(lower case), (_ underscore for multiple worlds) long var.
- user to u
- user_id to uid
- server_listener
- lpcfg
- If variable type is bool, its name should start with
has, is, can or allow
, etc. - Single letter represents index: i, j, k
Constants
- Constant should be
capitalized all letters
. WORLD
class
- type of class
should be capitalized and camel case
Class Person(object): - private function(
_private_f()
) and built-in(__eq__()
) function can NOT be accessed!
import package
- package(is dir with init.py under it) name should be lowercase. like import xxx.testhello, xxx is package name
printing
Printing is an easy way to show result, there are several ways to print variables.
- print one line
1 | print("hello" |
- print multiple lines
1 | print("hello \n jason") |
- show one parameter at last position
1 | name = "jason" |
- show multiple parameters at different positions
1 | # position parameters |
- variable can be at any position
1 | # print add space between different parts!!! |
- print with string.format()
1 | print('{{ {0}'.format('hi')) |
- print with template which is less verbose than format() but need high python version
1 | # use var directly in template with {} |
Suggestion for python3 printing
- print(‘{}’.format(var))
- print(f”hello {name}”)
1 | name='jason' |
hi jason
hi 5
hi jason
hello world
hello world
hello world
hello world in one line
hello
world
hello
world
built-in APIS
Python(without library) provides many methods to make it easy to use. here is a list of that.
- Complex
1
2
3c1 = 4 + 3j
c2 = complex(4, 3)
c1*c2 - Built-in function
1
2
3
4
5
6
7
8pow(2, 3)
divmod(8, 4) # result: (2, 0)
abs(-12)
sum([1,2]) sum([False, True])
max([1, 2])
min([1,2])
round(3.23, 1) # return 3.2
round(3.26, 1) # return 3.3 - built-in modules
1
2
3
4
5
6
7
8import math
math.pi
math.sin()
math.cos()
math.pow()
math.log2()
math.ceil(2.1) == 3 # rounds up to close integer
math.floor(2.1) == 2 # rounds down to close integer - assert
1
2
3a = 1
assert a, 'bad value' # assert true, never raise exception.
assert 0, 'bad value' # assert fail, exception with msg 'bad value' - argv
1
2
3print(sys.argv) # argv is list that includes the app name and parameter
# ./app.py -f xx.text
# sys.argv = ['./app.py', '-f', 'xx.text']
constants
- Python doesn’t have built-in constant types.
- By convention, Python uses a variable whose name consist of capital letters to define a constant.
NOTE: someone can go and change the value of constant
, even it’s unlikely but possible.
1 | MY_CONSTANT = "Whatever" |
variable
A variable is a label or a name given to a certain location in memory. This location holds the value you want your program to remember for use later on. What’s great in Python is that you do not have to explicitly state what the type of variable you want to define is - it can be of any type (string, integer, float, list, dict etc.). To create a new variable in Python, you simply use the assignment operator (=, a single equals sign) and assign the desired value to it, its type is determined by its value, but if you change the value, the type can be changed as well.
1 | first_string_var = "First String" |
Local Scope
A variable created inside a function belongs to the local scope of that function, and can only be used inside that function.
1 | def print_number(): |
The first number defined is: 1
Enclosing Scope
Inner function can access var defined in outer function directly, while the reverse direction is not allowed.
1 | def outer(): |
first_num from outer: 1
second_num from inner: 2
nolocal keyword
The nonlocal keyword is useful in nested functions. It causes the variable to refer to the previously bound variable in the closest enclosing scope
. In other words, it will prevent the variable from trying to bind locally first,
1 | def outer(): |
inner - second_num is: 1
outer - first_num is: 0
Global Scope
A variable created in the main body of the Python code is a global variable and belongs to the global scope.
Global variables are available from any scope, global and local.
If you need to create a global variable, but are stuck in the local scope, you can use the global
keyword.
The global keyword makes the variable global which is defined in a function or refer to a predefined global variable
1 | def gb(new_greeting): |
1 | greeting = "Hello" |
Hello World
Hello Samuel
Global keyword
To change the value of a global variable inside a function, refer to the variable by using the global keyword
, it’s similar like nolocal
keyword.
1 | greeting = "Hello" |
Hi World
types
operators
Arithmetic operators
Operator | Meaning | Example |
---|---|---|
+ | Add two operands or unary plus | x + y+ 2 |
- | Subtract right operand from the left or unary minus | x - y- 2 |
* | Multiply two operands | x * y |
/ | Divide left operand by the right one (always results into float) | x / y |
% | Modulus - remainder of the division of left operand by the right | x % y (remainder of x/y) |
// | Floor division - division that results into whole number adjusted to the left in the number line | x // y |
** | Exponent - left operand raised to the power of right | x**y (x to the power y) |
Comparison operators
Operator | Meaning | Example |
---|---|---|
> | Greater than - True if left operand is greater than the right | x > y |
< | Less than - True if left operand is less than the right | x < y |
== | Equal to - True if both operands are equal | x == y |
!= | Not equal to - True if operands are not equal | x != y |
>= | Greater than or equal to - True if left operand is greater than or equal to the right | x >= y |
<= | Less than or equal to - True if left operand is less than or equal to the right | x <= y |
Logical operators
Operator | Meaning | Example |
---|---|---|
and | True if both the operands are true | x and y |
or | True if either of the operands is true | x or y |
not | True if operand is false (complements the operand) | not x |
Bitwise operators
Operator | Meaning | Example |
---|---|---|
& | Bitwise AND | x & y = 0 (0000 0000) |
Bitwise OR | ||
~ | Bitwise NOT | ~x = -11 (1111 0101) |
^ | Bitwise XOR | x ^ y = 14 (0000 1110) |
>> | Bitwise right shift | x >> 2 = 2 (0000 0010) |
<< | Bitwise left shift | x << 2 = 40 (0010 1000) |
Assignment operators
Operator | Example | Equivalent to |
---|---|---|
= | x = 5 | x = 5 |
+= | x += 5 | x = x + 5 |
-= | x -= 5 | x = x - 5 |
*= | x *= 5 | x = x * 5 |
/= | x /= 5 | x = x / 5 |
%= | x %= 5 | x = x % 5 |
//= | x //= 5 | x = x // 5 |
**= | x **= 5 | x = x ** 5 |
&= | x &= 5 | x = x & 5 |
= | x | |
^= | x ^= 5 | x = x ^ 5 |
>>= | x >>= 5 | x = x >> 5 |
<<= | x <<= 5 | x = x << 5 |
Membership operators
Operator | Meaning | Example |
---|---|---|
in | True if value/variable is found in the sequence | 5 in x |
not in | True if value/variable is not found in the sequence | 5 not in x |
NOTE: +, ==, != works for tuple, list, string (sequence type)as well.
Integer
Integer supports most operators like C language
but with less difference, here are the operators it supports.
- +, -, *, /, //
- **, %
- x or y (C ||), x and y (C &&), not x (C !)
- <, <=, >, >=, ==, !=
- x | y, x & y, x ^ y, x >> y, x << y
1 | def integer_demo(): |
1 | integer_demo() |
convert str to int int('12') = 12
convert int to string str(12) = 12
// only remains interger 5//1.5= 3.0
/ result is float 1/2=0.50 1/2=0.5000
1.23
1.23
2**3 = 8
8%4 = 0
string
string
is a kind of sequence, like list, tuple
, but its content can't be modified in place
, in order to change its content, you must create a new one.
no char type in python, that means ‘’ and “” has the same meaning
Create a string
- s = “hello”
- s = ‘hello’
- s = “hi” + “world”
s = r'hello\nworld' # raw literal string now \n is a normal char!!
Ops
- index from 0, last index -1
- len(str), no \0 is there but we count in C.
- count(), index(), isdigit(), islower(), lower(), isupper(), upper(), isspace(), join(), replace(), find()(first matched one), split(), splitlines(), strip(), startwith(), endwith(), rfind()(last matched one)
- join() each string element of iterable object, “-“.join([1,2]) will cause error as element is not string!!!
str.strip('hy')
will strip h or y both from right and left not ‘hy’ as a whole- index() and find() return same if found(index), otherwise,
exception ValueError for index, -1 returned for find()
- slicing [2:5], [2:], [:5], [2:-1] all with default step 1 from left to right
- slicing with steps, [2:5:2] ([start:end:step])
- [::-1](reverse the string)
str.xxx() all such methods do NOT support regular pattern
1 | def str_demo(): |
1 | str_demo() |
raw string r"a\nb" = a\nb
str='hello boy'
reverse s1 by s1[::-1]= yob olleh
count sub words, str.count('o') = 2
first element index 0, str[0] = h
last element index: str[-1] = y
not include \0 len(str) = 9
a:b means [a, b) str[:-1] = hello bo
can't change the content of a string by str[2] = 'a'
create a copy of str by str[:]!
str is: hello boy
s1.startswith("hello") = True
s1.endswith("bo") = False
str is lower
find hello at 0 in : hello boy
replace boy with girl, new str is: hello girl
splitlines() == split('\n'), split() will return a list, but s1 is unchanged s1 = hello boy s1.split(' ') = ['hello', 'boy']
strip() removes characters(whitespace by default)
from both left and right based on the argument set of character
while rstrip() only from right
before strip str = hello boy
after strip('hy') str = ello bo
join() join each string elem in an iterable object with character provided, '-''.join('hello') = h-e-l-l-o
'-'.join(['hello', 'boy'] = hello-boy
encoding and decoding
Python3’s str type is meant to represent human-readable text and can contain any Unicode character
.
The bytes type
, conversely, represents binary data or sequences of raw bytes
, that do not intrinsically have an encoding attached to it.
Python 3 is all-in on Unicode and UTF-8 specifically. Here is what that means:
Python 3 source code is assumed to be UTF-8 by default. This means that you don’t need # -- coding: UTF-8 -- at the top of .py files in Python 3.
All text
(str) is Unicode by default
. Encoded Unicode text is represented as binary data in memory (bytes). The str type can contain any literal Unicode character, such as “Δv / Δt”, all of which will be stored as Unicode.Python’s re module defaults to the re.UNICODE flag rather than re.ASCII. This means, for instance, that r”\w” matches Unicode word characters, not just ASCII letters.
The default encoding/decoding in
str.encode() and bytes.decode() is UTF-8.
1 | # The length of a single Unicode character as a Python str will always be 1 |
len of character: 1
encoded with utf-8: b'\xf0\x9f\xa4\xa8'
len of bytes: 4
list
List is a sequence, element can be any type even for one list. but for sort() method it requires same type of all elements
.
To create a list
- lv = list()
- lv = [], lv == [] True, len(lv)==0
- lv = [1, 2]
- lv = list(‘abc’) same as lv = [‘a’, ‘b’, ‘c’]
- lv = list(dt.items()), dt={‘a’:1} same as lv=[(‘a’, 1)]
- lv = list(range(3)) same as lv = [0, 1, 2]
- lv = [1, ‘a’, False, [3, 4]]
- lv = [1] * 3 same as [1, 1, 1]
- lv = old[:] # shadow copy, only the top level is copied
lv = [val+10 for val in arr if val >= 0]
Ops
append(value)
, count(value),extend(iterable)
, index(value, start=None, stop=None), insert(index, value), pop(index=None)(default from last),remove(value)
, reverse(), sort(key=None, reverse=False)- sort() needs all elements have the same type.
for i in range(len(lt)):lt[i]
for elem in lt: print(elem)
for i in range(len(lt) - 1, -1, -1):lt[i]
loop from last
Note
- reverse() and sort() are
in place methods
. - if you pass a list to a function, modification in that function of the list will take place in original.
pop() from last by default ----> pop(0) pop from head.
1 | import copy |
1 | list_demo() |
list element can be any type: ['1', 5, [3, 4], 2]
append only take one element, after list.append(6): ['1', 5, [3, 4], 2, 6]
after list.extend([3,4]) = ['1', 5, [3, 4], 2, 6, 3, 4]
after insert 10 at index 1, the previous index 1 move back, list.insert(1,10): ['1', 10, 5, [3, 4], 2, 6, 3, 4]
after pop() value at index 2, list=: ['1', 10, [3, 4], 2, 6, 3, 4]
after remove() element whose value is 2, list.remove(2) now list is: ['1', 10, [3, 4], 6, 3, 4]
[2, 1, 4] after sorted , now lt is %s [1, 2, 4]
list.reverse() after reverse now list is: [4, 2, 1]
with index (0, 4)
with index (1, 2)
with index (2, 1)
with index: 0 4
with index: 1 2
with index: 2 1
without index: 4
without index: 2
without index: 1
reverse loop:
2 1
1 2
0 4
shadow copy la: ['1', 2, [3, 4], 6], cla: ['1', 2, [3, 4], 6]
cla[1] += 10, now la: ['1', 2, [3, 4], 6]
cla[2].append(5), la changes as well la: ['1', 2, [3, 4, 5], 6]
************************************************************
deep copy la: ['1', 2, [3, 4], 6], dla: ['1', 2, [3, 4], 6]
dla[1] += 10, now la: ['1', 2, [3, 4], 6]
dla[2].append(5), la changes as well la: ['1', 2, [3, 4], 6]
pack/unpack list
unpack list to separate elements, while pack from separate elements to a list, this is mostly used for parameter passing.
1 | def list_unpack_pack(): |
1 2 3
(1, 2, 3)
dict
dict is not sequence type, but we can convert dict to a list
.
to create a dict
- dt = {}
- dt = dict()
- dt = {“a”:1, “b”:2}
- lt = [(‘a’, 1), (‘b’, 2)] dt = dict(lt)
key without '' or ""
, treated as variable if not literal must define it firstly
1 | # both are valid, but key 2 and '2' are different keys!!!! |
Ops
dt[newkey] = 12(add a new element)
dt[key] (exception if no key), dt.key NOT support it s only valid for class
dt.get(key, default=None)
# should use this always to avoid exceptiondt.pop(key, default=None) # get its value and pop it.
del dt[key] # only delete it.
dt.keys()
dt.values()
dt.items() # each element is a tuple
dt.update(another_dict) #
extend a dict or update existing elem
dt.copy() # shallow copy!!!
dt.clear() # reset dict
1 | def dict_demo(): |
1 | dict_demo() |
dict now is: {'a': 1, 'b': 2}
add dt['c'] = 3 now dt is: {'a': 1, 'b': 2, 'c': 3}
after added and modifed
dt['c'] += 1
dt['d'] = [1, 2]
dt['e'] = {"f":6}
now dict: {'a': 1, 'b': 2, 'c': 4, 'd': [1, 2], 'e': {'f': 6}}
access one element dt['e']['f'] = 6
get a its value with dt.get(): 1
get f its vlaue with dt.get(): doesn't exist
pop f from dict with dt.pop(): doesn't exist
now dic is: {'a': 1, 'b': 2, 'c': 4, 'd': [1, 2], 'e': {'f': 6}}
pop a from dict, dt.pop('a') now dict: {'b': 2, 'c': 4, 'd': [1, 2], 'e': {'f': 6}}
all keys in dict is dt.keys() = dict_keys(['b', 'c', 'd', 'e'])
all values in dict is dt.values() = dict_values([2, 4, [1, 2], {'f': 6}])
all items in dict is dt.items() = dict_items([('b', 2), ('c', 4), ('d', [1, 2]), ('e', {'f': 6})])
update dict with {"c": 100, "g": 100}, now dt = {'b': 2, 'c': 100, 'd': [1, 2], 'e': {'f': 6}, 'g': 100}
b == 2
c == 100
d == [1, 2]
e == {'f': 6}
g == 100
dt is {} after clear()
pack/unpack dict
unpack dict to separate elements, while pack from separate elements to a dict, this is only used for parameter passing, when unpack, the parameters must use the same ‘key’ as dict and same count of element.
1 | dt = {"a":1, "b":2} |
1 2
{'a': 1, 'b': 2, 'c': 3}
tuple
tuple is similar as list(element can be any type) except it can NOT be modified meaning its top level element can not be changed, but the embedded object can be modified
, tuple has no special methods for itself
. it’s less used actually.
Create a tuple
- tp = 1, 2
- tp = (1, 2)
- tp = tuple([1, 2])
Ops
- no special method for itself, has sequence type generic methods
1 | def tuple_demo(): |
1 | tuple_demo() |
tuple is: (1, 2, 'd', {'a': 1}, [3, 4])
tp[:-1]: (1, 2, 'd', {'a': 1})
tp + (6,): (1, 2, 'd', {'a': 1}, [3, 4], 6)
change the value it points tuple is: (1, 2, 'd', {'a': 2}, [3, 4])
set
Set is like dict without value
, only keys and it’s not sequence type but iterable
and has its special methods
NO duplicate element in set.
Create a set
- st = set() empty set, only one to create set not like list, tuple, dict
- st = set(“abc”) == st={‘a’, ‘b’, ‘c’}
- st = {‘a’, ‘b’, ‘c’}
- st = set([‘a’, ‘b’, ‘c’]) # from list
Ops
- s1.add()
- s1.remove()
- s1.update() #extend a set with another one
- s1 | s2 并集
- s1 & s2 交集
- s1 - s2 差集
- s1 ^ st2 对称差
- s1.issubset(s2) s1 is subnet of s2
- s2.issuperset(s1) s2 is subnet of s1
1 | def set_demo(): |
1 | set_demo() |
st = {'c', 'b', 'a'}
after st.add(3) = {3, 'c', 'b', 'a'}
after st.remove('a') = {3, 'c', 'b'}
3
c
b
range
When you call range() API, it returns an object of range type, but most of time, we convert range to list or tuple implicitly.
1 | def range_demo(): |
1 | range_demo() |
range is: range(0, 5)
convert range to list: [0, 1, 2, 3, 4]
(0, 1, 2, 3, 4)
0
1
2
3
4
[5, 4, 3, 2, 1, 0]
conversion between different types
1 | # string <--> integer |
function
variable scope is like C
, variable is local by default, if want to change value of global variable, must use keyword global x in function, you can access global variable in function without global keyword, but only for accessing, not modifying
.
variable defined in a function is also visible to the function embedded in it.
argument can have default value when define it
1 | def show(x, y=0): |
when you call function with named parameter, the order can be any
1 | show(1, 2) |
For dynamic args(the number of argument is not defined)
- use
*arg
for list like parameters in function definition **arg
for dict like parameters in function definition
1 | def test(*args): |
Note: >=python3.5, python supports define function with type
1 | def function_demo_python3_5(name: str='jason') -> bool: |
1 | # no global keyword when defines it. |
1 | function_demo() |
x in show_v is: 10
x in show_sub_v is: 10
g_y: 200
out of show_v x is: 12
out of show_v y is: 200
x=1, argc=(2, 3) argv={'name': 'jason', 'id': 12}
flow control
Flow control controls the logic of statement, like C, python supports many flow control directives like while/else, for/else, if/elif/else, pass, break/continue, try/except/finally, raise
NO goto, switch/case
in python.
if/elif/else
1 | def if_demo(): |
con is 1
like: a = 12 if False else 23
a = 23
say hi
say hi
while/else
1 | def while_demo(): |
loop is out but not by break statement inside while
for/else
1 | def for_demo(): |
equal
break from loop
1-2-3-4
try/exception
1 | try: |
system env
Sometimes, you may want to get environment from system or set an environ for a process, use from os import environ
note: environ[‘PATH’] is different with os.path which is only used for search .py
1 | def env_demo(): |
1 | env_demo() |
get HOST env: 10.64.32.1
env-> http_proxy : http://10.226.136.231:3128
env-> ftp_proxy : http://10.226.136.231:3128
env-> PATH : /home/data/Anaconda3/envs/py3.9/bin:/opt/llvm/bin:/home/data/Anaconda3/envs/py3.9/bin:/home/data/Anaconda3/condabin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/home/go:/home/go/bin:/root/.yarn_pkg/bin:/usr/lib64:/usr/local/go/bin:/home/data/Anaconda3/envs/py3.9/libexec/git-core:/root/bin:/root/.yarn_pkg/bin:/home/go/bin:/home/go:/usr/local/go/bin
env-> PWD : /
env-> LANG : en_US.UTF-8
env-> https_proxy : http://10.226.136.231:3128
env-> SHLVL : 1
env-> _ : /usr/bin/env
env-> GOPROXY : https://goproxy.cn,direct
env-> GO111MODULE : on
env-> GOMODCACHE : /home/go/pkg/mod
env-> GOCACHE : /root/.cache/go-build
env-> GOPATH : /home/go
env-> PYDEVD_USE_FRAME_EVAL : NO
env-> JPY_PARENT_PID : 1811
env-> TERM : xterm-color
env-> CLICOLOR : 1
env-> PAGER : cat
env-> GIT_PAGER : cat
env-> MPLBACKEND : module://matplotlib_inline.backend_inline
env-> HOST : 10.64.32.1
small tips
Id of object
In python, each object has a unique identifier(memory address), to get it by id(var)
, a is b
checks the id of them, for integer, string, if content is same, id is same as well, but this is not true for list, tuple, dict
. for example:
1 | a = 3 |
while isinstance(var, str)
to check if a var is an instance of a class
None () {} [] “”
None () {} [] “” are false when used a condition.
1 | print("""None, (), {}, [], "", '' all are false but they are different types""") |
None, (), {}, [], "", '' all are false but they are different types
False False False False False
None not equal []
exec eval
- exec is used to
execute python statements which are stored in a string or file
- eval is used to
evaluate valid python expression which are stored in a string
.
1 | # execute python code from string |
hello
6
try/except
1 | try: |
Error: Division by zero