I am working with an external module with a class A and function foo. The class calls the function inside it
def foo(...):
...
class A:
def m(self, ...):
...
foo()
...
...
I need to change the behavior of foo without editing the module. Is there a neat way to do it, without subclassing class A?
Define the replacement function, then assign it to the class function.
def replacement_m(...):
...
from external_module import A
A.m = replacement_m
Unfortunately you can't just replace foo(), because it isn't a class method. You have to replace the whole A.m method.
This is called monkeypatching. See this question for more information What is monkey patching?
Related
So I have a method in a class and I have another separate function (i.e., outside the class) that want to reuse the docstring of that method. I tried something like __doc__ = <Class Name>.<Method Name>.__doc__ under the separate function but that does not work. Thus, is there a way to do so?
__doc__ needs to be assigned as a property of the new function, like this:
class C:
def foo(self):
'docstring'
def bar():
pass
bar.__doc__ = C.foo.__doc__ # NOT __doc__ = ...
assert bar.__doc__ == 'docstring'
Even this is a case, I'd use a manual copy of a docstring. Class or function could be moved around or separated to different projects. Moreso, reading a function below goesn't give me any idea what it's doing.
Please, consult with PEP-8, PEP-257 and PEP-20 for more information why this behavior is discoraged.
def myfunc():
...
myfunc.__doc__ = other_obj.__doc__
I have a code like this:
def my_func():
pass
class MyClass():
class_variable = my_func()
pass
i = MyClass()
Since my_func is logically related to MyClass, and doesn't serve any purpose outside of it, I'd prefer to have something like that instead:
class MyClass():
class_variable = my_func()
def my_func():
pass
i = MyClass()
The above doesn't work, of course, because my_func isn't defined yet at the time it's called. Is there some other way to assign a class variable from inside the class?
I'd personally keep my_func() outside the class. Sure, it may only be used for the class definition, but if it is not useful once the class is defined, it should not be part of the class API.
If the my_func() function should be used together with the class even after the class has been created, then you can still make this work with MyClass.my_func() being a static method. In that case define the function first before setting the class variable:
class MyClass():
#staticmethod
def my_func():
pass
class_variable = my_func.__func__()
The #staticmethod is not strictly necessary as at the time class_variable is set, my_func is still a local name in the class definition body.
However, since you are using it as as static function anyway, you may as well mark it as such. The advantage however is that MyClass.my_func() now also works.
Because a #staticmethod isn't going to bind outside of a class or instance attribute context, you do need to unwrap it first by accessing the wrapped function with the __func__ attribute.
Demo:
>>> class MyClass():
... #staticmethod
... def my_func():
... return 'foobar'
... class_variable = my_func.__func__()
...
>>> MyClass.class_variable
'foobar'
>>> MyClass.my_func()
'foobar'
I'm writing a method decorator and require access to the class defining the method that is currently decorated.
The issue seems with this is, that with Python 3 methods in a class are just functions unless the class is instantiated.
Is there any way around this? I don't really want to fiddle around with __qualname__...
In [29]: class A:
....: def B(self):
....: pass
....:
In [30]: A.B.__qualname__
Out[30]: 'A.B'
# This is what I want:
>>> get_class(A.B)
A
You can't, because at the time your decorator on a method is run, the class is yet to be created.
An example illustrates this a little better:
class Foo:
#spam
def bar(self): pass
When spam(bar) is invoked to produce a decorated function, we are inside the pseudo-function that Python runs to define the class body. Only when that pseudo-function is done executing, is the local namespace of that function turned into the class body and the actual class object itself is created.
That means that there is no Foo class object yet at the time spam() is run.
Instead, create a class decorator:
#spam
class Foo:
def bar(self): pass
Now spam() is passed the whole, complete Foo class giving you access to both the class and the methods.
If you need to mark specific methods on the class for decoration, you could use a marker decorator that sets attributes on the function:
def marker(func):
func._marked = True
return func
Use this decorator in the class body on methods that you want decorated, then use the class decorator to pick out those methods:
#spam
class Foo:
#marker
def bar(self): pass
def baz(self): pass
When you decorate a method, it is not bound yet to the class, and therefor doesn't have the im_class attribute yet. I looking for a way to get the information about the class inside the decorator. I tried this:
import types
def decorator(method):
def set_signal(self, name, value):
print name
if name == 'im_class':
print "I got the class"
method.__setattr__ = types.MethodType(set_signal, method)
return method
class Test(object):
#decorator
def bar(self, foo):
print foo
But it doesn't print anything.
I can imagine doing this:
class Test(object):
#decorator(klass=Test)
def bar(self, foo):
print foo
But if I can avoid it, it would make my day.
__setattr__ is only called on explicit object.attribute = assignments; building a class does not use attribute assignment but builds a dictionary (Test.__dict__) instead.
To access the class you have a few different options though:
Use a class decorator instead; it'll be passed the completed class after building it, you could decorate individual methods on that class by replacing them (decorated) in the class. You could use a combination of a function decorator and a class decorator to mark which methods are to be decorated:
def methoddecoratormarker(func):
func._decorate_me = True
return func
def realmethoddecorator(func):
# do something with func.
# Note: it is still an unbound function here, not a method!
return func
def classdecorator(klass):
for name, item in klass.__dict__.iteritems():
if getattr(item, '_decorate_me', False):
klass.__dict__[name] = realmethoddecorator(item)
You could use a metaclass instead of a class decorator to achieve the same, of course.
Cheat, and use sys._getframe() to retrieve the class from the calling frame:
import sys
def methoddecorator(func):
callingframe = sys._getframe(1)
classname = callingframe.f_code.co_name
Note that all you can retrieve is the name of the class; the class itself is still being built at this time. You can add items to callingframe.f_locals (a mapping) and they'll be made part of the new class object.
Access self whenever the method is called. self is a reference to the instance after all, and self.__class__ is going to be, at the very least, a sub-class of the original class the function was defined in.
My strict answer would be: It's not possible, because the class does not yet exist when the decorator is executed.
The longer answer would depend on your very exact requirements. As I wrote, you cannot access the class if it does not yet exists. One solution would be, to mark the decorated method to be "transformed" later. Then use a metaclass or class decorator to apply your modifications after the class has been created.
Another option involves some magic. Look for the implementation of the implements method in zope.interfaces. It has some access to the information about the class which is just been parsed. Don't know if it will be enough for your use case.
You might want to take a look at descriptors. They let you implement a __get__ that is used when an attribute is accessed, and can return different things depending on the object and its type.
Use method decorators to add some marker attributes to the interesting methods, and use a metaclass which iterates over the methods, finds the marker attributes, and does the logic. The metaclass code is run when the class is created, so it has a reference to the newly created class.
class MyMeta(object):
def __new__(...):
...
cls = ...
... iterate over dir(cls), find methods having .is_decorated, act on them
return cls
def decorator(f):
f.is_decorated = True
return f
class MyBase(object):
__metaclass__ = MyMeta
class MyClass(MyBase):
#decorator
def bar(self, foo):
print foo
If you worry about that the programmer of MyClass forgets to use MyBase, you can forcibly set the metaclass in decorator, by exampining the globals dicitionary of the caller stack frame (sys._getframe()).
I know C++ and Java and I am unfamiliar with Pythonic programming. So maybe it is bad style what I am trying to do.
Consider fallowing example:
class foo:
def a():
__class__.b() # gives: this is foo
bar.b() # gives: this is bar
foo.b() # gives: this is foo
# b() I'd like to get "this is bar" automatically
def b():
print("this is foo")
class bar( foo ):
def b( ):
print("this is bar")
bar.a()
Notice, that I am not using self parameters as I am not trying to make instances of classes, as there is no need for my task. I am just trying to refer to a function in a way that the function could be overridden.
What you want is for a to be a classmethod.
class Foo(object):
#classmethod
def a(cls):
Foo.b() # gives: this is foo
Bar.b() # gives: this is bar
cls.b() # gives: this is bar
#staticmethod
def b():
print("this is foo")
class Bar(Foo):
#staticmethod
def b():
print("this is bar")
Bar.a()
I've edited your style to match the Python coding style. Use 4 spaces as your indent. Don't put extra spaces in between parenthesis. Capitalize & CamelCase class names.
A staticmethod is a method on a class that doesn't take any arguments and doesn't act on attributes of the class. A classmethod is a method on a class that gets the class automatically as an attribute.
Your use of inheritance was fine.
Quote from the Execution Model:
The scope of names defined in a class block is limited to the class
block; it does not extend to the code blocks of methods – this
includes generator expressions since they are implemented using a
function scope.
This mean that there is no name b in the scope of function a. You should refer to it via class or instance object.