Self Attributes Live in Function Pointer? - python

Suppose I have a simple python3 class like so:
class Test():
def __init__(self):
self.a = 'a'
def checkIsA(self, checkA):
return self.a == checkA
And some further code such as:
def tester(func, item):
return func(item)
testObject = Test()
print(tester(testObject.checkIsA, 'a')) # prints True
How is the function pointer(?) checkIsA still aware of its class member variables (defined by self) when used independently by another function?
I want to use this functionality in a program I'm writing but I'm worried I'm not understanding these semantics correctly.

testObject.checkIsA is what's called a bound method - it remembers the instance it was taken from so that its self attribute gets automatically populated by that instance.
You can easily check a difference between a class function (unbound method) and an instance method (bound method), Python will quite happily tell you all the details:
testObject = Test()
print(Test.checkIsA) # <function Test.checkIsA at 0x00000000041236A8>
print(testObject.checkIsA) # <bound method Test.checkIsA of
# <__main__.Test object at 0x0000000004109390>>
You can simulate a call to testObject.checkIsA() directly through the unbound Test.checkIsA function by passing your instance, too, e.g.:
def tester(func, instance, item):
return func(instance, item)
testObject = Test()
print(tester(Test.checkIsA, testObject, 'a')) # prints True
Or, with functools.partial:
import functools
def tester(func, item):
return func(item)
testObject = Test()
print(tester(functools.partial(Test.checkIsA, testObject), 'a')) # prints True
And that's exactly what a bound instance method does for you in the back by supplementing the first self attribute with its stored __self__ value. You can check that, too:
testObject = Test()
print(testObject.checkIsA.__self__ is testObject) # True

Related

Why is an object not created when a method is called during the object's contruction?

Given the class test, why it is not possible to instantiate it by calling one of its methods along with the constructor?
class test:
def __init__(self, a):
self.a = a
def print_a(self):
print(self.a)
Here is an example:
>>> obj = test("Hello").print_a() # Prints the desired output.
Hello
>>> obj
>>> print(obj) # But the object does not exist.
None
>>> obj = test("Hello") # It obviously works when doing it separately.
>>> obj
<__main__.test object at 0x7f537fea3940>
>>> obj.print_a()
Hello
Why is it not possible to chain a method call with the constructor call?
This was implemented in python3.
You are assigning obj to the return value of the function print_a (which is None as it has no return). The actual test object was never stored and is therefore no longer in scope when you try to print it.

How to retrieve arguments from a "fluid" decorated function

Suppose I have this decorator:
def decorator(f):
def f_wrap(*args):
for item in args:
print(args)
return f(*args)
return f_wrap
When used as "permanent" decorators with the # syntax, args retrieves the arguments of the wrapped function. For example, when used with the class below, I receive the instance of MyObject.
Class MyObject(object):
def __init__(self):
pass
#decorator
def function(self):
return
How can I achieve the same result using a "fluid" decorator. Or a decorator that is not permanently bound to the function it is decorating? For example:
def decorator(f):
def f_wrap(*args):
if (not args):
print("Nothing in args")
return f(*args)
return f_wrap
class MyClass(object):
def __init__(self):
pass
def function(self):
return
if __name__ == "__main__":
myobj = MyClass()
myobj.function = decorator(myobj.function)
myobj.function()
In this case, the args tuple always returns empty (I always get "Nothing in args"), even though I anticipated that it would return the instance variable myobj.
EDIT:
In case it was not clear from #AChampion's post the solution is to simply call the fluid-decoratored method as an "unbound" method. E.g.,
from types import MethodType
def decorator(f):
def f_wrap(*args):
# I replaced this with an iteration through
# args. It's a bit more demonstrative.
for item in args:
print(item)
return f(*args)
return f_wrap
class MyClass(object):
def __init__(self):
pass
def function(self):
return
if __name__ == "__main__":
myobj = MyClass()
myobj.function = MethodType(decorator(MyClass.function), myobj)
myobj.function()
The reason for the difference is that you are wrapping different things, a unbound method vs a bound method:
class MyObject(object):
#decorator
def function(self):
pass
Is equivalent to:
import types
class MyClass(object):
def function(self):
pass
m = MyClass(object)
m.function = types.MethodType(decorator(MyClass.function), m)
Not:
m.function = decorator(m.function)
The first being an unbound method, the second being a bound method.
You aren't using all properly. all returns a bool on whether all conditions are met inside what you are checking for in all. In your case, you aren't really doing anything. You will always evaluate to True with how you are using all.
I believe what you are looking for is simply this:
if not args:
Now, ultimately what this checks is if the method you are executing has *args. For the case of the function you have, you aren't passing any arguments, therefore, with the if not args check, you will actually get:
"Nothing in args"
However, if you add an argument to your method as such:
def function(self, x):
return
Then call: myobj.function(1)
You will not get "Nothing in args".
To answer your last question about not getting your instance. If you print out f using this method of calling your decorator:
myobj.function = decorator(myobj.function)
myobj.function()
You will get a bound method:
<bound method MyClass.function of <__main__.MyClass object at 0x102002390>>
Now, set up your decorator as such:
#decorator
def function(self):
return
You will see you get a function attached to your class object:
<function MyClass.function at 0x102001620>
Hence showing that they aren't doing the exact same thing you would expect. Hope this helps clarify a bit.

