Implicitly call method when instance name is called - python

In an instance, is there a way I can call a method implicitly when I am calling just the instance name?
So for example if I have this
class MyClass:
def __init__(self, html):
self.html = html
def _render_html_(self):
# omitted
pass
>>> some_fancy_html = """(omitted)"""
>>> mc = MyClass(some_fancy_html)
## So instead of
>>> mc._render_html_()
## I would like to call
>>> mc
### to implicitly call the method _render_html()
Is that possible?
Background
In the Panda's source code I can see this in a docstring:
Notes
-----
Most styling will be done by passing style functions into
``Styler.apply`` or ``Styler.applymap``. Style functions should
return values with strings containing CSS ``'attr: value'`` that will
be applied to the indicated cells.
If using in the Jupyter notebook, Styler has defined a ``_repr_html_``
to automatically render itself. Otherwise call Styler.render to get
the generated HTML.
In the second paragraph it says:
Styler has defined a `_repr_html_` to automatically render itself
Source:
Github: Pandas

I don't think you can do that. I'd rather overload the parentheses operator, just like it's explained here.
>>> class MyClass:
... def __init__(self, html):
... self.html = html
... def __call__(self):
... print(self.html)
...
>>> mc = MyClass("Hello, world")
>>> mc
<__main__.MyClass instance at 0x7f3a27a29bd8>
>>> mc()
Hello, world

Instead of _render_html, call it __call__. This will be called by mc(). The step further than this - dropping the brackets in the calling code - is not possible, but you can come close if you make _render_html a property like so:
class MyClass:
#property
def html(self):
pass
Then you can do mc.html, without the brackets, to call that function.

You can try to assign this function to some variable:
mc = MyClass._render_html_(MyClass(some_fancy_html))
Then you when you call mc it will call class method.
Of course, you can always pass already existing class object as a self:
some_fancy_html = """(omitted)"""
mc = MyClass(some_fancy_html)
method = MyClass._render_html_(mc)
Then typing method will execute same what would do: mc._render_html_()

Related

Given a Python method, how to get its class?

Suppose I have this class:
class Foo():
def foo_method(self):
pass
Now suppose I have an object foo = Foo().
I can pass foo.foo_method around as argument to a function.
foo.foo_method.__qualname__ returns the string representing the method's "full name":
"Foo.foo_method".
What if I want to get Foo, the class itself, from foo.foo_method?
The solution I came up with is:
def method_class(method):
return eval(method.__qualname__.split(".")[0])
Is there a less "dirty" way of achieving this?
The instance that a bound method is bound to, is stored as the __self__ attribute. Thus:
class Foo:
def foo_method(self):
pass
foo = Foo()
assert foo.foo_method.__self__.__class__ is Foo
The following might do what you want:
##########################################################
class Klassy:
def methy(arg):
pass
insty = Klassy()
funky = insty.methy
##########################################################
insty_jr = funky.__self__
Klassy_jr = type(insty_jr)
print(Klassy_jr)

Python How to create method of class in runtime

