答案是肯定的:函数是 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__ 这样的魔术方法比动态方法绑定更常见。使用此技术需要您自担风险!