Change method definition

I want to change method definition of a class.
That is my case:
(I am importing these classes from another file)
class A(object):
def __init__(self, str):
self.str = str
def method_a(self):
print self.str
class B(object):
def __init__(self, str):
self.a = A(str)
def method_b(self):
self.a.method_a()
#######################################
from module import A, B
def main():
b = B('hello')
def my_method_a(self):
print self.str + 'other definition'
b.a.method_a = my_method_a
b.method_b()
if __name__ == '__main__':
main()
When I try to execute it, I get:
my_method_a() takes exactly 1 argument (0 given)
Because it does not get 'self'.
Any help please.
If you were to run type(b.a.method_a) before patching the method, you would see <type 'instancemethod'>. Running the same code after the patch produces <type 'function'>. In order for a function to work properly as a method, it must be an attribute of the class, not an instance of the class. The following would work, as you are manually invoking the magic that produces a method from a function:
b.a.method_a = my_method_a.__get__(b.a, A)
See https://wiki.python.org/moin/FromFunctionToMethod for more information.
The difference is that when you call b.a.method_a() after the patch, method_a is an attribute of the instance b.a, not of the class A. As a result, the function's __get__ method is never called to produce an instancemethod object which already has b.a bound to the first argument of method_a.
From one perspective, b.a.method_a() is identical to A.method_a(b.a). How does Python make that transition? You need to understand the descriptor protocol. All function objects implement the __get__ method to return an instancemethod object, which you can think of as the original function with the first argument bound to the appropriate object. Consider this code:
b = B()
b.a.method_a()
Does b have an attribute called a? Yes; we set it in B.__init__.
Does b.a have an attribute method_a? No.
Does type(b.a) (that is, A) have an attribute method_a? Yes.
Call A.method_a.__get__(b.a, A), since method_a was looked up for an instance. The result is an instance method object, with its first argument bound to b.a. (This is why you can consider b.a.method_a() identical to A.method_a(b.a)).
Call the resulting instance method with zero arguments.
Now consider this code.
b = B()
b.a.method_a = my_method_a
b.a.method_a()
Does b have an attribute called a? Yes; we set it in B.__init__.
Does b.a have an attribute method_a? Yes. We set it just before we tried to call it.
Since b.a.method_a was an instance lookup, not a class lookup, the descriptor protocol is not invoked and b.a.method_a.__get__ is not called, even though my_method_a has a __get__ function just like every other function.
Call b.a.method_a with zero arguments.
This produces the error, since the function expects one argument.
why not just use inheritance and method overrides:
from module import A, B
class myA(A):
def method_a(self):
print self.str + ' other definition'
class myB(B):
def __init__(self, str):
self.a = myA(str)
def main():
b = myB('hello')
b.method_b()
if __name__ == '__main__':
main()

Python: How to fix, if a static class variable gets a different function reference pointer?

