Redefine Class Methods or Class

Redefine Class Methods or Class

It's called monkey patching. But, PHP doesn't have native support for it.

Though, as others have also pointed out, the runkit library is available for adding support to the language and is the successor to classkit. And, though it seemed to have been abandoned by its creator (having stated that it wasn't compatible with PHP 5.2 and later), the project does now appear to have a new home and maintainer.

I still can't say I'm a fan of its approach. Making modifications by evaluating strings of code has always seemed to me to be potentially hazardous and difficult to debug.

Still, runkit_method_redefine appears to be what you're looking for, and an example of its use can be found in /tests/runkit_method_redefine.phpt in the repository:

runkit_method_redefine('third_party_library', 'buggy_function', '',
'return \'good result\''
);

Redefinition of class method in python

Well, unless I'm mistaken, you want to subclass Model. This is sort of like creating an instance of Model and replacing its function1 attribute with a function defined in the plugin module (i.e. your option 1); but it's much cleaner, and takes care of all the details for you:

# [in the plugin file]
from code import Model, instance

class MyModel(Model):
def function1(*args, **kwargs):
"""
Work to do by this model
"""
# some specific model-dependent work
return

newmodel = MyModel(a="a name", b="some other stuff")
instance.register(newmodel)

This way, all the other methods (functions "attached" to a Model instance) are inherited from Model; they will behave in just the same way, but function1 will be overridden, and will follow your customized function1 definition.

Class methods redefining, 'self' argument problems

It's a subtlety of what . does in Python. It both looks up the method on the class, and binds the method to the instance. This binding is what provides the class instance implicitly as the first argument, self. Look at this:

>>> print(example.some_method)
<function my_print at 0x7f66c4129f30>
>>> print(a.some_method)
<bound method my_print of <test.example object at 0x7f66c41c2290>>

However, when the method is found on the instance (which shadows the one on the class), the binding does not happen:

>>> a = example()
my print is called
>>> a.some_method = my_print
>>> print(a.some_method)
<function my_print at 0x7f66c4129f30>

This is stated in the Python reference:

It is also important to note that user-defined functions which are attributes of a class instance are not converted to bound methods; this only happens when the function is an attribute of the class.

The solution, then, is to make sure that the method is always an attribute of the class instance, and call it accordingly:

class example():

def __init__(self):
self.some_method = my_print
self.some_method(self)

def test(self):
self.some_method(self)

Looks weird, works great.

If you want the method to always be an attribute of the class instead, consider using inheritance.

Redefine __str__ method in the same way for multiple classes in Python

You could define a parent class that has the functionality you want and inherit it in each of the child classes:

class Stringer:
def __str__(self):
return(str(self.value + 5))

class testClass1(Stringer):
def __init__(self, value):
self.value = value

class testClass2(Stringer):
def __init__(self, value):
self.value = value

test1 = testClass1(2)
print(test1)
#7

test2 = testClass2(5)
print(test2)
#10

Ruby - How to redefine class methods?

alias_method is meant for instance methods. But File.basename is a class method.

class File
class << self
alias_method :basename_without_hello, :basename

def basename(*args)
puts "hello world!"
basename_without_hello(*args)
end
end
end

The class << self evaluates everything on the "class level" (Eigenklass) - so you don't need to write self. (def self.basename) and alias_method applies to class methods.

C++ Redefining Class Method for Specific Objects

If you want to "overwrite" a previous class definition, you can use virtual functions, and use a derived class.

Here you have some examples, particularly under the "Virtual members" title.

Good luck.

Is it possible to redefine a JavaScript class's method?

is it possible to redefine the class's method later?

Yes. However, you must not assign the new function to a property of the Person constructor, but to the instance itself:

var p2 = new Person("Sue");
p2.sayHello(); // Hello, Sue
p2.sayHello = function() {
alert('Hola, ' + this.name);
};
p2.sayHello(); // Hola, Sue

If you want to do this for all new instances automatically (and have not used the prototype for the method, which you easily could exchange as in @dystroy's answer), you will need to decorate the constructor:

Person = (function (original) {
function Person() {
original.apply(this, arguments); // apply constructor
this.sayHello = function() { // overwrite method
alert('Hola, ' + this.name);
};
}
Person.prototype = original.prototype; // reset prototype
Person.prototype.constructor = Person; // fix constructor property
return Person;
})(Person);

Override all class methods at once to do the same thing

Here is a possible way to do it using inspection of contents of TheirWrapper with dir():

import inspect


class TheirWrapper:
def __init__(self):
pass
def func1(self, a, b, c):
pass
def func2(self, d, e, f):
pass


class MyWrapper:
def addToQueue(self, localvars):
# your implementation
print(localvars)


### You can orginize this block into decorator or metaclass and make more general
def add_func(func_name):
def add(self, *args, **kwargs):
signature = inspect.signature(getattr(TheirWrapper, func_name))
bind = signature.bind(self, *args, **kwargs)
arguments = dict(bind.arguments)
arguments['func_name'] = func_name
self.addToQueue(arguments)
return add


for name in dir(TheirWrapper):
if not name.startswith('__'):
setattr(MyWrapper, name, add_func(name))
###

w = MyWrapper()
w.func1(1, 2, 3)
# prints {'self': <__main__.MyWrapper object at 0x00000000030262E8>, 'a': 1, 'b': 2, 'c': 3, 'func_name': 'func1'}

docs for inspect.signature & bind

docs for dir

Redefining methods through class inheritance in Python

I think I understand your problem and I have some suggestions for how you can resolve this:

Using "private" methods

For example:

class Parent:
def __init__(self, x):
self.x = x

def _foo(self, a=None):
a = a if a else self.x * 2

if a > 10:
over = True
else:
over = False

return over

def foo(self):
return self._foo()

class Child1(Parent):

def foo(self, y=None, condition=False):

if condition:
a = y*2
else:
a = self.x*2

return self._foo(a)

class Child2(Parent):
pass

In this example, all child classes will inherit the _foo "private" function, where they may or may not receive a value of a.

Using abstract classes

There is another solution to this problem with abstract classes (here is an example of how to do this), where you forces the child class to implement the function foo:

Important

Remembering that in the case of abstract classes, if you do not define the function decorated with @abstractmethod, you will receive an error similar to this TypeError: Can't instantiate abstract class Child2 with abstract methods foo

Example:

Python 2.x

from abc import ABCMeta, abstractmethod

class Parent:
__metaclass__ = ABCMeta

def __init__(self, x):
self.x = x

def _foo(self, a=None):
a = a if a else self.x * 2

if a > 10:
over = True
else:
over = False

return over

@abc.abstractmethod
def foo(self):
pass

class Child1(Parent):

def foo(self, y=None, condition=False):

if condition:
a = y*2
else:
a = self.x*2

return self._foo(a)

class Child2(Parent):

def foo(self):
return self._foo()

Python 3.x

class Parent(metaclass=ABCMeta):

def __init__(self, x):
self.x = x

def _foo(self, a=None):
a = a if a else self.x * 2

if a > 10:
over = True
else:
over = False

return over

@abc.abstractmethod
def foo(self):
pass

class Child1(Parent):

def foo(self, y=None, condition=False):

if condition:
a = y*2
else:
a = self.x*2

return self._foo(a)

class Child2(Parent):

def foo(self):
return self._foo()

In both examples you will have the same result by running this:

print(Child1(2).foo(10, True)) // True
print(Child1(2).foo()) // False
print(Child2(2).foo()) // False

Redefine Method of an Object

It doesn't work because b isn't an attribute belonging to the instance, it belongs to the class. So you can't delete it on the instance because it isn't there to be deleted.

>>> a = A()
>>> list(a.__dict__)
[]
>>> list(A.__dict__)
['__module__', 'b', '__dict__', '__weakref__', '__doc__']

When a.b is evaluated, Python will see that a has no instance attribute named b and fall back to the class. (It's a little more complicated because when falling back to the class, it will not simply return the method itself, but a version of the method which is bound to the instance a.)

Since you don't want to delete the method on the class, the way to go is to replace the method on the instance. I don't know why you tried to do this with __setattr__ - there is no need for that, simply assign self.b = ... as normal. The reason your attempt failed is because your lambda requires a positional parameter named self, but this parameter will not be automatically bound to the instance when you look it up, because it is an instance attribute, not a class attribute.

class A:
def b(self):
print('first')
self.b = lambda: print('second')

Usage:

>>> a = A()
>>> a.b()
first
>>> a.b()
second


Related Topics



Leave a reply



Submit