如何将函数附加到类的实例?

问题描述 投票:0回答:2

我曾经在方案中编程: 在方案(函数式风格)中,函数就是值。 您可以将函数附加到“结构”- 相当于 python 中的类的方案- 你能做类似的事情吗 与 python 类? 或者,换句话说,你可以将函数传递给构造函数吗?

python class functional-programming
2个回答
5
投票

答案是肯定的:函数是 Python 中的一等值,您可以将它们动态附加到类或类实例来创建方法。对于类来说,这很简单,但对于实例来说,这需要一些设置。

为了说明差异,请考虑以下代码:

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

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

可以看到,对于同一个方法,从类中引用时是函数类型,从实例中引用时是方法类型。 (此外,函数和方法本身就是类;它一直都是乌龟。)

要动态向类添加方法,使用常规函数就足够了。例如:

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!"

但是,实例上的方法是绑定到实例上的;这意味着当您调用

instance.method()
时,Python 会自动向该方法提供
self
参数。对于普通类,Python 会自行处理绑定,但当您动态添加方法时,这种情况不会发生。例如,此代码将导致错误:

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'

您必须自己绑定该方法。这可以使用类型库中的MethodType来完成。

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!"

警告:在 99% 的情况下,您最好只使用常规函数或类,因为动态分配方法通常不会在 Python 中完成,并且可能会让其他开发人员感到困惑。如果您确实需要动态查找,那么使用像 __getattr__ 这样的魔术方法比动态方法绑定更常见。使用此技术需要您自担风险!


1
投票
class MyClass: def my_method(self): print("Hello world!")

通过使用

my_object.my_method = my_function

MyClass.my_method = my_function
 您可以动态添加它。但这是不鼓励的,因为它会使代码更难理解。

编辑: 要获取接收 self

 参数的绑定方法,您需要将其添加到类中。这也会反映在现有实例上。如果直接将该方法添加到实例中,调用时不会收到
self

© www.soinside.com 2019 - 2024. All rights reserved.