I wonder why my class calls the referenced function (assigned to a static class variable) with with an argument. If I assign the function reference to a normal class variable it works like expected.
Here my example code:
# This function is not editable, because it's imported from an API
def getStuff():
print "I do my stuff!!!"
class foo(object):
GET_STUFF = getStuff
def __init__(self):
print "static var: ",self.GET_STUFF
self.GET_STUFF()
print "outer func: ",getStuff
foo()
This comes up with the following error:
outer func: <function getStuff at 0x0000000003219908>
static var: <bound method foo.getStuff of <__main__.foo object at 0x00000000030AB358>>
Traceback (most recent call last):
File "C:/example.py", line 13, in <module>
foo()
File "C:/example.py", line 10, in __init__
self.GET_STUFF()
TypeError: getStuff() takes no arguments (1 given)
To fix this issue I point the function reference inside the constructor to the class variable:
class foo(object):
def __init__(self):
self.GET_STUFF = getStuff
print "static var: ",self.GET_STUFF
self.GET_STUFF()
The result is like expected and works fine:
outer func: <function getStuff at 0x000000000331F908>
static var: <function getStuff at 0x000000000331F908>
I do my stuff!!!
But:
I wanted to use a static class variable, because it makes it easy to read and simple to setup for different API's. So in the end I would come up with some wrapper classes like in the following:
from API01 import getStuff01
from API02 import getStuff02
# bar calculates stuff object from the API (it calls GET_STUFF)
# and stores the object into self.stuff
import bar
class foo01(bar):
GET_STUFF = getStuff01
def DoSomething(self, volume):
self.stuff.volume = volume
class foo02(bar):
GET_STUFF = getStuff02
def DoSomething(self, volume):
self.stuff.volume = volume
# [...] and so on..
Is there a way to bring it to work in the way I want to setup my wrapper classes, or do I really have to define a constructor for each wrapper class?
Thanks
The reason for the error is that
self.GET_STUFF()
actually means
tmp = getattr(self, 'GET_STUFF')
tmp(self)
That means these two classes are equivalent:
def foo(self): pass
class Foo(object):
a = foo
class Bar(object):
def a(self): pass
In both cases, a function object is added to the class as a member and that means for Python that the function wants self as the first parameter.
To achieve what you want:
from API01 import getStuff01
def wrapper01(self):
getStuff01()
class foo01(object):
GET_STUFF = wrapper01
Just for extend Aaron answer, if you want to have static methods you can use the #staticmethod decorator:
class Calc:
#staticmethod
def sum(x, y):
return x + y
print (Calc.sum(3,4))
>>> 7
I thought already that my object is calling the referenced function with itself as argument. After a bit of research I finally found a solution. When I use a class variable to point to a function it will not referencing a direct pointer. It references the function as a bounced method of it's class. To get rid of the default call of calling a method with getattr, the call function of getattr for the class itself has to be overwritten (in this case the class bar, because foo (the wrapper classes) inherits the functionalities of bar:
import inspect
class bar(object):
GET_STUFF = None
def __getattribute__(self, name):
attr = object.__getattribute__(self,name)
if name == "GET_STUFF":
# Check: is method and is bounced?
if inspect.ismethod(attr) and attr.im_self is not None:
return attr.__func__
return attr
getattr of bar is now pointing to the original function reference, but only for the class variable GET_STUFF, because I want to leave the default functionality for the rest of my variables.
So, when I now execute the following:
class foo(bar):
GET_STUFF = getStuff
def __init__(self):
print "inner func: ",self.GET_STUFF
self.GET_STUFF()
foo()
I get the expected result and can write my wrappers without producing additional code for each module with those wrapper classes:
outer func: <function getStuff at 0x00000000034259E8>
inner func: <function getStuff at 0x00000000034259E8>
I do my stuff!!!

Is possible to create a non-existent method when it is called in Python?

If I have this class:
class MyClass(object):
pass
And then I do it:
instance = MyClass()
instance.new_method()
I got an AttributeError Exception, but I want to create this method dinamically and return an especifc value. Is it possible?
Firstly Python checks if attribute with such name exists, if yes, it will call it. There's no clear way to prematurely detect whether this attribute will be called or not.
Here's the tricky way to achieve what you want:
class Dispatcher(object):
def __init__(self, caller, name):
self.name = name
self.caller = caller
def __call__(self, *a, **ka):
print('Call on Dispatcher registered!',
'Will create method on',
self.caller.__class__.__name__,
'now.')
setattr(self.caller, self.name, self.mock)
return getattr(self.caller, self.name)(*a, **ka)
#classmethod
def mock(cls, *a, **ka):
return 'Some default value for newly created methods.'
class MyClass(object):
def __getattr__(self, attr):
return Dispatcher(self, attr)
instance = MyClass()
print(instance.new_method, '\n')
print(instance.new_method(), '\n')
print(instance.new_method(), '\n')
print(instance.other_method)
Output:
<__main__.Dispatcher object at 0x0000000002C07DD8>
Call on Dispatcher registered! Will create method on MyClass now.
Some default value for newly created methods.
Some default value for newly created methods.
<__main__.Dispatcher object at 0x0000000002C07DD8>
Although this solution is comprehensive, it will return the new instance of Dispatcher every time you try to access non-existent attribute.
If Dispatcher instance is called (e.g Dispatcher(self, attr)()), it will set mock as a new method named attr to the object, passed as the first argument to the constructor.
Yes, you can do it as:
class MyClass(object):
pass
def some_method():
pass
name = 'new_method'
setattr(MyClass, name, classmethod(some_method))
It is possible.
>>> class MyClass(object):
pass
>>> instance = MyClass()
>>> def new_method(cls, x):
print x
>>> MyClass.new_method = new_method
>>> instance.new_method(45)
45
Note that the new_method has cls as the first parameter which (the instance) is passed implicitly when called as an instance method.

Categories