我想做这样的事情:
class X:
@classmethod
def id(cls):
return cls.__name__
def id(self):
return self.__class__.__name__
现在为类或其实例调用id()
:
>>> X.id()
'X'
>>> X().id()
'X'
显然这段确切的代码并不起作用,但有没有类似的方法让它起作用? 或任何其他解决方法,以获得这种行为没有太多" hacky"东西?
答案 0 :(得分:20)
不知道你的实际用例是什么,但你可以使用描述符做这样的事情:
class Desc(object):
def __get__(self, ins, typ):
if ins is None:
print 'Called by a class.'
return lambda : typ.__name__
else:
print 'Called by an instance.'
return lambda : ins.__class__.__name__
class X(object):
id = Desc()
x = X()
print x.id()
print X.id()
<强>输出:强>
Called by an instance.
X
Called by a class.
X
答案 1 :(得分:11)
类和实例方法存在于同一名称空间中,您不能重用这样的名称;在这种情况下,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()
)上调用它。除了类之外,该实例被忽略。
答案 2 :(得分:5)
Class().__dict__
时,Python将调用Class().foo()
中的实例属性(因为它在类&#39;之前搜索实例&#39; s __dict__
)和类绑定方法调用Class.__dict__
时在Class.foo()
中找到。
这有许多潜在的用例,但它们是否反模式是有争议的:
class Test:
def __init__(self):
self.check = self.__check
@staticmethod
def check():
print('Called as class')
def __check(self):
print('Called as instance, probably')
>>> Test.check()
Called as class
>>> Test().check()
Called as instance, probably
或者......让我们说我们希望能够滥用map()
这样的内容:
class Str(str):
def __init__(self, *args):
self.split = self.__split
@staticmethod
def split(sep=None, maxsplit=-1):
return lambda string: string.split(sep, maxsplit)
def __split(self, sep=None, maxsplit=-1):
return super().split(sep, maxsplit)
>>> s = Str('w-o-w')
>>> s.split('-')
['w', 'o', 'w']
>>> Str.split('-')(s)
['w', 'o', 'w']
>>> list(map(Str.split('-'), [s]*3))
[['w', 'o', 'w'], ['w', 'o', 'w'], ['w', 'o', 'w']]
答案 3 :(得分:2)
“类型”自Python 3.4开始提供了一些非常有趣的东西:DynamicClassAttribute
它并没有完成您所想的100%,但它似乎密切相关,您可能需要稍微调整一下我的元类,但是很麻烦,您可以使用它;
from types import DynamicClassAttribute
class XMeta(type):
def __getattr__(self, value):
if value == 'id':
return XMeta.id # You may want to change a bit that line.
@property
def id(self):
return "Class {}".format(self.__name__)
这将定义您的class属性。对于instance属性:
class X(metaclass=XMeta):
@DynamicClassAttribute
def id(self):
return "Instance {}".format(self.__class__.__name__)
这可能有点矫kill过正,尤其是如果您想远离元类。我想在自己这边探索这个技巧,所以我只想分享这个隐藏的宝石,以防您可以抛光它并使它发光!
>>> X().id
'Instance X'
>>> X.id
'Class X'
Voila ...
答案 4 :(得分:1)
在您的示例中,您可以完全删除第二个方法,因为staticmethod和class方法都做同样的事情。
如果您希望他们做其他事情:
class X:
def id(self=None):
if self is None:
# It's being called as a static method
else:
# It's being called as an instance method
答案 5 :(得分:0)
(仅适用于Python 3)详细介绍a pure-Python implementation of @classmethod
的概念,我们可以声明一个@class_or_instance_method
作为装饰器,它实际上是一个实现attribute descriptor protocol的类:
import inspect
class class_or_instance_method(object):
def __init__(self, f):
self.f = f
def __get__(self, instance, owner):
if instance is not None:
wrt = instance
else:
wrt = owner
def newfunc(*args, **kwargs):
return self.f(wrt, *args, **kwargs)
return newfunc
class A:
@class_or_instance_method
def foo(self_or_cls, a, b, c=None):
if inspect.isclass(self_or_cls):
print("Called as a class method")
else:
print("Called as an instance method")