How to replace __str__ for a function - python

I want to change the string representation of a python function to be just the function name.
Eg for some function
def blah(x):
...
str(blah) currently gives
<function blah at 0x10127b578>
So I replace __str__ like this:
blah.__str__=lambda: 'blah'
but it doesn't get called by str(blah).
Is it possible to change __str__ for a function?

Replacing __str__ like that never actually works on any type of object. The builtin function type isn't special:
>>> class Foo(object):
pass
>>> f = Foo()
>>> f.__str__ = lambda: 'f'
>>> str(f)
'<__main__.Foo object at 0x0000000002D13F28>'
>>> f.__str__()
'f'
The str builtin doesn't lookup __str__ via the usual lookup protocol, it skips straight to looking at the class of its argument. So you can't "override" the __str__ method on an individual object; you have to set it on a class to apply to all objects of that class.1
But then again, the builtin function type isn't special. You can make a class that behaves mostly like a function, and use that instead:
class Function(object):
def __init__(self, raw_function):
self.raw_function = raw_function
def __call__(self, *args, **kwargs):
return self.raw_function(*args, **kwargs)
def __str__(self):
return self.raw_function.__name__
The __call__ method means you can call objects of this class exactly as if they were functions. This one just passes whatever arguments it receives straight through to the underlying raw function and returns whatever it returns (or throws whatever exceptions it throws). And since this class takes a single function as an argument, it also fits the pattern for a decorator:
#Function
def blah(x):
return x + 1
With that:
>>> blah
<__main__.Function object at 0x0000000002D13EB8>
>>> str(blah)
'blah'
>>> blah(33)
34
1 The builtin function type is special in some regards (I lied), one of which being that you can't assign to its attributes (that's the attributes of the class itself, not the attributes of any particular function object). So before you think maybe it would be great if you could monkeypatch the builtin function type so that str worked the way you want on all functions, that doesn't work. It's probably for the best; modifying things as global and fundamental as the builtin function type would be a great way to invent some really bizarre bugs.

As Joran said:
class NamedFunction:
def __init__(self, name, f):
self.f = f
self.name = name
def __call__(self, *args, **kwargs):
return self.f(*args, **kwargs)
def __str__(self):
return self.name
f = NamedFunction("lambda: 'blah'", lambda: 'blah')
print(f())
print(f)

class FNMagic:
def __init__(self,fn,fn_name):
self.fn = fn
self.fn_name = fn_name
def __call__(self,*args,**kwargs):
return self.fn(*args,**kwargs)
def __str__(self):
return self.fn_name
def blah(x):
return x
blah = FNMagic(blah,"blah!")
print blah
you could make a simple decorator
class NamedFn:
def __init__(self,name):
self.fn_name = name
def __call__(self,fn):
return FNMagic(fn,self.fn_name)
#NamedFn("some_name!!!")
def blah2(x,y):
return x*y
print blah2

As noted already, the answer is no. If you just want to get the name of a function as a string, you can use blah.__name__.

Related

Python wrapper get wrapped object

I do have a wrapperclass for a specific object giving it some extra methods.
However this object (wrapped or not) is often passed as an argument. In this case I want to past the original (wrapped) object allways.
Is there a way (I guess magic method) to overwrite what is coming back if I do the following in print:
class Foo:
pass
C = Foo()
print(C)
I do now that this is actually calling __repr__ (which needs to be a str). If I do the same for a function call
def Bar(obj):
pass
does get Bar a string or the actual class here?
How I wrap the object:
class Wrapper:
def __init__(self, obj):
self._obj = obj
def __getattr__(self, attr):
orig_attr = self._obj.__getattribute__(attr)
if callable(orig_attr):
def hooked(*args, **kwargs):
result = orig_attr(*args, **kwargs)
# prevent wrapped_class from becoming unwrapped
if result == self._obj:
return self
return result
return hooked
else:
return orig_attr
So if do:
C_wrapped = Wrapper(C)
and than
Bar(C_wrapped)
if would actually have it to act as
Bar(C)
even if pass C_wrapped
The solution i found is that the function Bar (or object in my case) needs to check if it gets a wrapped or unwrapped object. If it is wrapped, Bar unwraps it.
The downside is this induces coupling.

How to use a function outside a class as a property inside a class?

