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
Amazon S3 - How to Fix 'The Request Signature We Calculated Does Not Match the Signature' Error
Notice: Trying to Get Property of Non-Object Error
Find Highest Value in Multidimensional Array
Fpdf Error: Some Data Has Already Been Output, Can't Send Pdf
Trying to Get Property of Non-object In
How to Login in With Curl and Ssl and Cookies
What Does "1" Mean At the End of a PHP Print_R Statement
Redefine Built in PHP Functions
Reference - Composer Error "Your PHP Version Does Not Satisfy Requirements" After Upgrading PHP
How to Combine Two Arrays Together
PHP: Warning: Sort() Expects Parameter 1 to Be Array, Resource Given
Jquery Ui Sortable, Then Write Order into a Database
On Delete Cascade With Doctrine2
Magento - Quote/Order Product Item Attribute Based on User Input