2017-07-27 66 views
1

我想编写一些Python代码,当从类型的上下文调用时的行为类似于@classmethod,但是当在对象的实例上调用时,第一个参数的行为与普通,self引用当前实例。即我想写:Python方法,其中第一个参数是类或自我

class Foo(object): 
    @something # <- does this exist? How can I even write it? 
    def bar(self_or_class): 
     print(repr(self_or_class)) 

Foo.bar() # Should print: <class '__main__.Foo'> 
inst = Foo() 
inst.bar() # Should print: <__main__.Foo at 0x....> 

回答

2

我曾经写过一个代码片段在daniweb这个

from __future__ import print_function 
from functools import partial 

class mixedmethod(object): 
    """This decorator mutates a function defined in a class into a 'mixed' class and instance method. 

    Usage: 

     class Spam: 

      @mixedmethod 
      def egg(self, cls, *args, **kwargs): 
       if self is None: 
        pass # executed if egg was called as a class method (eg. Spam.egg()) 
       else: 
        pass # executed if egg was called as an instance method (eg. instance.egg()) 
    The decorated methods need 2 implicit arguments: self and cls, the former being None when 
    there is no instance in the call. This follows the same rule as __get__ methods in python's 
    descriptor protocol. 
    """ 
    def __init__(self, func): 
     self.func = func 
    def __get__(self, instance, cls): 
     return partial(self.func, instance, cls) 

if __name__ == '__main__': 

    class Spam(object): 

     @mixedmethod 
     def ham(self, cls, *args): 
      if self is None: 
       print("Spam.ham() was called as a class method with {0}.".format((self, cls)+ args)) 
      else: 
       print("Spam.ham() was called as an instance method with {0}.".format((self, cls) + args)) 

     def __repr__(self): 
      return '<Spam instance>' 
    egg = Spam() 
    egg.ham(5) 
    Spam.ham(5) 
+0

我希望我能发现,一个小时前 – Flexo

+0

@Flexo这种想法的唯一缺点是不是真的有用。你也可以用不同的名字编写一个类方法和一个实例方法。通常,客户端代码知道参数是类型还是实例。 – Gribouillis

+1

我使用的是跨语言互操作性。即要在Python代理与其他语言之间建立1:1的行为映射,您必须执行此操作。 – Flexo

1

经过一番研究,我设法做到了这一点。我发现的第一件事是你可以实际上implement @classmethod in pure Python,在文档中引用。

有了这些知识是相当简单的适应代码来测试是否obj存在:

class something(object): 
    ''' 
    This works like @classmethod, except the first argument is either class or self if it's available 
    ''' 
    def __init__(self, f): 
     self.f = f 

    def __get__(self, obj, klass=None): 
     if klass is None: 
      klass = type(obj) 
     def newfunc(*args, **kwargs): 
      return self.f(klass if obj is None else obj, *args, **kwargs) 
     return newfunc 

所有我们要做的结束,文档在上面的例子中检查是否objNone和青睐objklass如果不是。

相关问题