Change what dictionary serves as a function's global scope - python

I want to make an #pure decorator for Python, part of this is being able to selectively disallow access to the global scope of the function.
Is there a way to programmatically change which dictionary thing serves as a function's global/external scope?
So for instance in the following I want to be able to intercept the access to f in h and throw an error, but I want to allow access to g because it's a pure function.
def f():
print("Non-pure function")
#pure
def g(i):
return i + 1
#pure
def h(i):
f()
return g(i)

You would have to create a new function object from the old one:
newfunc = type(h)(h.__code__, cleaned_globals, h.__name__, h.__defaults__, h.__closure__)
Here, cleaned_globals is a dictionary that is to be used as the global namespace for the newly created function object. All other arguments echo the original function's.
cleaned_globals could be based on a copy of h.__globals__, of course.
Demo:
>>> def h(i):
... f()
... return g(i)
...
>>> def g(i):
... return i + 1
...
>>> def f():
... print("Non-pure function")
...
>>> h(1)
Non-pure function
2
>>> cleaned_globals = {'g': g}
>>> newfunc = type(h)(h.__code__, cleaned_globals, h.__name__, h.__defaults__, h.__closure__)
>>> newfunc(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in h
NameError: global name 'f' is not defined
>>> cleaned_globals['f'] = lambda: print('Injected function')
>>> newfunc(1)
Injected function
2

Related

printing variable inside a def, inside a class

I am new to object oriented programming, what I want to do basically is print a variable inside a def which is in its turn inside a class, I think there's probably a very simple answer but I just can't figure it out, thanks for the assistance, here's my code:
class test():
def test2():
x = 12
print(test.test2.x)
this gives me the following error:
Traceback (most recent call last):
File "/home/vandeventer/x.py", line 4, in <module>
print(test.test2.x)
AttributeError: 'function' object has no attribute 'x'
when I try:
class test():
def test2():
x = 12
print(test.x)
I get:
Traceback (most recent call last):
File "/home/vandeventer/x.py", line 4, in <module>
print(test.x)
AttributeError: type object 'test' has no attribute 'x'
You can't do what you want; local variables only exist during the lifetime of a function call. They are not attributes of the function nor are they available outside of the call in any other way. They are created when you call the function, destroyed again when the function exits.
You can set attributes on function objects, but those are independent of locals:
>>> class test():
... def test2():
... pass
... test2.x = 12
...
>>> test.test2.x
12
If you need to keep a value a function produced, either return the value, or assign it to something that lasts longer than the function. Attributes on the instance are a common place to keep things:
>>> class Foo():
... def bar(self):
... self.x = 12
...
>>> f = Foo()
>>> f.bar()
>>> f.x
12
If you want to print that value you could also use a return statement and the self parameter.
class test():
def test2(self):
x = 12
return x
test = test()
print(test.test2())
I do not know if this fully answers your questions but it is a way to print your x.

Can a function in python behave like a class?

In python a function is a first class object. A class can be called. So you can replace a function with a class. But can you make a function behave like a class? Can you add and remove attributes or call inner functions( then called methods) in a function?
I found a way to do this via code inspection.
import inspect
class AddOne(object):
"""class definition"""
def __init__(self, num):
self.num = num
def getResult(self):
"""
class method
"""
def addOneFunc(num):
"inner function"
return num + 1
return addOneFunc(self.num);
if __name__ == '__main__':
two = AddOne(1);
two_src = '\n'.join([line[4:] for line in inspect.getsource(AddOne.getResult).split('\n')])
one_src = '\n'.join([line[4:] for line in two_src.split('\n')
if line[:4] == ' ' and line[4:8] == ' ' or line[4:8] == 'def '])
one_co = compile(one_src, '<string>', 'exec')
exec one_co
print addOneFunc(5)
print addOneFunc.__doc__
But is there a way to access the local variables and functions defined in a class in a more direct way?
EDIT
The question is about how to access the inner structure of python to get a better understanding. Of course I wouldn't do this in normal programming. The question arose when we had a discussion about private variables in python. My opinion was this to be against the philosophy of the language. So someone came up with the example above. At the moment it seems he is right. You cannot access the function inside a function without the inspect module, rendering this function private. With co_varnames we are awfully close because we already have the name of the function. But where is the namespace dictionary to hold the name. If you try to use
getResult.__dict__
it is empty. What I like to have is an answer from python like
function addOneFunc at <0xXXXXXXXXX>
You can consider a function to be an instance of a class that only implements __call__, i.e.
def foo(bar):
return bar
is roughly equivalent to
class Foo(object):
def __call__(self, bar):
return bar
foo = Foo()
Function instances have a __dict__ attribute, so you can freely add new attributes to them.
Adding an attribute to a function can be used, for example, to implement a memoization decorator, which caches previous calls to a function:
def memo(f):
#functools.wraps(f)
def func(*args):
if args not in func.cache: # access attribute
func.cache[args] = f(*args)
return func.cache[args]
func.cache = {} # add attribute
return func
Note that this attribute can also be accessed inside the function, although it can't be defined until after the function.
You could therefore do something like:
>>> def foo(baz):
def multiply(x, n):
return x * n
return multiply(foo.bar(baz), foo.n)
>>> def bar(baz):
return baz
>>> foo.bar = bar
>>> foo.n = 2
>>> foo('baz')
'bazbaz'
>>> foo.bar = len
>>> foo('baz')
6
(although it's possible that nobody would thank you for it!)
Note, however, that multiply, which was not made an attribute of foo, is not accessible from outside the function:
>>> foo.multiply(1, 2)
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
foo.multiply(1, 2)
AttributeError: 'function' object has no attribute 'multiply'
The other question addresses exactly what you're trying to do:
>>> import inspect
>>> import new
>>> class AddOne(object):
"""Class definition."""
def __init__(self, num):
self.num = num
def getResult(self):
"""Class method."""
def addOneFunc(num):
"inner function"
return num + 1
return addOneFunc(self.num)
>>> two = AddOne(1)
>>> for c in two.getResult.func_code.co_consts:
if inspect.iscode(c):
print new.function(c, globals())
<function addOneFunc at 0x0321E930>
Not sure if the following is what you're thinking about, but you can do this:
>>> def f(x):
... print(x)
...
>>> f.a = 1
>>> f.a
1
>>> f(54)
54
>>> f.a = f
>>> f
<function f at 0x7fb03579b320>
>>> f.a
<function f at 0x7fb03579b320>
>>> f.a(2)
2
So you can assign attributes to a function, and those attributes can be variables or functions (note that f.a = f was chosen for simplicity; you can assign f.a to any function of course).
If you want to access the local variables inside the function, I think then it's more difficult, and you may indeed need to revert to introspection. The example below uses the func_code attribute:
>>> def f(x):
... a = 1
... return x * a
...
>>> f.func_code.co_nlocals
2
>>> f.func_code.co_varnames
('x', 'a')
>>> f.func_code.co_consts
(None, 1)

Determining scope / context of a method call in python

I would like to write a decorator for a python class method that can determine if the method was called from a public context or private context. For example, given the following code
def public_check_decorator(f):
def wrapper(self):
if self.f is `called publicly`: # <-- how do I make this line work correctly?
print 'called publicly'
else:
print 'called privately'
return f(self)
return wrapper
class C(object):
#public_check_decorator
def public_method(self):
pass
def calls_public_method(self):
self.public_method()
runtime execution would ideally look something like this:
>>> c = C()
>>> c.public_method()
called publicly
>>> c.calls_public_method()
called privately
Is there any way to do this in python? That is, alter the line
if self.f is `called publicly`: # <-- how do I make this line work correctly?
to give the desired output?
Given the name of the package decides whether a function is being called from a private context or public one:
import inspect
import re
def run():
package_name = '/my_package/'
p = re.match(r'^.*' + package_name, inspect.stack()[0].filename).group()
is_private_call = any(re.match(p, frame.filename) is not None for frame in inspect.stack()[1:])
print(is_private_call)
Try running from within the package and then from outside the package!!!
see inspect.stack()
Some of this seems like trying to swim against the current of "python". Is that appropriate?
Do you know about the double-unscore standard? It makes methods "more private":
>>> class C(object):
... def __hide_me(self):
... return 11
... def public(self):
... return self.__hide_me()
...
>>> c = C()
>>> c.__hide_me()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'C' object has no attribute '__hide_me'
>>> c.public()
11
>>> c._C__hide_me()
11
>>>
Is that private enough? And using this technique is pythonic.

Python: Why do an unbound method with two params behave other than a class method?

In this piece of code:
def fa(a,b):
print a
print b
print " fa called"
class A:
#classmethod
def fa(a,b):
print a
print b
print " A.fa called"
class B:
def __init__(s,a):
s.a = a
obj1 = B(A.fa)
obj1.a("xxxx")
obj2 = B(fa)
obj2.a("xxxx")
Output:
__main__.A
xxxx
A.fa called
Traceback (most recent call last):
File "test.py", line 20, in <module>
obj2.a("xxxx")
TypeError: fa() takes exactly 2 arguments (1 given)
Why is the free method "fa" not receiving the "self" as a first parameter? The bound method A.fa behaves as expected.
The bound method A.fa receives A as the first parameter because it is a class method of A. No matter how you call this function it will always receive A as the first parameter.
The free method fa is not bound, so the only arguments it will receive are the ones that are passed in. No matter how you call this function, it will never receive parameters other than the ones that are passed in.
This behavior is different from a language like JavaScript, where how the method is called determines the context. In Python the implicit argument passing (similar to JavaScript context) is determined at the function definition time, and that binding or lack thereof will always be used for that function regardless of how it is called.
If you want to dynamically bind a free method you can do this using types.MethodType, for example:
def fa(x):
print x
class B: pass
>>> obj1 = B()
>>> obj1.a = MethodType(fa, obj1)
>>> obj1.a() # obj1.a behaves like an instance method bound to obj1
<__main__.B instance at 0x7f0589baf170>
>>> obj1.a2 = MethodType(fa, B)
>>> obj1.a2() # obj1.a2 acts like a class method bound to B
__main__.B
Because doing obj2.a = fa does not make a (fa) a method of obj2:
>>> class A(object):
... def meth(self, x, y):
... print x, y
...
>>>
>>> a = A()
>>>
>>> a.meth
<bound method A.meth of <__main__.A object at 0x10e281950>> # Method
>>>
>>> def fn(x, y):
... print x, y
...
>>>
>>> fn
<function fn at 0x10e287140>
>>> a.fn = fn
>>>
>>> a.fn
<function fn at 0x10e287140> # Not a method, still a function

Python: how to dynamically set function closure environment

I want to declare a function dynamically and I want to wrap any access to global variables OR alternatively define which variables are free and wrap any access to free variables.
I'm playing around with code like this:
class D:
def __init__(self):
self.d = {}
def __getitem__(self, k):
print "D get", k
return self.d[k]
def __setitem__(self, k, v):
print "D set", k, v
self.d[k] = v
def __getattr__(self, k):
print "D attr", k
raise AttributeError
globalsDict = D()
src = "def foo(): print x"
compiled = compile(src, "<foo>", "exec")
exec compiled in {}, globalsDict
f = globalsDict["foo"]
print(f)
f()
This produces the output:
D set foo <function foo at 0x10f47b758>
D get foo
<function foo at 0x10f47b758>
Traceback (most recent call last):
File "test_eval.py", line 40, in <module>
f()
File "<foo>", line 1, in foo
NameError: global name 'x' is not defined
What I want is somehow catch the access to x with my dict-like wrapper D. How can I do that?
I don't want to predefine all global variables (in this case x) because I want to be able to load them lazily.
What you're looking for is object proxying.
Here is a recipe for an object proxy which supports pre- and post- call hooks:
http://code.activestate.com/recipes/366254-generic-proxy-object-with-beforeafter-method-hooks/
Create a subclass that doesn't actually load the object until the first time the _pre hook is called. Anything accessing the object will cause the real object to be loaded, and all calls will appear to be handled directly by the real object.
Try this out
class GlobalDict(object):
def __init__(self, **kwargs):
self.d = kwargs
def __getitem__(self, key):
print 'getting', key
return self.d[key]
def __setitem__(self, key, value):
print 'setting', key, 'to', value
if hasattr(value, '__globals__'):
value.__globals__.update(self.d)
self.d[key] = value
for v in self.d.values():
if v is not value:
if hasattr(v, '__globals__'):
v.__globals__.update(self.d)
def __delitem__(self, key):
print 'deling', key
del self.d[key]
for v in self.d.values():
if hasattr(v, '__globals__'):
del v.__globals__[key]
>>> gd = GlobalDict()
>>> src = 'def foo(): print x'
>>> compiled = compile(src, '<foo>', 'exec')
>>> exec compiled in {}, gd
setting foo to <function foo at 0x102223b18>
>>> f = gd['foo']
getting foo
>>> f
<function foo at 0x102223b18>
>>> f() # This one will throw an error
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<foo>", line 1, in foo
NameError: global name 'x' is not defined
>>> gd['x'] = 1
setting x to 1
>>> f()
1
>>> del gd['x'] # removes 'x' from the globals of anything in gd
>>> f() # Will now fail again
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<foo>", line 1, in foo
NameError: global name 'x' is not defined

Categories