首页 > 解决方案 > 类方法输入变量

问题描述

通常,当我在 Python(和其他语言)中创建类时,我很难决定哪种做法更好:(a)在我的方法函数中使用实例变量,或者(b)在函数定义中列出输入变量。

(一个)

    class ClassA(object):
        def __init__(self, a):
            self.variable_a = a

        def square_a(self):
            return self.variable_a ** 2

(二)

   class ClassB(object):
        def __init__(self, b):
            self.variable_b = b

        def square_b(self, input_var):
            return input_var ** 2

这些示例非常简单明了,但强调了我对哪个更好的想法感到困惑。此外,在方法之外设置实例变量是否禁忌__init__?例如:

   class ClassC(object):
        def __init__(self, c):
            self.variable_c = c

        def square_c(self):
            self.square_of_c = self.variable_c ** 2

编辑:我理解这个问题有点模糊的性质,但我问它是因为很难知道人们期望在我为协作项目编写的源代码中看到什么。如果我给出的一个或多个示例是反模式,我的想法是这个问题将为我提供有用的见解。

从 PEP 20 开始:

There should be one-- and preferably only one --obvious way to do it.

标签: pythonpython-3.xoop

解决方案


在这个例子中,(b) 作为成员函数不是很有用。它可以很容易地成为一个免费功能:

def square(input_var):
    return input_var ** 2

这可以说是一个更好的接口,因为它可以在任何上下文中使用,而不仅仅是来自ClassB.

self.variable_a一般来说,如果我知道函数应该需要的唯一输入,我会选择 (a) 。如果我想让它与任何东西一起工作并且它不依赖于类中的任何东西,我会让它成为一个自由函数。如果我想让它与任何东西一起工作,但它确实依赖于某些类状态,那么让它成为一个将输入作为参数的成员。例如,如果ClassA同时包含 avariable_a和 avariable_b怎么办?您不能使用square_ato modify variable_b,这可能需要也可能不需要,具体取决于实际用例。

此外,在init方法之外设置实例变量是否禁忌?

不,但通常最好确保所有成员都在类实例化时的某个地方初始化。即使您只是将您的成员初始化为None. None检查成员变量是否比尝试确定它是否已定义要容易得多。

编辑:另外几个例子:

# Here a free function makes the most sense because the operation is 'pure'
# i.e. it has no side effects and requires no state besides its input arguments
def square(value):
    return value ** 2

class LoggedCalculator(object):
    def __init__(self, logger):
        self.__logger = logger

    # (a) makes more sense here because it depends on class state and doesn't need to change
    # its behavior by taking in some parameter
    def get_logger(self):
        return self.__logger

    # (b) makes more sense here because we rely on a mixture of class state and some other input
    def square(self, value):
        result = square(value) # Re-use free function above
        self.__logger.info('{}^2 = {}'.format(value, result))
        return result

calc = LoggedCalculator(logging.getLogger())
calc.square(4)  # This requires an instance of LoggedCalculator
square(2)       # This can be called anywhere, even if you don't have a logger available

推荐阅读