当参数为常量时,是否适合在python类中使用闭包?

当参数为常量时,是否适合在python类中使用闭包?,python,Python,这是一个关于编码约定的问题,以及某些东西是否是“pythonic”或良好实践 假设我有这样一个python类: class ClassName: def __init__(self, arg1, arg2, arg3, arg4, arg5): self.arg1 = arg1 self.arg1 = arg2 self.arg1 = arg3 self.arg1 = arg4 self.arg1 = arg

这是一个关于编码约定的问题,以及某些东西是否是“pythonic”或良好实践

假设我有这样一个python类:

class ClassName:
    def __init__(self, arg1, arg2, arg3, arg4, arg5):
        self.arg1 = arg1
        self.arg1 = arg2
        self.arg1 = arg3
        self.arg1 = arg4
        self.arg1 = arg5

        self.some_var = 0


    def some_function1(self):
        make use of self.arg1, self.arg2
        modify self.some_var

    def some_function2(self):
        make use of self.arg3, self.arg4, self.arg5
        modify self.some_var
class C():
    def __init__(self, arg1, arg2, arg3):
        self.some_function = lambda: self._some_function(arg1, arg2)
        self.arg3 = arg3

    def _some_function(self, arg1, arg2):
        self.arg3 *= 5
        return arg1 + arg2
其中所有的
arg
s将被视为常量,用于整个类中的计算和方法

我有时使用以下模式,而不是这样做:

class ClassName:
    def __init__(self, arg1, arg2, arg3, arg4, arg5):
        self.some_var = 0

        self.some_function1 = self.some_function1(arg1, arg2)
        self.some_function2 = self.some_function2(arg3, arg4, arg5)

    def some_function1(self, arg1, arg2):
        def inner():
            make use of arg1, arg2
            modify self.some_var
        return inner

    def some_function2(self, arg3, arg4, arg5):
        def inner():
            make use of arg3, arg4, arg5
            modify self.some_var
        return inner
因为我们传递给
\uuuuu init\uuuu
方法的变量在某些计算中只是用作常量,所以有必要将它们绑定到函数闭包,而不是使它们成为成员变量(从而为它们提供更合适的范围)。然而,我认为,虽然这样做是有道理的,但这是不寻常的,对某些人来说,这一点可能并不明显


这是一种糟糕的形式,还是有意义呢?

我担心这将是非常主观的,我不能在这里要求太多的权威,所以请谨慎对待


我不认为使用闭包本质上是非语法的,但我认为用实例上的绑定闭包来屏蔽类上的方法的模式正在进入非语法的领域。这让我想知道,一个包含
某些函数1
某些函数2
定义的类是否真的是这里最自然的抽象。它甚至看起来不像他们使用
self
,即使他们将其作为参数接收?也许它们是逻辑上更独立的实体(类/函数),其实例可能由类的实例所拥有?

我不一定像您那样做,而且读起来很奇怪

对于你的问题,我有一些潜在的解决方案——一个非常难看,但我还是把它包括进去了

from functools import partial

class A():
    def __init__(self, arg1, arg2, arg3):
        self.B = self.B(self, arg1, arg2)
        self.arg3 = arg3

    class SomeFunction():
        def __init__(self, parent, arg1, arg2):
            self.parent = parent
            self.arg1 = arg1
            self.arg2 = arg2

        def __call__(self):
            self.parent.arg3 = 5
            return self.arg1 + self.arg2

class B():
    def __init__(self, arg1, arg2, arg3):
        self.some_function = partial(self.some_function, arg1=arg1, arg2=arg2)
        self.arg3 = arg3

    def some_function(self, arg1, arg2):
        self.arg3 *= 5
        return arg1 + arg2
在类
A
中将函数定义为可调用类,然后在
\uuuu init\uuuu
中将其重新定义为
A
实例上的实例。这是丑陋的一个

在类
B
中,我使用
functools.partial
将方法替换为另一个方法,但将参数固定为
arg1
arg2
。这在技术上可能与
A
中的方法类似,但更具可读性,并且不需要对函数本身进行任何更改,这是一个优点

另一种方法是:

class ClassName:
    def __init__(self, arg1, arg2, arg3, arg4, arg5):
        self.arg1 = arg1
        self.arg1 = arg2
        self.arg1 = arg3
        self.arg1 = arg4
        self.arg1 = arg5

        self.some_var = 0


    def some_function1(self):
        make use of self.arg1, self.arg2
        modify self.some_var

    def some_function2(self):
        make use of self.arg3, self.arg4, self.arg5
        modify self.some_var
class C():
    def __init__(self, arg1, arg2, arg3):
        self.some_function = lambda: self._some_function(arg1, arg2)
        self.arg3 = arg3

    def _some_function(self, arg1, arg2):
        self.arg3 *= 5
        return arg1 + arg2
因此,实际上是通过lambda定义函数,该lambda将实际操作委托给某个函数,从而使函数实现保持不变。由于您使用了“闭包”作为一个术语,您可能熟悉从rust(或rust从…)获得闭包的语言)中窃取闭包的概念,这本质上就是。 我也尝试过使用函数/类装饰器,但我认为它们不能在这里使用,因为它们不能访问调用中的参数


Imo使用
B
C
是可以的,如果选择
C
,下一个维护人员肯定会讨厌你。这个方法是从哪里来的?为什么它有一个不同的签名,这取决于我是在看一个类还是一个实例?我该如何对这个东西进行子分类


不要那样做。记住,“显性的比隐性的好”。如果您在方法中使用了
self.foo
,请将其实际称为
self.foo
,以便下一个人可以一眼看出它的定义位置。老实说,下一个人很可能就是你,六个月后,凌晨2点,当什么东西坏了,你正试图解决它。你保存的想法可能是你自己的。

我个人觉得第一个更容易阅读,如果你要将代码共享给一个更大的组,那么就使用第一个。摆脱类并按IMO的方式将参数传递给函数更合理。@rdas除非函数有副作用。该类的要点是避免每个函数都以一长串全局变量开头。“我本应该更清楚这一点的。”亚历克斯范德克勒特从你的问题中,我假设这些都是纯函数。如果不是,我宁愿选择方案1。更容易阅读。我认为第二种方法非常容易混淆,尤其是如何在
\uuuuu init\uuuuuu
中重新定义两个
函数,从重新调整函数到成为该函数……我编辑了这个问题,以包括函数具有副作用/修改/依赖于类的成员变量这一事实。