如何确定用C编写的stdlib方法的方法类型

2024-04-19 00:15:57 发布

您现在位置:Python中文网/ 问答频道 /正文

来自inspect模块的classify_class_attrs函数可用于确定类的每个属性是什么类型的对象,包括函数是实例方法、类方法还是静态方法。举个例子:

from inspect import classify_class_attrs

class Example(object):
    @classmethod
    def my_class_method(cls):
        pass

    @staticmethod
    def my_static_method():
        pass

    def my_instance_method(self):
        pass

print classify_class_attrs(Example)

这将为Example上的每个属性输出一个Attribute对象列表,其中包含关于该属性的元数据。在这种情况下,相关的是:

Attribute(name='my_class_method', kind='class method', defining_class=<class '__main__.Example'>, object=<classmethod object at 0x100535398>)
Attribute(name='my_instance_method', kind='method', defining_class=<class '__main__.Example'>, object=<unbound method Example.my_instance_method>)
Attribute(name='my_static_method', kind='static method', defining_class=<class '__main__.Example'>, object=<staticmethod object at 0x100535558>)

然而,Python的标准库中的许多对象似乎不能以这种方式进行内省。我猜这与许多都是用C实现的事实有关。例如,datetime.datetime.nowAttribute对象描述inspect.classify_class_attrs

Attribute(name='now', kind='method', defining_class=<type 'datetime.datetime'>, object=<method 'now' of 'datetime.datetime' objects>)

如果我们将其与返回的关于Example上属性的元数据进行比较,您可能会得出结论datetime.datetime.now是一个实例方法。但它实际上是一个类方法!你知道吗

from datetime import datetime

print datetime.now()  # called from the class: 2014-09-12 16:13:33.890742
print datetime.now().now()  # called from a datetime instance: 2014-09-12 16:13:33.891161

有没有可靠的方法来确定stdlib类上的方法是静态方法、类方法还是实例方法?你知道吗


Tags: 对象方法instancefromdatetime属性objectexample
1条回答
网友
1楼 · 发布于 2024-04-19 00:15:57

我认为你可以得到很多你想要的东西,区分五种,而不依赖于inspect没有记载的任何东西:

  • Python实例方法
  • Python类方法
  • Python静态方法
  • 内置实例方法
  • 内置类方法或静态方法

但使用特定于CPython的实现细节无法区分最后两个。你知道吗

(据我所知,只有3.x在stdlib中有任何内置的静态方法……但当然,即使在2.x中,也有人可以在扩展模块中定义一个静态方法。)


inspect中可用的细节,甚至它的含义在每个版本的Python中都有些不同,部分原因是在2.x和3.x之间发生了变化,部分原因是inspect基本上是一堆随着时间的推移逐渐改进的启发式算法。你知道吗

但至少对于cpython2.6和2.7以及3.3-3.5来说,区分内建实例方法和其他两种类型的最简单方法是^{}在从类中查找的方法上。对于静态方法或类方法,这将是True;对于实例方法,这将是False。例如:

>>> inspect.isbuiltin(str.maketrans)
True
>>> inspect.isbuiltin(datetime.datetime.now)
True
>>> inspect.isbuiltin(datetime.datetime.ctime)
False

为什么这样做?嗯,isbuiltin会:

Return true if the object is a built-in function or a bound built-in method.

在实例上查找时,会绑定常规方法或类似classmethod的方法。但是在类上查找时,常规方法是未绑定的,而类classmethod方法是绑定的(类)。当然,类似staticmethod的方法在任何一种情况下都会变成一个普通的旧函数。所以,这有点间接,但总是正确的。*


类方法和静态方法怎么样?你知道吗

在cpython3.x中,内置的静态和类方法描述符在查找它们的类时都返回完全相同的类型,并且没有一个文档化的属性可以用来区分它们。即使这不是真的,我认为引用的编写方式保证了inspect中没有函数能够区分它们。你知道吗

如果我们转向描述符本身呢?是的,我们有办法区分它们……但我不认为这是语言所能保证的:

>>> callable(str.__dict__['maketrans'])
False
>>> callable(datetime.datetime.__dict__['now'])
True

为什么这样做?静态方法只是使用一个staticmethod描述符,与Python中完全一样(但是包装一个内置函数而不是函数)。但是类和实例方法使用特殊的描述符类型,而不是像Python类和实例方法那样使用classmethod包装(内置)函数和(内置)函数本身。这些特殊的描述符类型classmethod_descriptormethod_descriptor是未绑定的(类和实例)方法,也是绑定它们的描述符。这是真的有历史/实现原因,但我不认为语言引用中有任何东西要求它是真的,甚至没有暗示它。你知道吗

如果您愿意依赖实现工件,isinstance(m, staticmethod)似乎简单得多

尽管如此,除了CPython之外,还有什么实现同时具有内置的staticmethods和classmethods吗?如果不是,记住实用胜过纯洁


*它真正要测试的是该对象是否可以在没有额外参数的情况下调用,但这与文档中的“函数或绑定方法”基本相同;无论哪种方式,它都是您想要的。

相关问题 更多 >