Possible to change a function's repr in python? - python

I've only seen examples for setting the __repr__ method in class definitions. Is it possible to change the __repr__ for functions either in their definitions or after defining them?
I've attempted without success...
>>> def f():
pass
>>> f
<function f at 0x1026730c8>
>>> f.__repr__ = lambda: '<New repr>'
>>> f
<function __main__.f>

Yes, if you're willing to forgo the function actually being a function.
First, define a class for our new type:
import functools
class reprwrapper(object):
def __init__(self, repr, func):
self._repr = repr
self._func = func
functools.update_wrapper(self, func)
def __call__(self, *args, **kw):
return self._func(*args, **kw)
def __repr__(self):
return self._repr(self._func)
Add in a decorator function:
def withrepr(reprfun):
def _wrap(func):
return reprwrapper(reprfun, func)
return _wrap
And now we can define the repr along with the function:
#withrepr(lambda x: "<Func: %s>" % x.__name__)
def mul42(y):
return y*42
Now repr(mul42) produces '<Func: mul42>'

No, because repr(f) is done as type(f).__repr__(f) instead.

In order to do that, you'd need to change the __repr__ function for the given class, which in this case is the built-in function class (types.FunctionType). Since in Python you cannot edit built-in classes, only subclass them, you cannot.
However, there are two approaches you could follow:
Wrap some functions as kwatford suggested
Create your own representation protocol with your own repr function. For example, you could define a myrepr function that looks for __myrepr__ methods first, which you cannot add to the function class but you can add it to individual function objects as you suggest (as well as your custom classes and objects), then defaults to repr if __myrepr__ is not found. A possible implementation for this would be:
def myrepr(x):
try:
x.__myrepr__
except AttributeError:
return repr(x)
else:
return x.__myrepr__()
Then you could define __myrepr__ methods and use the myrepr function. Alternatively, you could also do __builtins__.repr = myrepr to make your function the default repr and keep using repr. This approach would end up doing exactly what you want, though editing __builtins__ may not always be desirable.

This appears to be difficult. Kwatford's approach only solves this problem partially since it does not work for functions in classes, becuase self would be treated like a positional argument, as explained in Decorating Python class methods - how do I pass the instance to the decorator? - However, the solution for that question is not applicable to this case, unfortunately, as using __get__() and functools.partial would override the custom __repr__().

Related

How to set a repr for a function itself? [duplicate]

This question already has answers here:
Possible to change a function's repr in python?
(4 answers)
Closed 2 years ago.
__repr__ is used to return a string representation of an object, but in Python a function is also an object itself, and can have attributes.
How do I set the __repr__ of a function?
I see here that an attribute can be set for a function outside the function, but typically one sets a __repr__ within the object definition itself, so I'd like to set the repr within the function definition itself.
My use case is that I am using tenacity to retry a networking function with exponential backoff, and I want to log the (informative) name of the function I have called last.
retry_mysql_exception_types = (InterfaceError, OperationalError, TimeoutError, ConnectionResetError)
def return_last_retry_outcome(retry_state):
"""return the result of the last call attempt"""
return retry_state.outcome.result()
def my_before_sleep(retry_state):
print("Retrying {}: attempt {} ended with: {}\n".format(retry_state.fn, retry_state.attempt_number, retry_state.outcome))
#tenacity.retry(wait=tenacity.wait_random_exponential(multiplier=1, max=1200),
stop=tenacity.stop_after_attempt(30),
retry=tenacity.retry_if_exception_type(retry_mysql_exception_types),
retry_error_callback=return_last_retry_outcome,
before_sleep=my_before_sleep)
def connect_with_retries(my_database_config):
connection = mysql.connector.connect(**my_database_config)
return connection
Currently retry_state.fn displays something like <function <lambda> at 0x1100f6ee0> like #chepner says, but I'd like to add more information to it.
You could use a decorator that returns a class with the __call__ and __repr__ set:
class CustomReprFunc:
def __init__(self, f, custom_repr):
self.f = f
self.custom_repr = custom_repr
def __call__(self, *args, **kwargs):
return self.f(*args, **kwargs)
def __repr__(self):
return self.custom_repr(self.f)
def set_repr(custom_repr):
def set_repr_decorator(f):
return CustomReprFunc(f, custom_repr)
return set_repr_decorator
#set_repr(lambda f: f.__name__)
def func(a):
return a
print(repr(func))
I think a custom decorator could help:
import functools
class reprable:
"""Decorates a function with a repr method.
Example:
>>> #reprable
... def foo():
... '''Does something cool.'''
... return 4
...
>>> foo()
4
>>> foo.__name__
'foo'
>>> foo.__doc__
'Does something cool.'
>>> repr(foo)
'foo: Does something cool.'
>>> type(foo)
<class '__main__.reprable'>
"""
def __init__(self, wrapped):
self._wrapped = wrapped
functools.update_wrapper(self, wrapped)
def __call__(self, *args, **kwargs):
return self._wrapped(*args, **kwargs)
def __repr__(self):
return f'{self._wrapped.__name__}: {self._wrapped.__doc__}'
Demo: http://tpcg.io/uTbSDepz.
It's already set.
>>> repr(lambda x:x)
'<function <lambda> at 0x1100f6ee0>'
The problem is that the function type is immutable, so you can't just assign a new function to function.__repr__, and you also can't create a subtype of function in order to override __repr__. (Not that creating instances of the subclass would be easy, even if it were possible to define it.)
You can't do this for actual functions; the function type is immutable, and already defines a __repr__, and __repr__ is looked up on the type, not the instance, so changing __repr__ on a given function doesn't change behavior.
While probably not useful in this case, you can make your own callable class (analogous to C++ functors), and those can define their own __repr__. For example:
class myfunction:
#staticmethod # Avoids need to receive unused self
def __call__(your, args, here):
... do stuff and return as if it were a function ...
#classmethod # Know about class, but again, instance is useless
def __repr__(cls):
return f'{cls.__name__}(a, b, c)'
which you could convert to a singleton instance of the class (making it equivalent to a plain function in how you use it) at the end by just doing:
myfunction = myfunction()
to replace the class with a single instance of the class.
Note: In real code, I'd almost certainly just change where I'm printing it to print in a more useful way without modifying the function. This doesn't have much overhead over a plain function or a wrapped plain function (since we put the function itself in __call__ rather than wrapping, making it faster, but requiring a separate class for each "friendly repr function"), but it's just not the job of the function to decide how to represent itself in a human-friendly way; that's your job, based on the situation.
You can change retry_state.fn to retry_state.__name__. I use many decorators like this. If you add a decorator, it will be called each time a function of interest is called.
def display_function(func):
""" This decorator prints before and after running """
#functools.wraps(func)
def function_wrapper(*args, **kwargs):
print(f'\nNow: Calling {func.__name__}.')
entity = func(*args, **kwargs)
print(f'Done: Calling {func.__name__}.\n')
return entity
return function_wrapper
Additionally, the retrying module in python allows you to do some of what you're doing by default. I often use a decorator:
import retrying
#retrying.retry(wait_exponential_multiplier=1000, wait_exponential_max=10000)

