Python Duck类型和类方法(或者,如何使用来自类和实例的方法?)

Python Duck类型和类方法(或者,如何使用来自类和实例的方法?),python,class-method,duck-typing,Python,Class Method,Duck Typing,我有一些代码,我想互换地传递实例或类。在该代码中,我要做的就是调用一个我希望类和实例都具有的方法(下面示例中的方法go()) 不幸的是,我无法创建与常规方法同名的classmethod。。。见下面的例子。我最初期望第二个调用生成a,而不是b 有没有关于如何实现这一目标的建议 Type "help", "copyright", "credits" or "license" for more information. >>> class A(object): ... def

我有一些代码,我想互换地传递实例或类。在该代码中,我要做的就是调用一个我希望类和实例都具有的方法(下面示例中的方法
go()

不幸的是,我无法创建与常规方法同名的classmethod。。。见下面的例子。我最初期望第二个调用生成
a
,而不是
b

有没有关于如何实现这一目标的建议

Type "help", "copyright", "credits" or "license" for more information.
>>> class A(object):
...     def go(self):
...             print "a"
...     @classmethod
...     def go(cls):
...             print "b"
... 
>>> a=A()
>>> a.go()
b
>>> A.go()
b

比如说:

import inspect

class A(object):
   @staticmethod
   def go(obj):
      if inspect.isclass(obj):
         print 'class'
      else:
         print 'instance'

A.go(int) # class
A.go(1)   # instance
A.go(A)   # class
A.go(A()) # instance

您可以使用巧尽心思构建的
\uuu get\uuu()
方法创建自己的方法类型

在此方法中,您可以执行以下操作:

class combimethod(object):
    def __init__(self, func):
        self._func = func
    def classmethod(self, func):
        self._classfunc = classmethod(func)
        return self
    def __get__(self, instance, owner):
        if instance is None:
            return self._classfunc.__get__(instance, owner)
        else:
            return self._func.__get__(instance, owner)

class A(object):
    @combimethod
    def go(self):
        print "instance", self
    @go.classmethod
    def go(cls):
        print "class", cls

a=A()
print "i:",
a.go()
print "c:",
A.go()

注:上述测试不是很彻底,但似乎有效。然而,它应该被视为一种“接近伪代码的解决方案”,而不是一种解决方案。它应该给你一个实现目标的想法。

考虑重用formencode中的
classinstancemethod
装饰器

类classinstancemethod(对象):
"""
从类调用时的行为类似于类方法,例如
实例调用时的实例方法。该方法应
以两个参数“self”和“cls”为例,其中一个参数是None
取决于调用方法的方式。
"""
定义初始化(self,func):
self.func=func
定义获取(self,obj,type=None):
return _methodwrapper(self.func,obj=obj,type=type)
类_methodwrapper(对象):
定义初始化(self、func、obj、type):
self.func=func
self.obj=obj
self.type=type
定义呼叫(自,*args,**kw):
断言“自我”不以千瓦为单位,“cls”不以千瓦为单位(
“不能将'self'或'cls'参数用于”
“classinstancemethod”)
返回self.func(*(self.obj,self.type)+args),**kw)
定义报告(自我):
如果self.obj为无:
返回(“”)
%(self.type._名称_,self.func.func名称))
其他:
返回(“”)
%(self.type.\uuuuu名称,self.func.func名称,self.obj))

您真正想要实现的目标是什么?为什么不能将所有代码放在一个类方法中?或者,如果没有,有两个独立的类?还是始终使用默认值传递实例?不能将两个不同的方法/属性分配给同一个名称,就像试图将两个数字粘贴到一个整数变量中。这不是duck类型。Duck类型要求两个独立的类(不一定共享一个祖先)具有相同的方法。@DanielRoseman完全正确
a
具有类
a
。而
A
具有类
type
。。。它们是独立的类,不一定共享同一个祖先:)
self
如果通过类调用,将是
None
。但是我不确定
cls
是否会通过实例调用
None
fi-我认为这只对Py3有效。在Py2中,即使在实例中也会给出该类。输出是
i:
c:None
行。不管怎样,也许你只是向formencode提交一个补丁来修复注释。不管怎样,它会按照你的要求做。只是在Py3下进行了测试-在这两种情况下,它都会给出
cls
。然而,不是我问的:-)@ddaa我注意到你编辑了问题标题以使问题更清楚。我仍然认为在那里的某个地方放“鸭子打字”是有意义的,因为这是我第一次想到它的方式,我相信其他人也会这样想。在python中,类和实例都是。。。实例。因此,我认为这是一种很有意义的方式。你同意吗?谢谢。这很接近,但我必须将类本身作为参数传递,这并不是我想要的。
class classinstancemethod(object):
    """
    Acts like a class method when called from a class, like an
    instance method when called by an instance.  The method should
    take two arguments, 'self' and 'cls'; one of these will be None
    depending on how the method was called.
    """

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

    def __get__(self, obj, type=None):
        return _methodwrapper(self.func, obj=obj, type=type)


class _methodwrapper(object):

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

    def __call__(self, *args, **kw):
        assert 'self' not in kw and 'cls' not in kw, (
            "You cannot use 'self' or 'cls' arguments to a "
            "classinstancemethod")
        return self.func(*((self.obj, self.type) + args), **kw)

    def __repr__(self):
        if self.obj is None:
            return ('<bound class method %s.%s>'
                    % (self.type.__name__, self.func.func_name))
        else:
            return ('<bound method %s.%s of %r>'
                    % (self.type.__name__, self.func.func_name, self.obj))