How do I modify class method without touching source code in python? - python

How do I modify class method without touching source code?
There's a class from a library which I don't want to change the source code of.
class SomeLibraryClass(object):
def foo(self, a_var):
print self, a_var, "hello world"
Now, I want to define my own foo method, and substitute for the original SomeLibraryClass.foo .
def foo(obj, a_var):
print obj, a_var, "good bye"
SomeLibraryClass.foo = foo //
What should I do with the self variable?
How can I do this?

The same thing as you would do with self if you were in a method. self will be passed as the first parameter to your function and will be a reference to the current object. So if you want to define a function that will be used as a replacement for a method, just add self as the first parameter.
class SomeLibraryClass(object):
def __init__(self, x):
self.x = x
def foo(self, y):
print('Hello', self.x, y)
def my_foo(self, y):
print ('Good buy', self.x, y)
SomeLibraryClass.foo = my_foo
And how to use it:
>>> s = SomeLibraryClass(33)
>>> s.foo(5)
Good buy 33 5

Related

Classmethod: Using a function within a function

I have a situation where I'm using #classmethod to create a constructor for a class. Within this constructor, a function gets called, which then in turn calls another function. But either this doesn't work or (more probably) I'm doing something to make it not work. Here's an example in miniature:
class testclass:
def __init__(self, x):
self.x = x
#classmethod
def constructor(cls, x):
adj_x = cls.outer_adjust(cls, x)
return testclass(adj_x)
def outer_adjust(self, x):
return self.inner_adjust(x)
def inner_adjust(self, x):
return x + 1
test_instance = testclass.constructor(4)
This produces an error message:
inner_adjust() missing 1 required positional argument: 'x'
I can make it work by explicitly passing self to inner_adjust, eg
def outer_adjust(self, x):
return self.inner_adjust(self, x)
But this then means that the outer_adjust method can't be used outside of the constructor, which is not what I want.
Any assistance gratefully received.
Here's a more detailed example, with two constructors shown. I'm trying to follow the approach to constructors described in
What is a clean, pythonic way to have multiple constructors in Python?
Which is essentially that the constructors do some processing to figure out what variables they should pass to init when instantiating the class.
Both constructors give the same error:
if_char_is_z_make_it_a() missing 1 required positional argument: 'char_input'
As before, I need to be able to use the if_char_is_make_it_a function outside of the constructor (ie, when using the class normally).
class testclass:
def __init__(self, char):
self.char = char
#classmethod
def constructor_from_int(cls, int_input):
as_char = chr(int_input)
char = cls.process_char(cls, as_char)
return testclass(char)
#classmethod
def constructor_from_char(cls, char_input):
char = cls.process_char(cls, char_input)
return testclass(char)
def process_char(self, char_input):
processed_char = '(' + char_input + ')'
output_char = self.if_char_is_z_make_it_a(processed_char)
return output_char
def if_char_is_z_make_it_a(self, char_input):
if char_input == '(z)':
return '(a)'
return char_input
test_instance = testclass.constructor_from_char('a')
When you call cls.outer_adjust from constructor you are calling the unbound outer_adjust method.
Thus, you pass the class itself as self and not an instance to a method that expects to receive an instance as argument.
Although, there is no real reason to have a constructor method. This is exactly what __init__ is for.
class testclass:
def __init__(self, x):
self.x = self.outer_adjust(x)
def outer_adjust(self, x):
return self.inner_adjust(x)
def inner_adjust(self, x):
return x + 1
test_instance = testclass(4)
If you absolutely need the transformation on x to be done before the instantiation, then use __new__ instead. Although, this is generally not necessary.
Multiple constructors
If for some reason you still need to have a constructor method, by example if you want multiple constructors. Then keep in mind that outer_adjust and inner_adjust are instance methods, this means they must be called after you have created an instance.
class testclass:
def __init__(self, x):
self.x = x
#classmethod
def constructor1(cls, x):
instance = cls(x)
instance.outer_adjust()
return instance
#classmethod
def constructor2(cls, x):
instance = cls(x)
instance.inner_adjust()
return instance
def outer_adjust(self):
print('Do something else')
return self.inner_adjust()
def inner_adjust(self):
self.x += 1
As a sidenote, notice how I did not need to call testclass, but simply called cls in the constructor methods. Since this is a class method, we do not need to explicitly name the class. This is better, especially if you are to use inheritance.
Basically what you are doing here shall be done via the __new__ which serve as constructor.
class testclass:
def __init__(self, x):
self.x = x
def __new__(cls, *args, **kwargs):
instance = super(testclass, cls).__new__(cls, *args, **kwargs)
instance.outer_adjust(args[0])
return instance
def outer_adjust(self, x):
return self.inner_adjust(x)
def inner_adjust(self, x):
self.x = x + 1
test_instance = testclass(4)
You are abusing self. The point of the class method is to use the cls argument as constructor, instead of explicitly naming the class by testclass(adj_x). Also, during the cls.outer_adjust(cls, x) call, you are passing the class instead of the instance, which happens to work because you are not using any instance attributes.
As to your questions, there's no way to avoid the x argument. inner_adjust increases some value by 1, so you must give it something to increase. The idea would be to have
def constructor(cls, x):
return cls(x)
def inner_adjust(self):
return self.x += 1
and then do something like
object= testclass.constructor(12)
object.inner_adjust()

