Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python classmethod and(?) instancemethod

Tags:

python

I have written a Python class for parsing a specialized text format.

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 )

As indicated the parser can be modified with the modifyParser method - but in most cases I will just use the Parser instance as it comes from the Parser.__init__(). I would like to be able to do this:

# 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")

This requires that the parseFile( ) method can be called both as an instance method - with a self - and as a classmethod. Is this possible? Bad form?

like image 863
user422005 Avatar asked Apr 07 '26 05:04

user422005


1 Answers

If I were you, I'd offer two distinct functions:

  1. mymodule.Parser().parseFile() (instance method), and
  2. mymodule.parseFile() (module-level function that uses the default instance).

This is what happens for example with the standard json module, where you have json.JSONDecoder().decode() and json.loads(). Offering two distinct functions makes the code less ambiguous, more explicit and more predictable (in my opinion).

However, yes: what you want to do is possible. You have to implement your own descriptor using __get__. Here's an example:

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
like image 91
Andrea Corbellini Avatar answered Apr 09 '26 19:04

Andrea Corbellini



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!