Adding a method to an existing object instance
In Python, there is a difference between functions and bound methods.
>>> def foo():
... print "foo"
...
>>> class A:
... def bar( self ):
... print "bar"
...
>>> a = A()
>>> foo
<function foo at 0x00A98D70>
>>> a.bar
<bound method A.bar of <__main__.A instance at 0x00A9BC88>>
>>>
Bound methods have been "bound" (how descriptive) to an instance, and that instance will be passed as the first argument whenever the method is called.
Callables that are attributes of a class (as opposed to an instance) are still unbound, though, so you can modify the class definition whenever you want:
>>> def fooFighters( self ):
... print "fooFighters"
...
>>> A.fooFighters = fooFighters
>>> a2 = A()
>>> a2.fooFighters
<bound method A.fooFighters of <__main__.A instance at 0x00A9BEB8>>
>>> a2.fooFighters()
fooFighters
Previously defined instances are updated as well (as long as they haven't overridden the attribute themselves):
>>> a.fooFighters()
fooFighters
The problem comes when you want to attach a method to a single instance:
>>> def barFighters( self ):
... print "barFighters"
...
>>> a.barFighters = barFighters
>>> a.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: barFighters() takes exactly 1 argument (0 given)
The function is not automatically bound when it's attached directly to an instance:
>>> a.barFighters
<function barFighters at 0x00A98EF0>
To bind it, we can use the MethodType function in the types module:
>>> import types
>>> a.barFighters = types.MethodType( barFighters, a )
>>> a.barFighters
<bound method ?.barFighters of <__main__.A instance at 0x00A9BC88>>
>>> a.barFighters()
barFighters
This time other instances of the class have not been affected:
>>> a2.barFighters()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: A instance has no attribute 'barFighters'
More information can be found by reading about descriptors and metaclass programming.
Add method to an instanced object
In ruby 1.9+, there's a better way of doing this using define_singleton_method
, as follows:
obj = SomeObject.new
obj.define_singleton_method(:new_method) do
"do some things"
end
JS: how to add methods to an instance of an object?
First things first, Game.help
will attach a function to the function Game
, not to instances of the Game
object.
That is, Game.help = function () { ... }
will allow Game.help()
but not new Game().help()
. This is the equivalent of a static method in most OO languages.
What you can do, but isn't very idiomatic, is to change help.js
to:
Game.prototype.help = function () {
...
}
This will attach the function as a method, so any instance of Game
can have help()
called on it.
Extending a class' prototype from another module(/file) is kind of sketchy, though, since it adds an implicit dependency (implicit preventing the browser from enforcing it, often leading to errors later when you forget about the dependency and change something that looks unrelated).
Until the ES7 extension methods proposal is finalized (and ES7) lands, you may want to consider using helper methods that take their scope as the first parameter:
help(game, ...) {
alert('help for ' + game.name);
}
This is still less than ideal, but somewhat safer.
Any elegant way to add a method to an existing object in python?
Normally, functions stored in object dictionaries don't automatically turn into boundmethods when you look them up with dotted access.
That said, you can use functools.partial to pre-bind the function and store it in the object dictionary so it can be accessed like a method:
>>> from functools import partial
>>> class Dog:
def __init__(self, name):
self.name = name
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> def bark(self): # normal function
print('Woof! %s is barking' % self.name)
>>> e.bark = partial(bark, e) # pre-bound and stored in the instance
>>> e.bark() # access like a normal method
Woof! Buddy is barking
This is a somewhat elegant way to add a method to an existing object (without needing to change its class and without affecting other existing objects).
Follow-up to Comment:
You can use a helper function to add the pre-bound function is a single step:
>>> def add_method(obj, func):
'Bind a function and store it in an object'
setattr(obj, func.__name__, partial(func, obj))
Use it like this:
>>> add_method(e, bark)
>>> e.bark()
Woof! Fido is barking
Hope this is exactly what you need :-)
Adding a property to an existing object instance
This comment gave a hint to the answer.
The follow function (inspired on 1) adds a property to a single instance of a class. It does it by creating a new class on the fly.
def attach_dyn_propr(instance, prop_name, propr):
"""Attach property proper to instance with name prop_name.
Reference:
* https://stackoverflow.com/a/1355444/509706
* https://stackoverflow.com/questions/48448074
"""
class_name = instance.__class__.__name__ + 'Child'
child_class = type(class_name, (instance.__class__,), {prop_name: propr})
instance.__class__ = child_class
Example and test:
def getter(self): print('Get!')
def setter(self, value): print('Set to {!r}!'.format(value))
def deleter(self): print('Delete!')
prop = property(getter, fset=setter, fdel=deleter)
class Foo: pass
foo = Foo()
foo2 = Foo()
attach_dyn_propr(foo, 'p', prop)
foo.p
foo2.p
... Get
... AttributeError: 'Foo' object has no attribute 'p'
Adding `__getattr__` method to an existing object instance
You can not - __dunder__
names are resolved on the type, not per-instance. Custom __getattr__
will need to be defined directly on A
.
See Special method lookup section of the datamodel documentation, specifically:
For custom classes, implicit invocations of special methods are only guaranteed to work correctly if defined on an object’s type, not in the object’s instance dictionary.
Note: if you only have a reference to an instance, not the class, it is still possible to monkeypatch the type by assigning a method onto the object returned by type(a)
. Be warned that this will affect all existing instances, not just the a
instance.
Related Topics
Ruby 'Encode': "\Xc3" from Ascii-8Bit to Utf-8 (Encoding::Undefinedconversionerror)
Why Can't Singleton Methods Be Defined on Symbols or Fixnums
When Would a Ruby Flip-Flop Be Useful
How to Make Part of a Regular Expression Optional in Ruby
Split String into a List, But Keeping the Split Pattern
Why Many People Use "-%>" Instead of "%>" in Rails
Ruby on Rails Rmagick on Windows 7
Why Does Code Need to Be Reloaded in Rails 3
What's the Point of Argv in Ruby
Why Doesn't Minitest::Spec Have a Wont_Raise Assertion
How to Add Information to an Exception Message in Ruby
Ruby on Rails "Invalid Byte Sequence in Utf-8" Due to Bot
How to Unzip a File in Ruby on Rails
Finding Out Current Index in Each Loop (Ruby)
How to Merge Two Hashes Without Overwritten Duplicate Keys in Ruby