Can you use a static method as default parameter in __init__ in python classes?

I am writing a class for a neural network and I want to give it some form of customization, so that you can choose different cost functions and regularizations. For this I want to set them as default parameters in the __init__() method.
But when I pass MyClass.static_method in my example, the Interpreter then tells me that MyClass is not (yet) defined. Why is this and is there a nicer workaround than mine?
You can of course just set the static method as a default parameter, but then other problems arise. For example, if I want to access the functions name (which I actually want), I cannot use __name__ rightaway. I know how to do it another way, by accessing static_method.__func__.__name__. But this seems clumsy and as you get a staticmethod object, seems like its not intended to be used this way.
class MyClass:
#staticmethod
def static_method():
do_something()
def __init__(self, func=MyClass.static_method, func2=static_method):
self.name = func.__name__ #Does not work
self.name2 = func2.__func__.__name__ #Should work
I did expect for the MyClass.static_method to work, but the class does not seem to exist then. So, one last time, why?
The reason you're having problems with your static method usage as a default argument is due to a combination of two issues.
The first issue is that the default argument needs to be well defined when the def statement is run, not only when the function is called. That's because the default argument gets built into the function object, rather than being recalculated each time the function runs (this is the same reason why a mutable default argument like an empty list is often an error). Anyway, this is why you can't use MyClass.static_method as the default argument, since MyClass isn't defined yet when the function is being defined (the class object is only made after all its contents have been created).
The next issue is that a staticmethod object doesn't have all the same attributes and methods as a regular function. Normally this doesn't matter, as when you access it through a class object (e.g. MyClass.static_method once MyClass exists) or through an instance (e.g. self.static_method), it will be callable and have a __name__. But that's because you get the underlying function in those situations, rather than the staticmethod object itself. The staticmethod object itself is a descriptor, but not a callable.
So neither of these functions will work correctly:
class MyClass:
#staticmethod
def static_method():
pass
def foo(self, func=MyClass.static_method): # won't work because MyClass doesn't exist yet
pass
def bar(self, func=static_method): # this declaration will work (if you comment out foo)
name = func.__name__ # but this doesn't work when the bar() is called
func() # nor this, as func is the staticmethod object
What does work would be to use the actual function underlying the staticmethod object as the default:
def baz(self, func=static_method.__func__): # this works!
name = func.__name__
func()
This also works when you pass in some other function (or bound method), unlike the version of your code that used name = func.__func__.__name__.
DEFAULT = object()
class MyClass:
#staticmethod
def static_method():
do_something()
def __init__(self, func=DEFAULT, func2=DEFAULT):
self.name = self.static_method.__name__ if func is DEFAULT else func.__name__
self.name2 = self.static_method.__func__.__name__ if func2 is DEFAULT else func2.__func__.__name__
I guess??

