Search code examples
pythonversion-controlpython-3.6python-decorators

Same name functions in same class - is there an elegant way to determine which to call?


I am trying to do product version control in Python scripts for a specific reason, but I couldn't figure out how to do it in an elegant way.

Currently, I am doing something like the below. However, the scripts are hard to maintain when version content is changed.

class Product(object):

    def __init__(client):
        self.version = client.version  # Get client version from another module

    def function():
        if self.version == '1.0':
            print('for version 1.0')
        elif self.version == '2.0':
            print('for version 2.0')
        else:
            print(f'function not support {self.version}')

Therefore, I want to do something like the below to separate the functions with the same name.

class Product(object):

    def __init__(client):
        self.version = client.version  # Get client version from another module

    def function():
        print('for version 1.0')

    def function():
        print('for version 2.0')

I was thinking about to use decorator to achieve this:

class Product(object):

    def __init__(client):
        self.version = client.version  # Get client version from another module

    @version(1.0)
    def function():
        print('for version 1.0')

    @version(2.0)
    def function():
        print('for version 2.0')

However, I failed to figure out how... it seems like a decorator cannot do this kind operation or I just don't understand how to.

Is there a elegant way to do this?


Solution

  • Inheritance is probably the best way to do this, but since you asked specifically about decorators, I wanted to show you could do this using decorators.

    You'll need to use a dictionary to store your functions by version, and then look up which version to use at runtime. Here's an example.

    version_store = {}
    
    def version(v):
        def dec(f):
            name = f.__qualname__
            version_store[(name, v)] = f
            def method(self, *args, **kwargs):
                f = version_store[(name, self.version)]
                return f(self, *args, **kwargs)
            return method
        return dec
    
    class Product(object):
        def __init__(self, version):
            self.version = version
    
        @version("1.0")
        def function(self):
            print("1.0")
    
        @version("2.0")
        def function(self):
            print("2.0")
    
    Product("1.0").function()
    Product("2.0").function()