Determining scope / context of a method call in python - 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.

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)

How to handle & return both properties AND functions missing in a Python class using the __getattr__ function?

It is fairly easy to use the __getattr__ special method on Python classes to handle either missing properties or functions, but seemingly not both at the same time.
Consider this example which handles any property requested which is not defined explicitly elsewhere in the class...
class Props:
def __getattr__(self, attr):
return 'some_new_value'
>>> p = Props()
>>> p.prop # Property get handled
'some_new_value'
>>> p.func('an_arg', kw='keyword') # Function call NOT handled
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: 'str' object is not callable
Next, consider this example which handles any function call not defined explicitly elsewhere in the class...
class Funcs:
def __getattr__(self, attr):
def fn(*args, **kwargs):
# Do something with the function name and any passed arguments or keywords
print attr
print args
print kwargs
return
return fn
>>> f = Funcs()
>>> f.prop # Property get NOT handled
<function fn at 0x10df23b90>
>>> f.func('an_arg', kw='keyword') # Function call handled
func
('an_arg',)
{'kw': 'keyword'}
The question is how to handle both types of missing attributes in the same __getattr__? How to detect if the attribute requested was in property notation or in method notation with parentheses and return either a value or a function respectively? Essentially I want to handle SOME missing property attributes AND SOME missing function attributes and then resort to default behavior for all the other cases.
Advice?
How to detect if the attribute requested was in property notation or in method notation with parentheses and return either a value or a function respectively?
You can't. You also can't tell whether a requested method is an instance, class, or static method, etc. All you can tell is that someone is trying to retrieve an attribute for read access. Nothing else is passed into the getattribute machinery, so nothing else is available to your code.
So, you need some out-of-band way to know whether to create a function or some other kind of value. This is actually pretty common—you may actually be proxying for some other object that does have a value/function distinction (think of ctypes or PyObjC), or you may have a naming convention, etc.
However, you could always return an object that can be used either way. For example, if your "default behavior" is to return attributes are integers, or functions that return an integer, you can return something like this:
class Integerizer(object):
def __init__(self, value):
self.value = value
def __int__(self):
return self.value
def __call__(self, *args, **kw):
return self.value
There is no way to detect how the returned attribute was intended to be used. Everything on python objects are attributes, including the methods:
>>> class Foo(object):
... def bar(self): print 'bar called'
... spam='eggs'
...
>>> Foo.bar
<unbound method Foo.bar>
>>> Foo.spam
'eggs'
Python first looks up the attribute (bar or spam), and if you meant to call it (added parenthesis) then Python invokes the callable after lookup up the attribute:
>>> foo = Foo()
>>> fbar = foo.bar
>>> fbar()
'bar called'
In the above code I separated the lookup of bar from calling bar.
Since there is no distinction, you cannot detect in __getattr__ what the returned attribute will be used for.
__getattr__ is called whenever normal attribute access fails; in the following example monty is defined on the class, so __getattr__ is not called; it is only called for bar.eric and bar.john:
>>> class Bar(object):
... monty = 'python'
... def __getattr__(self, name):
... print 'Attribute access for {0}'.format(name)
... if name == 'eric':
... return 'idle'
... raise AttributeError(name)
...
>>> bar = Bar()
>>> bar.monty
'python'
>>> bar.eric
Attribute access for eric
'idle'
>>> bar.john
Attribute access for john
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in __getattr__
AttributeError: john
Note that functions are not the only objects that you can invoke (call); any custom class that implements the __call__ method will do:
>>> class Baz(object):
... def __call__(self, name):
... print 'Baz sez: "Hello {0}!"'.format(name)
...
>>> baz = Baz()
>>> baz('John Cleese')
Baz sez: "Hello John Cleese!"
You could use that return objects from __getattr__ that can both be called and used as a value in different contexts.

Python Class Variable Initialization