I am curious how to create a custom method for a class at runtime...
I mean for example with name of method, name of parameters, body of method read from database and assign this method to a class or to an instance.
I have a found possibility to add method that is already written:
class A:
def __init__(self):
pass
def method(self):
return True
A.method = method
a = A()
print(a.method())
but I am interested in completely assembling a new method from scratch:
name = "method"
params = ["self"] # Params in list should be a strings
body = "return True"
# To create method from pieces
Is it possible using __dict__ ? Or how else this be done?
Methods are another attribute on the object that is the class. They can be added like other attributes:
Code:
class A:
def __init__(self):
pass
def method(self):
return True
def another_method(self):
return False
setattr(A, 'another_method', another_method)
Test Code:
a = A()
print(a.another_method())
Results:
False
Methods from a string:
Add if you really need to get your methods from a database or such you can use exec like:
method_string = """
def yet_another_method(self):
return type(self).__name__
"""
exec(method_string)
setattr(A, 'yet_another_method', yet_another_method)
a = A()
print(a.yet_another_method())
Results:
A
This answer has to be treated with care, using exec or eval can run arbitary code and may compromise your system. So if you rely on user-input to create the function you mustn't use this!!!
The warning aside you can simply create anything using exec:
exec("""
def method():
return True
""")
>>> method()
True
So what you basically need is just a way to get your requirements in there:
functionname = 'funfunc'
parameters = ['a', 'b']
body = 'return a + b'
exec("""
def {functionname}({parameters}):
{body}
""".format(
functionname=functionname,
parameters=', '.join(parameters),
body='\n'.join([' {line}'.format(line=line) for line in body.split('\n')])))
The body will be indented so that it's valid syntax and the parameter list will be joined using ,. And the test:
>>> funfunc(1, 2)
3
One of the best solutions that I have found is the following:
def import_code(code, name, add_to_sys_modules=0):
"""
Import dynamically generated code as a module. code is the
object containing the code (a string, a file handle or an
actual compiled code object, same types as accepted by an
exec statement). The name is the name to give to the module,
and the final argument says wheter to add it to sys.modules
or not. If it is added, a subsequent import statement using
name will return this module. If it is not added to sys.modules
import will try to load it in the normal fashion.
import foo
is equivalent to
foofile = open("/path/to/foo.py")
foo = importCode(foofile,"foo",1)
Returns a newly generated module.
"""
import sys,imp
module = imp.new_module(name)
exec(code,module.__dict__)
if add_to_sys_modules:
sys.modules[name] = module
return module
class A:
def __init__(self):
pass
name = "method"
params = ["self"] # Params in list should be a strings
body = "return True"
scratch = "def {0}({1}):\n\t{2}".format(name, ','.join(params), body)
new_module = import_code(scratch, "test")
A.method = new_module.method
a = A()
print(a.method())
Original function import_code by the following link http://code.activestate.com/recipes/82234-importing-a-dynamically-generated-module/
Using this solution I can dynamically create methods, load them in runtime and link to whatever I want object !!

Calling a method stored in object without also providing self in Python

If you have a class that can store a function, in my case used as a callback, and I want to call this function without having to also give self as a parameter how do I do that? As en example:
class foo:
def __init__(self, fun):
self.fun = fun
def call_fun(self):
self.fun()
Now, I would have expected this forces fun to look like:
def fun(foreign_self):
pass
since I expected object.fun() to be a shortcut for fun(object).
Edit: Updated the question to correctly reflect the situation.
Now, this forces fun to look like: def fun(foreign_self)
No, it does not.
fun doesn't have to accept anything:
class foo:
def __init__(self, fun):
self.fun = fun
def call_fun(self):
print(self.fun)
# <function fun at 0x02269588>
self.fun()
def fun():
print('in fun')
f = foo(fun)
f.fun()
# 'in fun'
f.call_fun()
# 'in fun'
print(f.call_fun)
# <bound method foo.call_fun of <__main__.foo object at 0x022239D0>>
Note that fun is a function while call_fun is an instance method. call_fun just happens to call the fun function by a reference that is kept within the instance.

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!!!

Using getattr function on self in python

I am trying to write call multiple functions through a loop using the getattr(...). Snippet below:
class cl1(module):
I =1
Name= 'name'+str(I)
Func= 'func'+str(I)
Namecall = gettattr(self,name)
Namecall = getattr(self,name)()
This is when get the following code: self.name1 = self.func1()
The desire is to loop multiple of these but the code is not working. Can you please advise?
Firstly, do use CapitalLetters for Classes and lowercase_letters for variables as it is easier to read for other Python programmers :)
Now, you don't need to use getattr() inside the class itself
Just do :
self.attribute
However, an example will be:
class Foo(object): # Class Foo inherits from 'object'
def __init__(self, a, b): # This is the initialize function. Add all arguments here
self.a = a # Setting attributes
self.b = b
def func(self):
print('Hello World!' + str(self.a) + str(self.b))
>>> new_object = Foo(a=1, b=2) # Creating a new 'Foo' object called 'new_object'
>>> getattr(new_object, 'a') # Getting the 'a' attribute from 'new_object'
1
However, an easier way would just be referencing the attribute directly
>>> new_object.a
1
>>> new_object.func()
Hello World!12
Or, by using getattr():
>>> getattr(new_object, 'func')()
Hello World!12
Although I explained the getattr() function,
I don't seem to understand what you want to achieve, do post a sample output.

Categories