14

我使用 Python 已经有一段时间了,我发现将方法声明为静态的语法很奇特。

将声明一个常规方法:

def mymethod(self, params)
   ...
   return

声明了一个静态方法:

def mystaticethod(params)
   ...
   return
mystaticmethod = staticmethod(mystaticmethod)

如果您不添加静态方法行,编译器会抱怨自我丢失。

这是一种非常复杂的方法,可以做一些非常简单的事情,在其他语言中只需使用关键字和声明语法即可。谁能告诉我这种语法的演变?这仅仅是因为在现有语言中添加了类吗?

由于我可以将 staticmethod 行移到课程的后面,这也表明解析器在簿记方面正在加倍努力。

请注意,我知道后来添加的装饰器语法,我很想知道从语言设计的角度来看原始语法是如何产生的。我能想到的唯一想法是静态方法应用程序调用了一个将函数对象转换为静态方法的操作。

4

8 回答 8

12

静态方法是在类出现很久之后才添加到 Python 中的(类很早就添加了,甚至可能在 1.0 之前;静态方法直到大约 2.0 的某个时候才出现)。它们被实现为对普通方法的修改——您从函数创建静态方法对象以获取静态方法,而编译器默认生成实例方法。

与 Python 中的许多东西一样,静态方法被引入,然后随着人们使用它们并想要更好的语法进行改进。第一轮是一种引入语义的方式,而无需向语言中添加新语法(Python 对语法更改非常有抵抗力)。我不是 Guido,所以我不确定他脑子里在想什么,这有点推测,但是 Python 往往会缓慢移动,逐步发展,并随着他们获得更多经验而改进事物(特别是,在找到正确的方法之前,他们不喜欢添加东西。这可能是为什么从一开始就没有针对静态方法的特殊语法的原因)。

不过,正如 mjv 所指出的,现在有一种更简单的方法,通过在 2.2 或 2.3 中添加的一些称为“装饰器”的语法糖:

@staticmethod
def mystaticmethod(params)
    ...
    return

@staticmethod语法是放在mystaticmethod = staticmethod(mystaticmethod)方法定义之后的糖。

于 2009-09-25T14:24:47.687 回答
11

voyager 和 adurdin 在他们之间很好地解释了发生的事情:随着 Python 2.2 中新型类和描述符的引入,出现了新的和深层的语义可能性——以及最明显有用的示例(静态方法、类方法, 属性)由内置描述符类型支持,没有任何新语法@foo装饰器的语法是在随后的几个版本中添加的,一旦新描述符充分证明了它们在现实世界中的有用性)。我真的没有资格引导 Guido(当你需要他时,Tim Peters 在哪里!-),但我当时已经是一名 Python 提交者并参与了这些开发,我可以确认这确实发生了。

voyager 对此提醒他 C 的观察是正确的:我一直声称 Python 比任何模仿C语法的语言(大括号、if/while 之后的括号)更能捕捉到“C 的精神” , ETC)。“C 的精神”实际上在 ISO C 标准的(非规范性)基本原理部分中进行了描述,包括五个原则(其中一个都不需要大括号!-)我声称 Python 与 4.5 匹配(有几个关于我在“Python for Programmers”上的演示网络,如果你好奇的话,我会在其中介绍)。

特别是,C 的精神“只提供一种操作方式”与 Python 的禅宗“应该有一种——最好只有一种——明显的方式来做”——以及 C 和 Python,我相信, 是仅有的两种广泛采用这种统一性和非冗余性的设计理想的广泛语言(这是一个理想,并且不能明智地达到 100% - 例如,如果 a 和 b 是整数,则 a+b 和 b+最好是两种同样明显的方法来得到它们的总和!-)——但这是一个目标!-)。

于 2009-09-25T15:13:08.680 回答
4

python 中的静态方法可以追溯到 Python 2.2 中所谓的“新式类”的引入。在此之前,类的方法只是普通的函数,存储为类的属性:

class OldStyleClass:
    def method(self):
        print "'self' is just the first argument of this function"

instance = OldStyleClass()
OldStyleClass.method(instance) # Just an ordinary function call
print repr(OldStyleClass.method) # "unbound method..."

对实例的方法调用经过特殊处理,可以自动将实例绑定到函数的第一个参数:

instance.method() # 'instance' is automatically passed in as the first parameter
print repr(instance.method) # "bound method..."

