gpt4 book ai didi

python - classmethod 和 instancemethod 同名

转载 作者:太空狗 更新时间:2023-10-29 19:30:27 30 4
gpt4 key购买 nike

我想做这样的事情:

class X:

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

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

现在为类或其实例调用 id():

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

显然,这个确切的代码不起作用,但是否有类似的方法让它起作用?

或者在没有太多“hacky”东西的情况下获得这种行为的任何其他解决方法?

最佳答案

类和实例方法存在于同一个命名空间中,你不能重复使用这样的名称; id 的最后一个定义在这种情况下会赢。

类方法将继续在实例上工作,但是,不需要创建一个单独的实例方法;只需使用:

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

因为方法继续绑定(bind)到类:

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

这是明确记录的:

It can be called either on the class (such as C.f()) or on an instance (such as C().f()). The instance is ignored except for its class.

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

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

descriptor API是 Python 如何将函数绑定(bind)为方法,并绑定(bind) classmethod类的对象;查看descriptor howto .

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

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并且只重新定义它如何处理绑定(bind),将原始实现委托(delegate)给 instance is None , 和标准函数 __get__否则实现。

请注意,在方法本身中,您可能需要测试它绑定(bind)的内容。 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 object at 0x10ac7d580>'

另一种实现可以使用两个函数,一个用于绑定(bind)到一个类,另一个用于绑定(bind)到一个实例:

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 值的区分,其中模型中的列对象会像这样切换行为;查看他们的 Hybrid Attributes documentation .此实现遵循与我的 hybridmethod 完全相同的模式。上面的类。

关于python - classmethod 和 instancemethod 同名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28237955/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com