robturtle
7/6/2017 - 3:39 AM

python.md

What's Python

Intepreted (V.S compiling) programming language

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. const table [None, 3, 2]
  2. local variable table [1, NOT_INIT, NOT_INIT]
  3. local stack []
  4. PC (Program Counter: iterator, index)
  5. pointer to code
[] [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

Data structure of CPython

Everything in CPython is a reference, even primitive literals!

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]

Scoping

Only two scopes in Python2: local and global Additional scope in Python3: nonlocal

Rules:

  1. if there's an assignment of x in local, x is a local variable (including parameters)
  2. otherwise, x is in global
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.

object model

Everything is an object.

a class 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)

a function is an object

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

a primitive value is an object

(1).__class__ # => int
(-3).__abs__() # => 3

create objects using a class

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)

type system

built-in functions