compile: form1 -> form2
source code (text) executable (machine code for machines, bytecode for virtual machines)
def foo(a):
b = 2
c = 3
return a + b * c
foo(1)
from dis import dis
dis(foo)
# => '''
2 0 LOAD_CONST 1 (2)
3 STORE_FAST 1 (b)
3 6 LOAD_CONST 2 (3)
9 STORE_FAST 2 (c)
4 12 LOAD_FAST 0 (a)
15 LOAD_FAST 1 (b)
18 LOAD_FAST 2 (c)
21 BINARY_MULTIPLY
22 BINARY_ADD
23 RETURN_VALUE
'''
function:
[] [1, NOT_INIT, NOT_INIT]
[2] [1, NOT_INIT, NOT_INIT]
[] [1, 2, NOT_INIT]
...
[] [1,2,3]
[1]
[1,3]
[1,3,2]
[1,6]
[7]
return
CPython (V.S. Jython, pypy, ...) is stack-based.
Call stacks
What is a primitive type?
The smallest indivisible data unit (e.g. int, float, char)
What are literals?
Their values are as same as the source code representations. (e.g. int x = 3, String s = "hello")
Common data structures in CPython:
typedef struct {
int type;
void *data;
} py_data_t;
a = 1000
b = 1000
a = 1001
def plus(a):
a = a + 1
plus(a)
l = [1000, 1001]
def plus(l):
l[0] += 1
// somewhere in initialization *((int*)0x1234abcd) = 1000
// *((int*)0xaaaabbbb) = 1001
py_data_t a { .type = INT_TYPE, .data = 0x1234abcd };
py_data_t b { .type = INT_TYPE, .data = 0x1234abcd };
a.data = 0xaaaabbbb;
// plus(a)
local_a = py_data_t;
local_a.type = a.type;
local_a.data = a.data;
local_a.data = 0xaaaabbbb;
// end of plus(a) // local_a is been destroyed
py_data_t l { .type = LIST_TYPE, .data = 0xccccdddd };
// 0xccccdddd = [0x1234abcd, 0xaaaabbbb]
l.data[0] = 0xaaaabbbb
// 0xccccdddd = [0xaaaabbbb, 0xaaaabbbb]
Only two scopes in Python2: local and global Additional scope in Python3: nonlocal
Rules:
x = 1
y = 2
def foo():
print(x) # ERROR!
x = 3
print(x)
print(y)
Since x is regarded as local, you can't use x before initialization.
Everything is an object.
class C:
x = 1
# roughly equivalent to:
'''
_classobj = createClass(block='x = 1\n')
C = _classobj
'''
# C is nothing more but a normal variable
T = C
print(T.x)
def foo():
return 1
# roughly equivalent to
'''
_funcobj = createFunction(block='return 1\n')
foo = _funcobj
'''
# foo is nothing more but a normal variable
bar = foo
bar() # => 1
(1).__class__ # => int
(-3).__abs__() # => 3
class Point:
def __init__(newobj, x, y):
newobj.x = x
newobj.y = y
p = Point(1,2)
# is roughly equivalent to:
def instantiate(clz, *args, **kargs):
newobj = clz.__new__(clz)
if hasattr(clz, '__init__'):
clz.__init__(newobj, *args, **kargs)
return newobj
p = instantiate(Point, 1, 2)