Frames Scope and Python

Posted on September 2, 2022
Tags: codeetc

1 Meta-Classes

def chooseclass(name):
    class Foo(object):
        pass
    return Foo
theclass = chooseclass("asd")
theobj = theclass()
   Frame           Objects
Global Frame
chooseclass -----> function chooseclass(name)
theclass    -----> Foo class
theobj      -----> Foo instance

2 List and Ref

a = 1 # create int(1) literal, bind it to a in Global Frame
b = a # bind b to the same literal that a binds to
a = 2 # create int(2) literal, bind it to a in Global Frame
  Frame       Objects
Global Frame
   a  2
   b  1

The above code does not create any reference to any objects.

Python names work like pointers with automatic de/referencing but do not allow explicit pointer operations. Other targets represent indirections, which behave similar to pointers.

i = 5  # name `i` refers to object `5`
j = i  # ???
j = 3  # name `j` refers to object `3`
int three=3, five=5;  // objects
int *i, *j;           // names
i = &five;   // name `i` refers to position of object `5`
j = i;       // name `j` refers to referent of `i`
j = &three;  // name `j` refers to position of object `3`
i = [1,2,3]  # name `i` refers to object `[1, 2, 3]`
j = i        # name `j` refers to referent of `i`
i[0] = 5     # ???
typedef struct{
    int *elements[3];
} list;  // length 3 `list` type

int one = 1, two = 2, three = 3, five = 5;
list values = {&one, &two, &three};  // objects
list *i, *j;                         // names
i = &values;             // name `i` refers to object `[1, 2, 3]`
j = i;                   // name `j` refers to referent of `i`
i->elements[0] = &five;  // leading element of `i` refers to object `5`
import copy
def fib(n):
    if n == 0:
        return 1
    if n == 1:
        return 1
    else:
        return fib(n-2)+fib(n-1)
def dec(g):
    cnt = 0
    def wrapper(*argv):
        nonlocal cnt
        cnt = cnt + 1
        print(argv,cnt*"-", 'Decorated!')
        ans = g(*argv)
        cnt = cnt - 1
        print(cnt*"-",'rev')
        return(ans)
    
    return(wrapper)
    
def cov(f):
    e = copy.deepcopy(f)
    e = dec(e)
    return e
fib = cov(fib) really means
g = cov(fib)
fib = g

t(4)

Scoping + pyObject pointerlike behavior means we can post modify global scoped functions after wrapping them.

It is possible to design a hacking solution for a wrapper. Why must we do assignment in the global scope f=dec(f)? Because the globalscope is the scope that allows us full access to all the variable names aka pointers to our target function which is what we need access to, to redirect them to our wrapped function.

def fib(n):
    if n == 0:
        return 1
    if n == 1:
        return 1
    else:
        return fib(n-2)+fib(n-1)
def big(f):
    print(f.__name__)
    
    def dec(g):
        cnt = 0
        def wrapper(*argv):
            nonlocal cnt
            cnt = cnt + 1
            print(argv,cnt*"-", 'Decorated!')
            ans = g(*argv)
            cnt = cnt - 1
            print(cnt*"-",'rev')
            return(ans)

        return(wrapper)
    globals()[f.__name__]=dec(globals()[f.__name__])
    return 0

big(fib)
fib(5)