How do you implement __str__ for a function?

Given a function foo:
def foo(x):
pass
Printing its representation by invoking str or repr gives you something boring like this:
str(foo)
'<function foo at 0x119e0c8c8>'
I'd like to know if it is possible to override a function's __str__ method to print something else. Essentially, I'd like to do:
str(foo)
"I'm foo!'
Now, I understand that the description of a function should come from __doc__ which is the function's docstring. However, this is merely an experiment.
In attempting to figure out a solution to this problem, I came across implementing __str__ for classes: How to define a __str__ method for a class?
This approach involved defining a metaclass with an __str__ method, and then attempting to assign the __metaclass__ hook in the actual class.
I wondered whether the same could be done to the class function, so here's what I tried -
In [355]: foo.__class__
Out[355]: function
In [356]: class fancyfunction(type):
...: def __str__(self):
...: return self.__name__
...:
In [357]: foo.__class__.__metaclass__ = fancyfunction
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
I figured it wouldn't work, but it was worth a shot!
So, what's the best way to implement __str__ for a function?
A function in Python is just a callable object. Using def to define function is one way to create such an object. But there is actually nothing stopping you from creating a callable type and creating an instance of it to get a function.
So the following two things are basically equal:
def foo ():
print('hello world')
class FooFunction:
def __call__ (self):
print('hello world')
foo = FooFunction()
Except that the last one obviously allows us to set the function type’s special methods, like __str__ and __repr__.
class FooFunction:
def __call__ (self):
print('hello world')
def __str__ (self):
return 'Foo function'
foo = FooFunction()
print(foo) # Foo function
But creating a type just for this becomes a bit tedious and it also makes it more difficult to understand what the function does: After all, the def syntax allows us to just define the function body. So we want to keep it that way!
Luckily, Python has this great feature called decorators which we can use here. We can create a function decorator that will wrap any function inside a custom type which calls a custom function for the __str__. That could look like this:
def with_str (str_func):
def wrapper (f):
class FuncType:
def __call__ (self, *args, **kwargs):
# call the original function
return f(*args, **kwargs)
def __str__ (self):
# call the custom __str__ function
return str_func()
# decorate with functool.wraps to make the resulting function appear like f
return functools.wraps(f)(FuncType())
return wrapper
We can then use that to add a __str__ function to any function by simply decorating it. That would look like this:
def foo_str ():
return 'This is the __str__ for the foo function'
#with_str(foo_str)
def foo ():
print('hello world')
>>> str(foo)
'This is the __str__ for the foo function'
>>> foo()
hello world
Obviously, doing this has some limitations and drawbacks since you cannot exactly reproduce what def would do for a new function inside that decorator.
For example, using the inspect module to look at the arguments will not work properly: For the callable type, it will include the self argument and when using the generic decorator, it will only be able to report the details of wrapper. However, there might be some solutions, for example discussed in this question, that will allow you to restore some of the functionality.
But that usually means you are investing a lot of effort just to get a __str__ work on a function object which will probably very rarely be used. So you should think about whether you actually need a __str__ implementation for your functions, and what kind of operations you will do on those functions then.
If you find yourself wrapping functions, it's useful to look at functools.partial. It's primarily for binding arguments of course, but that's optional. It's also a class that wraps functions, removing the boilerplate of doing so from scratch.
from functools import partial
class foo(partial):
def __str__(self):
return "I'm foo!"
#foo
def foo():
pass
assert foo() is None
assert str(foo) == "I'm foo!"

How to decorate an object method?

