当前位置: 首页 > 面试题库 >

classmethod和instancemethod的名称相同吗?

李甫
2023-03-14
问题内容

我想做这样的事情:

class X:

    @classmethod
    def id(cls):
        return cls.__name__

    def id(self):
        return self.__class__.__name__

现在调用id()类或它的实例:

>>> X.id()
'X'
>>> X().id()
'X'

显然,此确切的代码不起作用,但是是否有类似的方法可以使它起作用?还是任何其他解决方法都可以在没有太多“怪异”内容的情况下获得这种行为?


问题答案:

类和实例方法位于同一个命名空间中,并且您不能像这样重用名称。id在这种情况下,最后的定义将获胜。

类方法将继续在实例上运行,但是, 无需 创建单独的实例方法。只需使用:

class X:
    @classmethod
    def id(cls):
        return cls.__name__

因为方法继续绑定到该类:

>>> class X:
...     @classmethod
...     def id(cls):
...         return cls.__name__
... 
>>> X.id()
'X'
>>> X().id()
'X'

明确记录了以下内容:

可以在类(如C.f())或实例(如C().f())上调用它。该实例除其类外均被忽略。

如果确实需要区分绑定到类和实例

如果您需要一种方法,使其根据使用的位置而有所不同;在类上访问时绑定到一个类,在实例上访问时绑定到该实例,您需要创建一个自定义 描述符对象

该描述符的API是Python的如何导致功能被绑定为方法,并结合classmethod对象的类;
请参阅描述符说明。

您可以通过创建具有__get__方法的对象来为方法提供自己的描述符。这是一个简单的方法,可根据上下文切换方法所绑定的对象,如果to的第一个参数__get__None,则描述符将绑定到一个类,否则它将绑定到一个实例:

class class_or_instancemethod(classmethod):
    def __get__(self, instance, type_):
        descr_get = super().__get__ if instance is None else self.__func__.__get__
        return descr_get(instance, type_)

这将重用classmethod并且仅重新定义其处理绑定的方式,将的原始实现委派给instance is None__get__否则将其委派给标准函数实现。

请注意,在方法本身中,您可能随后必须测试其绑定的对象。isinstance(firstargument, type)这是一个很好的测试:

>>> class X:
...     @class_or_instancemethod
...     def foo(self_or_cls):
...         if isinstance(self_or_cls, type):
...             return f"bound to the class, {self_or_cls}"
...         else:
...             return f"bound to the instance, {self_or_cls"
...
>>> X.foo()
"bound to the class, <class '__main__.X'>"
>>> X().foo()
'bound to the instance, <__main__.X html" target="_blank">object at 0x10ac7d580>'

一种替代实现可以使用 两个 函数,一个函数绑定到类时,另一个函数绑定到实例时:

class hybridmethod:
    def __init__(self, fclass, finstance=None, doc=None):
        self.fclass = fclass
        self.finstance = finstance
        self.__doc__ = doc or fclass.__doc__
        # support use on abstract base classes
        self.__isabstractmethod__ = bool(
            getattr(fclass, '__isabstractmethod__', False)
        )

    def classmethod(self, fclass):
        return type(self)(fclass, self.finstance, None)

    def instancemethod(self, finstance):
        return type(self)(self.fclass, finstance, self.__doc__)

    def __get__(self, instance, cls):
        if instance is None or self.finstance is None:
              # either bound to the class, or no instance method available
            return self.fclass.__get__(cls, None)
        return self.finstance.__get__(instance, cls)

这是带有可选实例方法的类方法。像使用property对象一样使用它;用以下方法装饰实例方法@<name>.instancemethod

>>> class X:
...     @hybridmethod
...     def bar(cls):
...         return f"bound to the class, {cls}"
...     @bar.instancemethod
...     def bar(self):
...         return f"bound to the instance, {self}"
... 
>>> X.bar()
"bound to the class, <class '__main__.X'>"
>>> X().bar()
'bound to the instance, <__main__.X object at 0x10a010f70>'

就个人而言,我的建议是谨慎使用此方法。基于上下文更改行为的完全相同的方法可能会令人困惑。但是,有一些用例,例如SQLAlchemy在SQL对象和SQL值之间的区分,其中模型中的列对象会切换这样的行为。请参阅其_混合属性_文档。其实现遵循与我hybridmethod上面的类完全相同的模式。



 类似资料:
  • 问题内容: H2似乎在带引号的名称和不带引号的名称之间有所不同。有没有办法让他们以相同的方式对待他们? 这是我已经完成的测试: 这是查询: 我该怎么做才能使这些查询与H2一起使用? 问题答案: 根据SQL规范的要求,H2中的引号名称区分大小写。这意味着它将起作用: 但这不会: 在H2中,不带引号的名称不区分大小写。它们通常会转换为大写字母(例如在Oracle和其他数据库中)。这意味着声明 与…相同

  • 问题内容: 在我的Java应用程序中,我使用第三方库。 但是,我发现有些奇怪,有一些嵌套的程序包,有些类的名称可能与程序包的名称相同。 恐怕我不清楚。这是一个例子: 包 在“ com.xx.a”内部有一个名为“ a”的类。 因此,如果我想将此类称为“ a” … 我写: 然后,IDE将认为我的意思是软件包“ com.xx.a.a”。 那我就不能打电话了。 我想知道为什么? 顺便说一句,图书馆提供者似

  • 在Spring IOC中,bean的两个定义(具有相同的名称和类)是否有效? 我有两个bean定义文件包含在web中。xml。参见下面的示例。 应用Context-beans1.xml applicationContext-beans2。xml 到目前为止,我还没有遇到任何问题。但是,这可能会影响到多线程和集群的现实环境吗? 注意:这两个XMLs都被加载,因为我可以使用在这两个XMLs中定义的其他

  • 问题内容: 我的问题是为什么我不能再次调用该函数?或者,如何做到这一点? 假设我有这个功能: 我称之为: 我得到4。 但是,假设我声明了一个与该函数同名的变量(错误): 现在,如果我尝试这样做: 要么: 我将收到此错误:“ TypeError:’int’对象不可调用” 无法将变量“ a”分配给函数? 问题答案: 完成此操作后: 不再是一个 函数 ,而只是一个 整数 (您已将其重新分配!)。因此,很

  • 我不太清楚kotlin是如何管理属性名和主构造函数参数名的。如果我写了相同的属性名和参数名,那么kotlin编译器会给出一个错误。 它给出了这个错误。 但是,当我更改属性的名称或更改主构造函数的参数名称时,代码将工作并编译。 这将工作或编译罚款。 这背后的原因是什么?为什么主构造函数的参数名和属性名不能相同?

  • 假设您有2个包,并且有名为-Test的公共类。 第一个包。测试 第二包测试 它们中的每一个都有实例变量-x。 在第一种情况下-int x=2; 在第二种情况下-int x=3; 我想导入FirstPackage。在第二个包内测试。测试并打印值为2的x。 我的代码: 但是输出是3。如何打印?