【问题标题】:calling Python static methods objects [duplicate]调用Python静态方法对象[重复]
【发布时间】:2014-03-09 05:49:34
【问题描述】:

我希望这会奏效:

class A(object):

    @classmethod
    def do_it(cls, spam, eggs):
        if spam in A.ways_to_do_it:
            A.ways_to_do_it[spam](eggs)
        super(A, cls).do_it(spam, eggs)

    @staticmethod
    def do_it_somehow(eggs):
        ...

    @staticmethod
    def do_it_another_way(eggs):
        ...

    ways_to_do_it = {
        'somehow': do_it_somehow,
        'another_way': do_it_another_way,
    }

但它引发了TypeError: 'staticmethod' object is not callable。我想检查staticmethod 以找出一些东西,但它是内置的。我希望很清楚我想在这里实现什么。

你有什么想法可以做得很好吗?我知道将这些 @staticmethods 设为全局可以解决问题,但这会在我的模块中造成混乱。

P。 S. do_it_somehowdo_it_another_way 将仅从 A.do_it 调用。

【问题讨论】:

  • 至于那些试图将这个问题标记为重复的人:我认为这个问题比引用的问题更普遍——这是一个极端情况,描述了 OP 在此处遇到的相同问题。
  • @jsbueno:更一般的情况也包含在重复中。

标签: python function object static-methods class-method


【解决方案1】:

Python 有一个 descriptor 对象的概念,这些对象至少具有__get__ 方法。当从类或实例中检索这些对象作为属性时,这些对象的行为会有所不同(调用它们的__get__ 方法。)

@staticmethod 装饰器将后续函数声明转换为具有静态方法行为的描述符 - 但所述行为仅在将对象作为类属性检索时才可用。相反,上面的代码直接引用了对象。

既然你的字典还有其他(类)方法可以工作,你最好 类创建之后检索您想要的方法,以便通过描述符协议检索每个方法:

class A(object):

    @classmethod
    def do_it(cls, spam, eggs):
        if spam in A.ways_to_do_it:
            A.ways_to_do_it[spam](eggs)
        super(A, cls).do_it(spam, eggs)

    @staticmetod
    def do_it_somehow(eggs):
        ...

    @staticmetod
    def do_it_another_way(eggs):
        ...

A.ways_to_do_it = {
        'somehow': A.do_it_somehow,
        'another_way': A.do_it_another_way,
    }

您可以在创建类之前检索您的静态方法,调用do_it_another_way.__get__(object, None) - 因为它不需要类引用(但需要一个有效的类作为第一个参数)。但是,如果您希望您的字典也指向已定义的类方法,则必须在类创建之后获取它们:Python 无法在类创建之前为您创建“绑定类方法”。

在类体内创建对类/静态方法的其他直接引用是可行的:

class A(object):
   @staticmethod
   def foo(): ...

   bar = foo

因为通过这种方式,bar 也将通过描述符协议获取。但由于你有一个间接字典,你必须自己处理描述符__get__ 调用。

查看http://docs.python.org/2/reference/datamodel.html#implementing-descriptors 了解更多信息。 (这就是 classmethod、staticmethod 装饰器所做的,因为您也想知道)。

【讨论】:

  • 而在 Python 3 中,所有(非内置)函数都是描述符对象。 class A: pass; a = lambda self: id(self); A.a = a 将导致 a 成为类对象上的函数和任何实例上的绑定方法(即使是在将函数设置为类的属性之前创建的实例,假设它们还没有隐藏函数),你甚至可以通过显式使用 __get__: anA = A(); aa = a.__get__(anA); aa() 来获得相当于 JavaScript 的 bind
【解决方案2】:

试试这样:

class A(object):

    @classmethod
    def do_it(cls, spam, eggs):
        if spam in A.ways_to_do_it:
            A.ways_to_do_it[spam](eggs)
        super(A, cls).do_it(spam, eggs)

    @staticmethod
    def do_it_somehow(eggs):
        ...

    @staticmethod
    def do_it_another_way(eggs):
        ...

A.ways_to_do_it = {
    'somehow': A.do_it_somehow,
    'another_way': A.do_it_another_way,
}

在完成类的构造之前引用一个类会变得很棘手,因此最简单的方法是在类定义结束后立即向其中添加内容。

【讨论】:

  • 您的回答使它起作用,并描述了它为何适用于类方法的高级别的原因。但是静态方法不需要类引用,因此可以在类准备好之前引用它们。检查我的答案,看看发生了什么。
猜你喜欢
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 2018-05-07
相关资源
最近更新 更多