【问题标题】:classmethod and helper functions inside a python classpython类中的classmethod和helper函数
【发布时间】:2014-12-01 02:17:09
【问题描述】:

我的目标是减少我创建的类中的一些冗余。我已将问题简化为一个非常简单的示例

我现在的班级

class BigNumbers(object):
      def __init__(self, big_number):
            self.number = big_number

      @classmethod
      def make_with_sums(cls, sum_to):
            fin_num = 0

            for i in range(1, sum_to):
                  fin_num += i

            return cls( fin_num )

      @classmethod
      def make_with_product(cls, mul_to):
            fin_num = 1

            for i in range(1, mul_to):
                  fin_num *= i

            return cls( fin_num )

我想要的班级(DNRY)

class dnryNumbers(object):
      def __init__(self, big_number):
            self.number = big_number

      @classmethod
      def _make_with_helper(cls, make_meth, fin_num):
            method_dict = {'sum': lambda x, y: x + y,
                           'prod': lambda x, y: x * y
                           }
            var = 0
            for i in range(1, fin_num):
                  var = method_dict[make_meth](var, i)

            return cls( var )

      def make_with_sums(self, sum_to):

            return self._make_with_helper( 'sum', sum_to )

      def make_with_product(self, mul_to):

            return self._make_with_helper('prod', mul_to )

我的目标是使用与使用 BigNumbers 类时相同的函数调用,例如:

In [60]: bn = BigNumbers.make_with_product(10)

In [61]: bn.number
Out[61]: 362880

-- 或者--

In [63]: bn = BigNumbers.make_with_sums(10)

In [64]: bn.number
Out[64]: 45

但是当前的功能不起作用:

In [65]: bn = dnryNumbers.make_with_product(10)
TypeError: unbound method make_with_product() must be called with dnryNumbers instance as first argument (got int instance instead)

【问题讨论】:

  • 您还必须将这些方法设为类方法并调用 cls._make_with_helpers(args)
  • 您的示例似乎存在一些问题:例如,dnryNumbers.make_with_product 方法不是类方法。这是故意的吗?

标签: python oop decorator


【解决方案1】:

简单的答案:make_with_sumsmake_with_products 是类方法,而不是实例方法,因此需要这样声明。另外,请注意_make_with_helper 也需要将 starting 值作为参数;将 var 初始化为 0 将使 make_with_product 返回 cls(0),无论其参数是什么。

method_dict 是同一个字典,无论将什么输入传递给_make_with_helper,所以它应该是一个类变量:

class dnryNumbers(object):
    def __init__(self, big_number):
        self.number = big_number

    method_dict = {'sum': lambda x, y: x + y,
                   'prod': lambda x, y: x * y
                  }

    @classmethod
    def _make_with_helper(cls, make_meth, fin_num, starting_value):          
        var = starting_value
        for i in range(1, fin_num):
              var = dnryNumbers.method_dict[make_meth](var, i)
        return cls( var )

    @classmethod
    def make_with_sums(cls, sum_to):
        return cls._make_with_helper('sum', sum_to, 0)

    @classmethod
    def make_with_product(cls, mul_to):
        return cls._make_with_helper('prod', mul_to, 1)

但是现在,method_dict 只是添加了一个您不需要的额外间接层。由于函数不打算在类之外使用,只需将它们定义为“私有”方法,并直接使用对它们的引用。

class dnryNumbers(object):
    def __init__(self, big_number):
        self.number = big_number

    @staticmethod
    def _sum(x, y):
        return x + y

    @staticmethod
    def _prod(x, y):
        return x * y

    @classmethod
    def _make_with_helper(cls, make_meth, fin_num, starting_value):        
        var = starting_value
        for i in range(1, fin_num):
              var = make_meth(var, i)
        return cls(var)

      @classmethod def make_with_sums(cls, sum_to): return cls._make_with_helper(dnryNumbers._sum, sum_to, 0)

    @classmethod
    def make_with_product(cls, mul_to):
        return cls._make_with_helper(dnryNumbers._prod, mul_to, 1)

最后,值得指出的是,除非您的实际代码比此处显示的示例更复杂,否则_sum 已经可以作为operator.add 使用,_prod 只是operator.mul_make_with_helper 只是一个重新实现 reduce 内置函数(或 functools.reduce,如果是 Python 3)。

import operator
try:
    reduce
except NameError:
    from functools import reduce

class dnryNumbers(object):
    def __init__(self, big_number):
        self.number = big_number

    @classmethod
    def _make_with_helper(cls, make_meth, fin_num, starting_value):
        return cls(reduce(make_meth, range(1, fin_num), starting_value))

    @classmethod
    def make_with_sums(cls, sum_to):
        return cls._make_with_helper(operator.add, sum_to, 0)

    @classmethod
    def make_with_product(cls, mul_to):
        return cls._make_with_helper(operator.add, mul_to, 1)

【讨论】:

    【解决方案2】:

    解决方案 1:

    bn = dnryNumbers(5)
    bn.make_with_product(10)
    

    解决方案 2:

    @classmethod
    def make_with_product(cls, mul_to):
        return cls._make_with_helper('prod', mul_to )
    

    【讨论】:

    • 已编辑,因为您必须在类方法中使用 cls 而不是 self
    • 最好使用selfcls 作为函数的参数? IOW,make_with_product(cls, mul_to)——或——make_with_product(self, mul_to)?
    • @benjaminmgross 这取决于函数是什么类型的方法。常用方法使用self,类方法使用cls
    • 如果它被@classmethod修饰,你必须传递cls并将其他类方法称为cls.method_name。如果它没有被修饰,那么你必须传递 self,因此必须使用 self.method_name 或 ClassName.method_name 调用类方法
    • 我被抛弃了,因为原始(未编辑)答案有一个 @classmethod 装饰,但使用 self 作为函数参数。感谢您的澄清。
    猜你喜欢
    • 2013-02-23
    • 2012-06-28
    • 1970-01-01
    • 2021-03-30
    • 2018-04-15
    • 1970-01-01
    • 2019-08-14
    相关资源
    最近更新 更多