I'm having some problems. How we can define a function outside of a function that can be used in a class property? Also, how we can insert the self parameter into the function signature? I would like to visualize it like this:
>>> def a(self, x): #I thought maybe class will give "self" to this property function
... print(self)
...
>>> class aa:
... def __init__(self):
... pass
... #a
... def p():
... print('in it')
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in aa
TypeError: a() missing 1 required positional argument: 'x'
I want to define a function outside but to use inside of a class. Like a class's method as a property. How can I do this?
It's not really clear what you want your out-of-class function to do. There are a bunch of possibilities, but you may not know the terminology yet to describe it to us.
Here's the three I think are most likely:
You may want your function to be a decorator. That means you can apply it to a method with #decorator syntax to other functions, including methods in a class.
For this to work, your function needs to be written to accept a function object as its only argument. Whatever it returns is what will replace the function or method it was being called on, so usually you want to return a callable, but you could instead return a descriptor like property does. Try something like this:
def decorator(func):
def wrapper(self, *args, **kwargs):
print("in the wrapper")
result = func(self, *args, **kwargs)
print("wrapper is done")
return result
return wrapper
class Foo:
#decorator
def foo(self, x):
print("in foo(), x is", x)
f = Foo()
f.foo(1) # prints three messages
When you call the foo method, you're actually going to be calling the wrapper method that the decorator returned after it was applied to the original method (func). Because of how we wrote the wrapper, it will call func so the original method prints out its message too.
You may want to use property (a descriptor type) to call your out-of-class function. This is a less common way of using property than applying it as a decorator on a method, but it's not impossible. You could even have two different functions, one to be called when requesting the attribute, the other than will be called when setting it (but I'll demonstrate with just the getter):
def getter(obj):
print("in the getter")
return 1
class Foo2:
foo = property(getter)
f2 = Foo2()
print(f2.foo) # prints a message from the getter function first, then prints 1
Note that you can't use #decorator syntax when building a property this way. That is only legal syntax immediately before a function definition, and we're not defining any functions that way inside our class.
You may just want to copy a function defined outside of the class into it, without any decorator or property nonsense. This is the easiest one to do, it's just a simple assignment:
def func(self, x):
print("x is", x)
class Foo3:
method = func # just assign the global to a name in the class body
func = func # you can even use the same name if you don't mind confusing people
f3 = Foo3()
f3.method(1)
f3.func(2)
If you want to create a property that uses a function defined outside your class, it would be something like this:
def myfunc(self):
return self._p
class Foo:
def __init__(self, p):
self._p = p
p = property(myfunc)
f = Foo("Alpha")
f.p # gives "Alpha"
property accepts a function as its (first) argument. The function should have self as a parameter, and should return the value that you want the property to evaluate to.

Python - Call a function of an object which is stored in a dict

I have an Class which creates objects that contain a dict of functions. These functions are defined in the class.
class Foo:
def __init__(self, name, functions):
self.name = name
self.functions = functions
def myFunction1(self):
print self.name
return 'foo'
def myFunction2(self):
return 'bar'
In another file, I instance an object of the previous class and I want to run one of the functions that is in the dict.
from foo import Foo
myFunctions = Foo.('a name', {0 : Foo.myFunction1, 1 : Foo.myFunction2})
myFunctions.functions[0]()
I have this error :
TypeError: unbound method myFunction1() must be called with Foo instance as first argument.
I understand that when I execute the last line, I just call the function without call it with an object of Foo as first argument. But I can not write this :
myFunctions.myFunctions.functions[0]()
How can I call a function of this class which is stored in a dict attribute ?
I do not really understand what you are trying to achieve with this functions dictionary, but note that instance.function() is equivalent to Class.function(instance). In the former, instance is implicitly passed as the self parameter; in the latter, you pass it explicitly.
Thus, you could try the following.
foo = Foo({0 : Foo.myFunction1, 1 : Foo.myFunction2})
print foo.functions[0](foo)
If you need an object method, best way is to write another function that will call the correct function
class Foo:
def __init__(self, functions):
self.functions = functions
def myFunction1(self):
return 'foo'
def myFunction2(self):
return 'bar'
def run_func(self, func_key, *args, **kwargs):
func_name = self.functions.get(func_key)
if func_name and hasattr(self, func_name):
return getattr(self, func_name)(*args, **kwargs)
else:
return None
fun_dict = {0:'myFunction1', 1:'myFunction2'}
a = Foo(fun_dict)
print a.run_func(0)
You can send even arguments in this way.
def myFunction1(self, name):
return name
print a.run_func(0, "test")
This will print test by the myFunction1
You can call functions as a dictionary like this:
tmp = Foo()
tmp.functions={0:tmp.myFunction1, 1:tmp.myFunction2}
myFunctions = tmp.functions
print myFunctions.functions[0]()
Here is the simplest way to switch between functions:
dict = {0 : Foo.myFunction1(), 1 : Foo.myFunction2()}
function = fn_dict.get(0)
function()

Discover decorated class instance methods in python

