gpt4 book ai didi

Python:将函数作为参数传递以初始化对象的方法。 Pythonic 与否?

转载 作者:太空宇宙 更新时间:2023-11-03 15:34:56 24 4
gpt4 key购买 nike

我想知道是否有一种可接受的方法将函数作为参数传递给对象(即在 init block 中定义该对象的方法)。

更具体地说,如果函数依赖于对象参数,将如何做到这一点。

似乎 pythonic 足以将函数传递给对象,函数就像其他任何东西一样是对象:

def foo(a,b):
return a*b

class FooBar(object):
def __init__(self, func):
self.func = func

foobar = FooBar(foo)
foobar.func(5,6)

# 30

这样行得通,一旦您引入对对象的其他属性的依赖,问题就会出现。

def foo1(self, b):
return self.a*b

class FooBar1(object):
def __init__(self, func, a):
self.a=a
self.func=func

# Now, if you try the following:
foobar1 = FooBar1(foo1,4)
foobar1.func(3)
# You'll get the following error:
# TypeError: foo0() missing 1 required positional argument: 'b'

这可能只是违反了 python 中 OOP 的一些神圣原则,在这种情况下我只需要做其他事情,但它似乎也可能被证明是有用的。

我想出了一些可能的方法来解决这个问题,我想知道哪种(如果有的话)被认为是最可接受的。

解决方案1

foobar1.func(foobar1,3)

# 12
# seems ugly

解决方案2

class FooBar2(object):
def __init__(self, func, a):
self.a=a
self.func = lambda x: func(self, x)

# Actually the same as the above but now the dirty inner-workings are hidden away.
# This would not translate to functions with multiple arguments unless you do some ugly unpacking.
foobar2 = FooBar2(foo1, 7)
foobar2.func(3)

# 21

如有任何想法,我们将不胜感激!

最佳答案

将函数传递给一个对象是可以的。这种设计没有任何问题。

但是,如果您想将该函数转换为绑定(bind)方法,则必须小心一点。如果您执行类似 self.func = lambda x: func(self, x) 的操作,您将创建一个引用循环 - self 具有对 self.func 的引用,并且 self.func 中存储的 lambda 具有对 self 的引用。 Python 的垃圾收集器确实检测引用循环并最终清理它们,但这有时会花费很长的时间。过去我的代码中有引用循环,这些程序经常使用超过 500 MB 的内存,因为 python 不会经常垃圾收集不需要的对象。

正确的解决方案是使用 weakref模块创建对 self弱引用,例如:

import weakref

class WeakMethod:
def __init__(self, func, instance):
self.func = func
self.instance_ref = weakref.ref(instance)

self.__wrapped__ = func # this makes things like `inspect.signature` work

def __call__(self, *args, **kwargs):
instance = self.instance_ref()
return self.func(instance, *args, **kwargs)

def __repr__(self):
cls_name = type(self).__name__
return '{}({!r}, {!r})'.format(cls_name, self.func, self.instance_ref())


class FooBar(object):
def __init__(self, func, a):
self.a = a
self.func = WeakMethod(func, self)

f = FooBar(foo1, 7)
print(f.func(3)) # 21

以下所有解决方案都会创建引用循环,因此不好:

  • self.func = MethodType(func, self)
  • self.func = func.__get__(self, type(self))
  • self.func = functools.partial(func, self)

关于Python:将函数作为参数传递以初始化对象的方法。 Pythonic 与否?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55413060/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com