I need to decorate a object's method. It needs to be at runtime because the decorators applied on the object depends on the arguments that the user gave when calling the program (arguments supplied with argv), so a same object could be decorated 3 times, 2 times, or not be decorated at all.
Here is some context, the program is a puzzle solver, the main behavior is to find a solution for the puzzle automatically, by automatically I mean without user intervention. And here is where the decoration gets to play, one of the things I want to is draw a graph of what happened during the execution, but I want to do so only when the flag --draw-graph is used.
Here is what I've tried:
class GraphDecorator(object):
def __init__(self, wrappee):
self.wrappee = wrappee
def method(self):
# do my stuff here
self.wrappee.method()
# do more of stuff here
def __getattr__(self,attr):
return getattr(self.wrappee,attr)
And why it did NOT work:
It did not work because of the way I built the application, when a method that did not exist in my Decorator class was called it felt back to the implementation of the decorated class, the problem is that the application always started invoking the method run that did not need to be decorated, so the undecorated fall back was used and from inside the undecorated form it always called undecorated methods, what I needed was to replace the method from the object, not to proxy it:
# method responsible to replace the undecorated form by the decorated one
def graphDecorator(obj):
old_method = obj.method
def method(self):
# do my stuff here
old_method()
# do more of my stuff
setattr(obj,'method',method) # replace with the decorated form
And here is my problem, the decorated form does not receive self when it is called resulting on a TypeError because of the wrong number of arguments.
The problem was that I couldn't use func(self) as a method. The reason is that setattr() method does not bound the function, and the function acts like it a static method - not a class method -, thanks to the introspective nature of python I've able to come up with this solution:
def decorator(obj):
old_func = obj.func # can't call 'by name' because of recursion
def decorated_func(self):
# do my stuff here
old_func() # does not need pass obj
# do some othere stuff here
# here is the magic, this get the type of a 'normal method' of a class
method = type(obj.func)
# this bounds the method to the object, so self is passed by default
obj.func = method(decorated_func, obj)
I think this is the best way to decorate a object's method at runtime, though it would be nice to find a way to call method() directly, without the line method = type(obj.func)
You might want to use __getattribute__ instead of __getattr__ (the latter being only called if "standard" lookup fails):
class GraphDecorator(object):
def __init__(self, wrappee):
self.__wrappee = wrappee
def method(self):
# do my stuff here
self.wrappe.method()
# do more of stuff here
def __getattribute__(self, name):
try:
wrappee = object.__getattribute__(self, "_GraphDecorator__wrappee")
return getattr(wrappee, name)
except AttributeError:
return object.__getattribute__(self, name)
I need to decorate a object's method. It needs to be at runtime because the decorators applied on the object depends on the arguments that the user gave when calling the program (arguments supplied with argv), so a same object could be decorated 3 times, 2 times, or not be decorated at all.
The above is unfortunately incorrect, and what you are trying to do is unnecessary.
You can do this at runtime like so. Example:
import sys
args = sys.argv[1:]
class MyClass(object):
pass
if args[0]=='--decorateWithFoo':
MyClass = decoratorFoo(MyClass)
if args[1]=='--decorateWithBar'
MyClass = decoratorBar(MyClass)
The syntax:
#deco
define something
Is the same thing as:
define something
something = deco(something)
You could also make a decorator factory #makeDecorator(command_line_arguments)
"It needs to be at runtime because the decorators applied on the object depends on the arguments that the user gave when calling the program"
The don't use decorators. Decorators are only syntactical support for wrappers, you can just as well use normal function/method calls instead.

Python: Decorated staticmethod receives non-callable method

I'm having a little problem decorating a static method in Python. I think the following code best represents my problem:
def decorator(func):
print callable(func)
return func
class Foo():
#decorator
#staticmethod
def bar():
return
# outputs False
print callable(Foo.bar)
# outputs True
This seems to be a bug. I imagine it arises because when the method Foo.bar is passed to the decorator, it is a function, not a method. That is the only reason I can see for it not being callable, for if we decorate a standard function, it is not callable, as shown below.
#staticmethod
def function():
return
print callable(function)
# outputs False
So is this a true bug in implementation of the staticmethod decorator, and/or are there any simple workarounds? I did think of writing a decorator to asign a __call__ attribute, but I don't know how callable is implemented, so I can't gauge the sucess of such a method.
Methods are functions. But staticmethod objects aren't. They are descriptors, so there's extra magic that gives you a callable when you access it as Cls.static_method, but this magic can't hide anything when you use (i.e. pass to decorator) static_method inside the body of Cls. You can't really hack your way around this, at least not cleanly. A much simpler solution is reordering the decorators such that staticmethod get applied last - i.e. put it at the top, above all other decorators.
Well, whether you consider it a bug or not, it's documented:
Static method objects provide a way of defeating the transformation of
function objects to method objects
described above. A static method
object is a wrapper around any other
object, usually a user-defined method
object. When a static method object is
retrieved from a class or a class
instance, the object actually returned
is the wrapped object, which is not
subject to any further transformation.
Static method objects are not
themselves callable, although the
objects they wrap usually are. Static
method objects are created by the
built-in staticmethod() constructor.
I wrote my own implementation of staticmethod that is callable and this seems to solve this problem nicely.
class staticmethod(object):
"""Make #staticmethods play nice with #memoize."""
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
"""Call the static method with no instance."""
return self.func(*args, **kwargs)
This doesn't use the descriptor protocol and as such behaves very differently than the builtin staticmethod internally, however in practice it makes functions callable as class attributes, instance attributes, and even as function attributes (ie, if you've wrapped your class in a decorating function, this implementation of staticmethod will still allow you to call your static methods as attributes on the wrapping function).

Categories

Resources