简体   繁体   中英

how do you attach a function to an instance of a class?

I used to program in scheme: in scheme (a functional style), functions are values. you can attach a function to a "struct"- the scheme equivalent of a class in python- can you do something similar with python classes?

The answer is yes: functions are first-class values in Python, and you can attach these dynamically to classes or objects to make methods. In the case of classes this is trivial, but in the case of objects this requires a bit of setup.

To illustrate the difference, consider the following code:

class Hello:
    def say_hello(self):
        print("Hello")

print(type(Hello.say_hello))   # <class 'function'>
print(type(Hello().say_hello)) # <class 'method'>

You can see that for the same method, when it is referenced from the class it is a function type, and when it is referenced from the instance it is a method type. (Also, functions and methods are themselves classes; it's turtles all the way down.)

To dynamically add methods to classes, it it suffices to use regular functions. For example:

def say_hello(self):
    print(f"Hello, {self.name}!")

class Greeter:
    def __init__(self, name):
        self.name = name

Greeter.greet = say_hello
Greeter("Sir Robin").greet() # Prints "Hello, Sir Robin!"

However, methods on instances are bound to the instance; this means that when you call instance.method() , Python supplies the self argument to the method automatically. For normal classes Python handles the binding itself, but this does not happen when you add methods dynamically. For example, this code will result in an error:

def say_hello(self):
    print(f"Hello, {self.name}!")

class Greeter:
    def __init__(self, name):
        self.name = name

greeter = Greeter("Sir Robin")
greeter.greet = say_hello
greeter.greet() # TypeError: say_hello() missing 1 required positional argument: 'self'

Instead you have to bind the method yourself. This can be done using MethodType from the types library.

import types

def say_hello(self):
    print(f"Hello, {self.name}!")

class Greeter:
    def __init__(self, name):
        self.name = name

greeter = Greeter("Sir Robin")
greeter.greet = types.MethodType(say_hello, greeter)
greeter.greet() # Prints "Hello, Sir Robin!"

Caveat: In 99% of cases you will be better off just using regular functions or classes, as dynamically assigning methods is not usually done in Python and will likely confuse other developers. If you really need dynamic lookup, it is much more common to use magic methods like __getattr__ than dynamic method binding. Use this technique at your own risk!

class my_class:
   def my_method(self):
       print("Hello world!")

or

By using my_object.my_method = my_function or my_class.my_method = my_function you can add it dynamically. But this is discouraged, since it makes the code harder to understand.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM