我曾经在方案中编程: 在方案(函数式风格)中,函数就是值。 您可以将函数附加到“结构”- 相当于 python 中的类的方案- 你能做类似的事情吗 与 python 类? 或者,换句话说,你可以将函数传递给构造函数吗?
答案是肯定的:函数是 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__ 这样的魔术方法比动态方法绑定更常见。使用此技术需要您自担风险!
class MyClass:
def my_method(self):
print("Hello world!")
或通过使用
my_object.my_method = my_function
或
MyClass.my_method = my_function
您可以动态添加它。但这是不鼓励的,因为它会使代码更难理解。
编辑: 要获取接收 self
参数的绑定方法,您需要将其添加到类中。这也会反映在现有实例上。如果直接将该方法添加到实例中,调用时不会收到
self
。