Python classmethod和(?)instancemethod

时间:2016-01-19 14:30:16

标签: python

我编写了一个用于解析专用文本格式的Python类。

class Parser(object):

   def __init__(self):
       # Initialize parser instance


   def parseFile(self , filename):
       pass

   def modifyParser(self , *args , **kwargs):
       pass 

   #Classmethod has same name as instance method - this does not work.
   @classmethod 
   def parseFile(cls , filename)
       parser = Parser( )
       return parser.parseFile( filename )

如上所示,可以使用modifyParser方法修改解析器 - 但在大多数情况下,我将只使用Parser实例,因为它来自Parser.__init__()。我希望能够做到这一点:

# Parse file using 'custom' parser:
parser = Parser( )
parser.modifyParser( ... )
result = parser.parseFile("file.input")


# Parse using the default parser - do not explicitly instantiate an object:
result = Parser.parseFile("file.input")

这要求parseFile( )方法既可以作为实例方法调用 - 使用self - 也可以作为类方法调用。这可能吗?形式不好?

2 个答案:

答案 0 :(得分:6)

如果我是你,我会提供两个不同的功能:

  1. mymodule.Parser().parseFile()(实例方法)和
  2. mymodule.parseFile()(使用默认实例的模块级函数)。
  3. 例如,使用标准json模块会发生这种情况,您有json.JSONDecoder().decode()json.loads()。提供两个不同的函数使得代码不那么模糊,更明确,更可预测(在我看来)。

    然而,是的:你想做的事情是可能的。您必须使用__get__实施自己的descriptor。这是一个例子:

    from functools import partial
    
    class class_and_instance_method(object):
    
        def __init__(self, func):
            self.func = func
    
        def __get__(self, obj, type=None):
            first_arg = obj if obj is not None else type
            return partial(self.func, first_arg)
    
    class Parser(object):
    
        @class_and_instance_method
        def parseFile(self):
            if isinstance(self, type):
                print('using default parser')
            else:
                print('using the current instance')
    

    >>> Parser.parseFile()
    using default parser
    

    >>> p = Parser()
    >>> p.parseFile()
    using the current instance
    

答案 1 :(得分:2)

您必须使用两个单独的名称。在python中由于它的动态特性,在C ++中没有运算符重载,当一个函数具有不同参数的相同名称时。

当您在脚本中说def时,您告诉Python“将以下对象(函数对象)设置为此名称”。因此,在您的代码中,您只需重新定义名称以引用classmethod,并且您的实例方法函数对象将丢失。

解决方案:对instace方法和类方法使用不同的名称。