【问题标题】:Is there a way to make a function from a method inside a class有没有办法从类中的方法创建函数
【发布时间】:2021-04-01 00:12:13
【问题描述】:

我有一个数字类,其中有两个方法:

    def digit_sum(self):
        """Returns the sum of all the digits"""
        str_num = str(self.num)
        ans = Number(0)
        for item in str_num:
            ans += Number(item)
        return ans

    def digit_product(self):
        """Returns the sum of all the digits"""
        str_num = str(self.num)
        ans = Number(1)
        for item in str_num:
            ans *= Number(item)
        return ans

我希望这些方法可以像函数一样被访问,例如,我会输入x = digit_product(Number(54)) 有没有办法在python中做到这一点?

【问题讨论】:

  • 你能解释一下为什么这是可取的吗?这些函数/方法显然对非Numbers 没有任何意义,那为什么不直接做Number(54).digit_product() 呢?这闻起来是an XY problem
  • 能否请您包括Number 类定义的其余部分,即__init__ 和相关属性?
  • 我可以想象您可能想要这样做的一个原因是将作为参数传递给mapsort 或类似的。例如。 numbers.sort(key=Number.digit_product) 根据数字产品对数字列表进行排序。
  • 实际上,参数不需要是Number;那时,我们基本上是在讨论一个替代构造函数,像 x = Number.digit_product(54) 一样访问

标签: python function class oop


【解决方案1】:

您已经可以将函数作为类的属性访问,如下所示:

Number.digit_product(Number(54))

如果您希望能够以 digit_product 的名称访问它,您可以这样做:

digit_product = Number.digit_product

【讨论】:

  • 如果要作为类的属性访问,则应装饰@classmethod@staticmethod
  • 如果您这样做,您将无法将其作为实例方法调用为instance.method()。无需将其设为静态或类方法即可使其也可用作类的属性。
  • @sabik:事实上,在这种特定情况下,使用staticmethodclassmethod 是错误的; self 参数被显式传递,而不是像方法调用语法中那样隐式传递,并且无法接收它(或尝试传递类,然后将实例作为参数)会中断。
  • @sabik 这是self 的值绑定。对于instance 方法barfoo.bar()type(foo).bar(foo) 是等效的(忽略继承)。对于类方法barfoo.bar()type(foo).bar(type(foo)) 是等价的。对于静态方法barfoo.bar()type(foo).bar() 是等价的。
  • self 只是一个参数名称。您可以使用名为self 的参数定义一个常规函数,它会正常工作,并且您可以定义一个方法,其中第一个参数被称为self 以外的其他名称(如果您仍然会绑定到实例将其作为实例方法调用)。您实际上不应该做任何这些事情,因为它们会令人困惑,但重要的是要了解调用该参数 self 只是一种约定; self 这个名字不会改变调用函数的语义。
【解决方案2】:

假设这些方法是在Number 上定义的,它们已经是函数;你已经可以这样做了:

x = Number.digit_product(Number(54))

如果您遇到多个类可能提供同名方法的情况,但您只想调用与该类关联的方法,您可以编写一个简单的包装器:

def digit_product(x):
    return x.digit_product()

它将分派到适当的方法,同时仍然允许您以顶级函数语法调用它。如果它变得更复杂(并非所有类型都有相同的方法,但您希望它适用于所有类型),functools.singledispatch 允许您专门化与特定类型相关的调用,而所有非专门化调用尝试默认代码路径,例如:

from functools import singledispatch

@singledispatch
def digit_product(x):
    return x.digit_product()

@digit_product.register
def _(x: MyWeirdNumber):
    return x.my_weird_digit_product()

【讨论】:

    猜你喜欢
    • 2019-02-01
    • 2011-11-30
    • 2011-11-18
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 2013-09-10
    • 1970-01-01
    • 2021-04-18
    相关资源
    最近更新 更多