在 Python 2.2 中,大部分类系统都被重新思考和重新设计为“新型类”——继承自object. 新型类的特征之一是“描述符”,本质上是类中的一个对象,负责描述、获取和设置类的属性。描述符有一个__get__方法,该方法被传递给类和实例,并且应该返回类或实例的请求属性。

描述符使得使用单个 API 实现类属性的复杂行为成为可能,例如属性、类方法和静态方法。例如,staticmethod描述符可以这样实现:

class staticmethod(object):
    """Create a static method from a function."""

    def __init__(self, func):
        self.func = func

    def __get__(self, instance, cls=None):
        return self.func

将此与普通方法的假设纯 Python 描述符进行比较,该描述符默认用于类属性中的所有普通函数(这与从实例中查找方法不完全一样,但它确实处理了自动“自我”争论):

class method(object):
    """Create a method from a function--it will get the instance
    passed in as its first argument."""

    def __init__(self, func):
        self.func = func

    def __get__(self, instance, cls=None):
        # Create a wrapper function that passes the instance as first argument
        # to the original function
        def boundmethod(*args, **kwargs):
            return self.func(self, *args, **kwargs)
        return boundmethod

因此,当您编写 时method = staticmethod(method),实际上是在创建一个新的描述符,其工作是原封不动地返回原始函数,并将此描述符存储在类的“方法”属性中。

如果仅仅为了恢复原始功能,这似乎需要做很多工作——你是对的,它是。但是由于正常的方法调用是默认情况,静态方法和类方法需要分别实现,而描述符提供了一种通过一个简单的 API 启用这些和其他复杂行为的方法。

正如其他人已经指出的那样,Python 2.4 中引入的装饰器语法提供了一种更方便的方式来声明静态方法,但这只是一种语法上的便利,并没有改变静态方法的工作方式。

有关新样式的更多详细信息,请参见http://www.python.org/doc/2.2.3/whatsnew/sect-rellinks.htmlhttp://users.rcn.com/python/download/Descriptor.htm类和描述符。

于 2009-09-25T14:54:12.547 回答
3

Guido 一直对向语言中添加新结构持谨慎态度。当提出静态方法时,表明您已经可以做到(staticmethod()从 2.2 开始就有一个装饰器),您只是没有语法糖。

如果您阅读 PEP,您可以看到所有关于添加内容的讨论。一方面,我喜欢这种方法。它让我想起了C没有不必要的关键字。

当装饰器的新语法添加到 Python 2.4 时,您可以使用具有更简洁语法的现有装饰器。

无论如何,如果您必须维护旧系统,它们并没有太大的不同。

#>2.4
class MyClass(object):
    @staticmethod
    def mystaticmethod(params)
        pass
        return

#<2.4
class MyClass(object):

    def mystaticmethod(params)
        '''Static Method'''
        pass
        return
    staticmethod(mystaticmethod)

我建议您在静态方法中添加注释或文档字符串,是一种静态方法。

于 2009-09-25T14:48:39.123 回答
2

从 Python 2.4 开始,还可以使用装饰器,如下所示:

   @staticmethod
   def mystaticethod(params)
      ...
      return

但是我对这个特性的起源没有任何见解,正如最初在语言中实现的那样。但话又说回来,我不是荷兰人 :-) 请看 Michael E 在这篇文章中的回应,关于静态方法在 Python 发展过程中的迟到。

顺便说一句,尽管它们很简单,但

@MyDeco
 一些对象

   仅仅是“语法糖”

  我的装饰(一些对象)

装饰器可以用于许多其他很酷的事情!

于 2009-09-25T14:18:00.837 回答
2

The static method situation in Python is a rather direct consequence of the design decisions of first-class everything and everything is an executable statement. As others have stated, staticmethod only became available with new semantics allowed by the Python 2.2 descriptor protocol and made syntactically sweeter by function decorators in Python 2.4. There's a simple reason why static methods have gotten so little attention - they don't extend the power of the language in any way and make syntax only slightly better. Semantically they are the equivalent of plain old functions. That's why they were only implemented when the power of the language grew enough to make them implementable in terms of other language features.

于 2009-09-25T16:12:03.200 回答
1

Guido 撰写了博客The History of Python。我认为有一种方法可以联系他并请求扩展这个特定的主题。

于 2009-09-25T14:31:29.993 回答
0

也许,设计最初并没有考虑到当可以使用函数时需要静态方法。由于 python 没有数据隐藏,所以实际上不需要静态方法,而是使用类作为命名空间。

于 2009-09-25T14:24:51.533 回答