Same name functions in same class - is there an elegant way to determine which to call?
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 decclass 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()
Could you put your Product
class into two modules, v1 and v2, then import them conditionally?
For example:
Productv1.py
class Product(object): def function(): print('for version 1.0')
Productv2.py
class Product(object): def function(): print('for version 2.0')
Then in your main file:
main.py
if client.version == '1.0': from Productv1 import Productelif client.version == '2.0': from Productv2 import Productelse: print(f'function not support {self.version}')p = Productp.function()
As another option, you could go for some factory to create your class.
Create your versioned functions (note the self
parameter). This can be done in a different module. Also, add some collection to fetch the function based on the version number.
def func_10(self): print('for version 1.0')def func_20(self): print('for version 2.0')funcs = {"1.0": func_10, "2.0": func_20}
Add a base class that contains the static parts of your implementation and a utility class to create your instances in:
class Product: def __init__(self, version): self.version = versionclass ProductFactory(type): @classmethod def get_product_class(mcs, version): # this will return an instance right away, due to the (version) in the end return type.__new__(mcs, "Product_{}".format(version.replace(".","")), (Product,), {"function": funcs.get(version)})(version) # if you want to return a class object to instantiate in your code omit the (version) in the end
Using this:
p1 = ProductFactory.get_product_class("1.0")p2 = ProductFactory.get_product_class("2.0")print(p1.__class__.__name__) # Product_10p1.function() # for version 1.0print(p1.function) # <bound method func_10 of <__main__.Product_10 object at 0x0000000002A157F0>>print(p2.__class__.__name__) # Product_20p2.function() # for version 2.0 print(p2.function) # <bound method func_20 of <__main__.Product_20 object at 0x0000000002A15860>>