Function callable as class method or instance method [duplicate]

This question already has an answer here:
can a function be static and non-static in python 2
(1 answer)
Closed 4 years ago.
I have a Python class that I created previously, it looks something like this:
class Foo:
#classmethod
def bar(cls, x):
print(x + 3)
Foo.bar(7) # prints '10'
Now I would like to retrofit this interface with some state, so that the caller can create a Foo object, give it some properties, and then call its bar() method, which has access to self and its properties:
class Foo:
def __init__(self, y=3):
self.y = y
def bar(self, x):
print(x + self.y)
Foo().bar(7) # prints '10'
Foo(20).bar(7) # prints '27'
Unfortunately, this breaks the previous interface - Foo.bar(7) will now give TypeError: bar() missing 1 required positional argument: 'x', because Foo.bar(...) is a simple function reference.
I can add a #classmethod decorator to get part way there:
class Foo:
def __init__(self, y=3):
self.y = y
#classmethod
def bar(cls, x):
self = cls()
print(x + self.y)
Foo.bar(7) # prints '10'
Foo().bar(7) # prints '10'
Foo(20).bar(7) # prints '10', but I want '27'
Is it possible to create a #flexmethod decorator that converts the other direction? Specifically - if called as an instance method like Foo(20).bar(...), then do nothing; if called as a class method like Foo.bar(...) then create a new Foo object (using no-arg constructor) and pass that as the self argument.
I was going to try this myself by looking at the source for #classmethod, but it looks like it's implemented at the C level.
The Descriptor HOWTO has entire section on how #classmethod and #staticmethod work, and how to implement variations on them, including this pure-Python equivalent to classmethod:
class ClassMethod(object):
"Emulate PyClassMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, klass=None):
if klass is None:
klass = type(obj)
def newfunc(*args):
return self.f(klass, *args)
return newfunc
If it isn't obvious to you how that works, you probably need to read the whole HOWTO. I've got a blog post that tries to provide an introduction to the method-related stuff first, which may help get over the abstraction hump of the first part of the HOWTO.

Should I use the class name or `cls` param to construct a an instance?