I'd like to store some information about a class as class (static) variables. However, I can't figure out how these things get initialized. Here is a basic, dumb example:
class A(object):
clsVar = 'a'
#classmethod
def clsMeth(cls):
print 'changing clsVar'
cls.clsVar = 'b'
A.clsMeth()
# prints 'changing clsVar'
print A.clsVar # prints 'a'
A.clsVar = 'b'
print A.clsVar # prints 'b'
Since the function got called (as the print statement worked), why didn't the class variable stay changed? Do I have to use a metaclass if I don't want to do it after the class definition completes?
[Specifically, I want clsMeth to be a decorator and have the class variable be a list of all the functions that were so decorated. I'm guessing this isn't the right way to go about accomplishing that, so I've moved on, but I'm still curious.]
EDIT: As numerous people have pointed out, the code above won't run. I was running it in an IPython session where the call to A.clsMeth() would refer to a previous version of A and run. Such are the risks of using an interpreted language, I guess. I ended up going with something like this:
outsideDict = {}
def outsideDec(func):
outsideDict[func.__name__] = func
class A(object):
#outsideDec
def someMethod(self):
print 'ID %s' % id(self)
def otherMethod(self):
print 'other'
print outsideDict
one, two = A(), A()
outsideDict['someMethod'](one)
outsideDict['someMethod'](two)
Perhaps this should be another question, but when outsideDec gets run, is there a way to tell what class it's argument is a member of? Or is there a better way of doing introspection like this in Python? I recognize I'm veering off course here so I'll accept the answer below and do more research. Thanks everyone!
The call to A.clsMeth() in the definition of A will not run, as A does not exist at that point:
>>> class A(object):
... clsVar = 'a'
... #classmethod
... def clsMeth(cls):
... print 'changing clsVar'
... cls.clsVar = 'b'
... A.clsMeth()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in A
NameError: name 'A' is not defined
The code may have seemed to work if A had been defined previously (eg, if you were testing it out in the REPL), but the call to A.clsMeth would have been called on the old class, which would be shadowed by the new one.
However, we can definitely put that call after the definition and get the result you want:
>>> class A(object):
... clsVar = 'a'
... #classmethod
... def clsMeth(cls):
... print 'changing clsVar'
... cls.clsVar = 'b'
...
>>> A.clsMeth()
changing clsVar
>>> A.clsVar
'b'
Of course, as fabianhrj noted, you can put it in the constructor as well, but it won't be called until you create an instance.

Extending builtin classes in python

How can I extend a builtin class in python?
I would like to add a method to the str class.
I've done some searching but all I'm finding is older posts, I'm hoping someone knows of something newer.
Just subclass the type
>>> class X(str):
... def my_method(self):
... return int(self)
...
>>> s = X("Hi Mom")
>>> s.lower()
'hi mom'
>>> s.my_method()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in my_method
ValueError: invalid literal for int() with base 10: 'Hi Mom'
>>> z = X("271828")
>>> z.lower()
'271828'
>>> z.my_method()
271828
One way could be to use the "class reopening" concept (natively existing in Ruby) that can be implemented in Python using a class decorator.
An exemple is given in this page:
http://www.ianbicking.org/blog/2007/08/opening-python-classes.html
I quote:
I think with class decorators you could do this:
#extend(SomeClassThatAlreadyExists)
class SomeClassThatAlreadyExists:
def some_method(self, blahblahblah):
stuff
Implemented like this:
def extend(class_to_extend):
def decorator(extending_class):
class_to_extend.__dict__.update(extending_class.__dict__)
return class_to_extend
return decorator
Assuming that you can not change builtin classes.
To simulate a "class reopening" like Ruby in Python3 where __dict__ is an mappingproxy object and not dict object :
def open(cls):
def update(extension):
for k,v in extension.__dict__.items():
if k != '__dict__':
setattr(cls,k,v)
return cls
return update
class A(object):
def hello(self):
print('Hello!')
A().hello() #=> Hello!
#reopen class A
#open(A)
class A(object):
def hello(self):
print('New hello!')
def bye(self):
print('Bye bye')
A().hello() #=> New hello!
A().bye() #=> Bye bye
In Python2 I could also write a decorator function 'open' as well:
def open(cls):
def update(extension):
namespace = dict(cls.__dict__)
namespace.update(dict(extension.__dict__))
return type(cls.__name__,cls.__bases__,namespace)
return update

Categories