Reputation: 2031
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?
Upvotes: 3
Views: 156
Reputation: 6331
You'll have to use two separate names. In python due to it's dynamic nature there's no operator overloading as in C++, when one function has same name with different arguments.
When you say def
in your script, you tell Python "set the following object(function object) to this name". So in your code you just redefine the name to reference classmethod
and your instance method function object is lost.
Solution: use different names for instace method and class method.
Upvotes: 2
Reputation: 17761
If I were you, I'd offer two distinct functions:
mymodule.Parser().parseFile()
(instance method), andmymodule.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
Upvotes: 6