python - Python:将函数作为参数传递以初始化对象的方法。Pythonic 与否?
问题描述
我想知道是否有一种可接受的方式将函数作为参数传递给对象(即在init块中定义该对象的方法)。
更具体地说,如果函数依赖于对象参数,将如何做到这一点。
似乎 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
任何想法,将不胜感激!
解决方案
将函数传递给对象很好。这种设计没有任何问题。
但是,如果您想将该函数转换为绑定方法,则必须小心。如果您执行类似的操作self.func = lambda x: func(self, x)
,您将创建一个引用循环 -self
具有对 的引用self.func
,并且存储在其中的 lambdaself.func
具有对 的引用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)
推荐阅读
- gensim - 通过指定单词/主题分布来创建 Gensim 模型
- json - 如何动态地将值传递给组件
- sql - EFCore 模型无效。以多种方式引用另一个类似乎是问题所在?
- macos - Apache多个虚拟主机指向不同的目录
- java - 如何从同一个 Java 项目的 jar 文件中运行 ant 命令?
- haskell - 使用任一时如何对条件进行排序
- node.js - AWS Elasticsearch 和 Cognito - 如何允许 Cognito 用户创建私有索引?
- vue.js - 使用 Nuxt 为 css-loader 扩展 Webpack 的问题
- algorithm - 为什么第一个决策有更好的覆盖测试用例?
- testing - 使用 Intellij 运行测试时“未收到测试事件”