I have a python class, for example:
class Book(models.Model):
enabled = models.BooleanField(default=False)
full_title = models.CharField(max_length=256)
alias = models.CharField(max_length=64)
author = models.CharField(max_length=64)
status = models.CharField(max_length=64)
#serializable
def pretty_status(self):
return [b for a, b in BOOK_STATUS_CHOICES if a == self.status][0]
The method pretty_status is decorated with #serializable.
What is the simplest and most efficient way to discover the methods in a class that have a certain decoration ? (in the above example giving: pretty_status).
Edit:
Please also note that the decorator in question is custom/modifiable.
If you have no control over what the decorator does, then in general, you can not identify decorated methods.
However, since you can modify serializable, then you could add an attribute to the wrapped function which you could later use to identify serialized methods:
import inspect
def serializable(func):
def wrapper(self):
pass
wrapper.serialized = True
return wrapper
class Book:
#serializable
def pretty_status(self):
pass
def foo(self):
pass
for name, member in inspect.getmembers(Book, inspect.ismethod):
if getattr(member, 'serialized', False):
print(name, member)
yields
('pretty_status', <unbound method Book.wrapper>)
Generally speaking, you can't. A decorator is just syntactic sugar for applying a callable. In your case the decorator syntax translates to:
def pretty_status(self):
return [b for a, b in BOOK_STATUS_CHOICES if a == self.status][0]
pretty_status = serializable(pretty_status)
That is, pretty_status is replaced by whatever serializable() returns. What it returns could be anything.
Now, if what serializable returns has itself been decorated with functools.wraps() and you are using Python 3.2 or newer, then you can see if there is a .__wrapped__ attribute on the new .pretty_status method; it's a reference to the original wrapped function.
On earlier versions of Python, you can easily do this yourself too:
def serializable(func):
def wrapper(*args, **kw):
# ...
wrapper.__wrapped__ = func
return wrapper
You can add any number of attributes to that wrapper function, including custom attributes of your own choosing:
def serializable(func):
def wrapper(*args, **kw):
# ...
wrapper._serializable = True
return wrapper
and then test for that attribute:
if getattr(method, '_serializable', False):
print "Method decorated with the #serializable decorator"
One last thing you can do is test for that wrapper function; it'll have a .__name__ attribute that you can test against. That name might not be unique, but it is a start.
In the above sample decorator, the wrapper function is called wrapper, so pretty_status.__name__ == 'wrapper' will be True.
You can't discover them directly but You can mark decorated methods with some flag.
import functools
def serializable(func):
functools.wraps(func)
def wrapper(*args, **kw):
# ...
wrapper._serializable = True
return wrapper
And then You can make metaclass for example analyse presence or absence of _serializable attribute.
Or You can collect all wrapped methodsin decorator
import functools
DECORATED = {}
def serializable(func):
functools.wraps(func)
def wrapper(*args, **kw):
# ...
DECORATED[func.__name__] = wrapper
return wrapper

Overload a method with a function at runtime

OK, I'll admit upfront this is a mega kludge and that I could definately implement this better. It's only morbid curiosity that's driving me to find out how I could do this.
class SomeClass(object):
def __init__(self):
def __(self, arg):
self.doStuff(arg)
self.overLoaded = __
def doStuff(self, string):
print string
SomeClass().overLoaded("test string")
This returns a parameter error because I'm only supplying overLoaded() with one argument instead of two. Is there some magic to tell the interpreter that it's now a method of a class (I tried decorating it with #classmethod, I always understood this to be it's purpose??)
Don't worry about the self parameter, the function already has that from local scope.
class SomeClass(object):
def __init__(self):
def __(arg):
self.bar(arg)
self.foo = __
def foo(self, arg):
print "foo", arg
def bar(self, arg):
print "bar", arg
SomeClass().foo("thing") # prints "bar thing"
When creating an instance (after __new__, iirc, but before __init__) Python binds all the methods to automagically supply the instance as the first argument. If you're adding a method later then you need to supply the instance manually. As you are defining the function with self already in scope you don't need to pass it again.
Python's new module is not a solution as it has been deprecated since 2.6. If you want to create a "real" instance method do it with the partial decorator like this:
import functools
class SomeClass(object):
def __init__(self):
def __(self, arg):
self.bar(arg)
self.foo = functools.partial(__, self)
def foo(self, arg):
print "foo", arg
def bar(self, arg):
print "bar", arg
SomeClass().foo("thing") # prints "bar thing"
The issue is that you are trying to add a new instance method (not class method) and it is not binding properly. Python has a module function to manually bind functions to instances.
import new
self.method = new.instancemethod(func, self, class)
Edit: Apparently the new module is deprecated. Use the types module instead for metamagic.
import types
self.method = types.MethodType(func, self, class)
sj26's solution is a good one. Another alternative, if you want to set up a method that can be overloaded with any user-supplied function or with another of the object's methods, is build a custom descriptor. This descriptor can be used as a decorator (analogous to #classmethod or #staticmethod); and it allows you to store a function in an instance's dictionary, and returns it as a method:
import types
class overloadable(object):
def __init__(self, func):
self._default_func = func
self._name = func.__name__
def __get__(self, obj, type=None):
func = obj.__dict__.get(self._name, self._default_func)
return types.MethodType(func, obj, type)
def __set__(self, obj, value):
if hasattr(value, 'im_func'): value = value.im_func
obj.__dict__[self._name] = value
def __delete__(self, obj):
del obj.__dict__[self._name]
Now we can just decorate a function with "#overloadable":
class SomeClass(object):
def doStuff(self, string):
print 'do stuff:', string
#overloadable
def overLoaded(self, arg):
print 'default behavior:', arg
And it'll just do the right thing when we overload it for a given instance:
>>> sc = SomeClass()
>>> sc.overLoaded("test string") # Before customization
default behavior: test string
>>> sc.overLoaded = sc.doStuff # Customize
>>> sc.overLoaded("test string")
do stuff: test string
>>> del sc.overLoaded # Revert to default behavior
>>> sc.overLoaded("test string")
default behavior: test string

Categories

Resources