Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning a function to an object attribute

Tags:

Based on my understanding of Python's data model, and specifically the subsection "Instance Methods", whenever you read an attribute whose value is of type "user-defined function", some magic kicks in and you get a bound instance method instead of the actual, original function. That magic is why you don't explicitly pass the self parameter when you're calling a method.

But then, I would expect to be able to replace an object's method with a function with the same signature:

class Scriptable:     def __init__(self, script = None):         if script is not None:             self.script = script   # replace the method     def script(self):         print("greetings from the default script")  >>> scriptable = Scriptable() >>> scriptable.script() greetings from the default script  >>> def my_script(self): ...     print("greetings from my custom script") ... >>> scriptable = Scriptable(my_script) >>> scriptable.script() Traceback (most recent call last):   ... TypeError: script() takes exactly 1 positional argument (0 given) 

I'm creating an instance of Scriptable, and setting its script attribute to a user-defined function with a single parameter, just like what's defined in the class. So when I read the scriptable.script attribute, I would expect the magic to kick in and give me a bound instance method that takes no parameters (just like I get when I didn't replace script). Instead, it seems to be giving back the exact same function I passed in, self parameter and all. The method-binding magic isn't happening.

Why does the method-binding magic work when I define a method inside the class declaration, but not when I assign the attribute? What makes Python treat these situations differently?

I'm using Python3 if it makes any difference.

like image 274
Joe White Avatar asked Jun 25 '11 14:06

Joe White


People also ask

How do you pass a function in an object?

To pass an object as an argument we write the object name as the argument while calling the function the same way we do it for other variables. Syntax: function_name(object_name); Example: In this Example there is a class which has an integer variable 'a' and a function 'add' which takes an object as argument.

Can a function be an object property?

In JavaScript, functions are called Function Objects because they are objects. Just like objects, functions have properties and methods, they can be stored in a variable or an array, and be passed as arguments to other functions.

Can you put a function in an object JavaScript?

You can call a function inside an object by declaring the function as a property on the object and invoking it, e.g. obj. sum(2, 2) . An object's property can point to a function, just like it can point to a string, number or other values. Copied!

Can you assign a function to a variable?

In Python, we can assign a function to a variable. And using that variable we can call the function as many as times we want. Thereby, increasing code reusability. Simply assign a function to the desired variable but without () i.e. just with the name of the function.

What is object () function in Python?

Python object() Function The object() function returns an empty object. You cannot add new properties or methods to this object. This object is the base for all classes, it holds the built-in properties and methods which are default for all classes.


2 Answers

Here is how you do it:

import types class Scriptable:     def __init__(self, script = None):         if script is not None:             self.script = types.MethodType(script, self)   # replace the method     def script(self):         print("greetings from the default script") 

As ba__friend noted in the comments, methods are stored on the class object. A descriptor on the class object returns functions as bound methods when you access the attribute from a instance.

When you assign a function to a instance nothing happens special happens, so you have to wrap the function yourself.

like image 85
Jochen Ritzel Avatar answered Oct 17 '22 07:10

Jochen Ritzel


Thanks to Alex Martelli's answer here is another version:

class Scriptable:     def script(self):         print(self)         print("greetings from the default script")  def another_script(self):     print(self)     print("greetings from the another script")  s = Scriptable() s.script()  # monkey patching: s.script = another_script.__get__(s, Scriptable) s.script() 
like image 22
warvariuc Avatar answered Oct 17 '22 05:10

warvariuc