As title described, I an confused as the example:
class Point(object):
def __init__(self, x=0.0, y=0.0):
self.x, self.y = x, y
#classmethod
def get_point1(cls, cor): # cor is list with x=1 and y=2
return Point(cor[0], cor[1])
#classmethod
def get_point2(cls, cor):
return cls(cor[0], cor[1])
I am confused which one(get_point1 or get_point2) should I use, and what is the difference between them?
The #classmethod decorator makes the function a class method, as opposed to instance method. To make it more robust, it is preferable to use cls rather than the actual class name where it is defined.
If you use cls, the parameter which will be passed depends on the actual class being called (for example, if you subclass Point) while using Point explicity, may cause issues if you subclass it and use the class method.
Look at this code for example
class Point(object):
def __init__(self, x=0.0, y=0.0):
self.x, self.y = x, y
#classmethod
def get_point1(cls, cor): # cor is list like [1,2] with x=1 and y=2
return Point(cor[0], cor[1])
#classmethod
def get_point2(cls, cor):
return cls(cor[0], cor[1])
class SubPoint(Point):
pass
sub1 = SubPoint.get_point1([0, 1])
sub2 = SubPoint.get_point2([2, 2])
print sub1.__class__
print sub2.__class__
<class '__main__.Point'>
<class '__main__.SubPoint'>
Is there any other difference? - well, if you need to do some logic inside your class method, which depends on class attributes, then yes it does.

Python: avoid defining both a classmethod and an instancemethod

NOTE on the question below. I think the 'proper' pythonic idiom is to a) create module functions, such as foo_math below, and then call their specific action against an instance within the class itself. The bottom piece of code reflects that approach.
I want to define a classmethod which takes two arguments and returns a value. I want the same method to be able to be called on a class instance with the instance value pass as one of the arguments. Can I do this without defining two distinct methods as I have done here?
class Foo(object):
__init__(x):
self.x = x
#classmethod
def foo_math(cls, x, y):
return x + y
def math(self, y):
return Foo.foo_math(self.x, y)
What I would like is:
>>> Foo.math(3, 4)
7
>>> f = Foo()
>>> f.x = 3
>>> f.math(4)
7
Short of subtyping int, here is my conclusion to this question:
def foo_math(cls, x, y):
return x + y
class Foo(object):
__init__(x):
self.x = x
def foo_math(self, y):
return foo_math(self, y)
i don't recommend doing this, but if you really want, it's this (thank you other guy on stackoverflow for first part):
class staticorinstancemethod(object):
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
return functools.partial(self.func, instance)
then, do something like
class F(object):
#staticorinstancemethod
def math(instOrNone, v1, v2=None):
return instOrNone.x + v1 if instOrNone else v1 + v2
but maybe you just want to define the __add__ and __radd__ methods...
I don't think that you can call a method from a class without defining an object of that class (class methods don't belong inside the methods of any one class), so things like Foo.math(3, 4) will return a NameError as Foo has not been defined.
With this in mind, you should modify your code to be like this (even though with the problem solved there are still some issues with the code):
# A class method would probably go here somewhere.
class Foo(object):
def __init__(self, x):
self.x = x
def foo_math(self, x, y):
return x + y
def math(self, y):
return self.foo_math(self.x, y)
Then you can do:
>>> f = Foo(3)
>>> f.math(4)
7

Adding to the dir() of instance

I have a class (named "A") with some instance variables. I want to add the dir() of this variables to the dir() of instances of class A.
For example:
class A(object):
def __init__(self, x, y):
self.x = x
self.y = y
class X(object):
def f_x(self):
pass
class Y(object):
def f_y(self):
pass
x = X(); y = Y()
a = A(x,y)
I want f_x and f_y to appear in
dir(a)
Is there a better way, or a more 'correct' one, than just iterating X.dict and Y.dict and for each element, use something like:
setattr(A, str(element), element)
Thanks.
A should really be a subclass of X and Y in this case. (Just be sure to read Michele Simionato's article on super and diamond inheritence before you get too deep into it.)
class X(object):
def f_x(self):
pass
class Y(object):
def f_y(self):
pass
class A(X, Y):
def __init__(self, *args, **kwargs): # splats optional
# do what you need to here
dir(A(X(),Y())) # Ah! Lisp!
However, if you really need things to be magic, then just override __getattr__ for X to look in self.x and self.y before throwing an error. But seriously, don't do this.
Why don't you simply inherit from both classes?
class B(A, X):
pass
a = B()
dir(a)

Categories