Same name functions in same class, elegant way to determine which to call?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
21
down vote

favorite
5












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 - please help.



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... seems like a decorator cannot do this kind operation or I just don't understand how to.



Is there any elegant way to do this?










share|improve this question



















  • 1




    The "standard" way to solve this would be to have ProductV1 and ProductV2 then your Product class simply has an _impl attribute that is assigned to a ProductV<version> and all the methods are forwarded like def function(self): return self._impl.function(). In python you could even avoid defining them by using __getattr__. Also: ProductVX would simply define the basic operations and you can put in Product the facade methods that you can build on top of the basic methods.
    – Bakuriu
    2 days ago










  • I forgot to say: by "standard solution" I mean: this is what you'd do in most programming languages where you cannot use stuff like decorators for example. Also: if you have big classes using decorators makes your class quite big and hard to work with. It's easier to separate completely the version-specific implementations.
    – Bakuriu
    2 days ago














up vote
21
down vote

favorite
5












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 - please help.



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... seems like a decorator cannot do this kind operation or I just don't understand how to.



Is there any elegant way to do this?










share|improve this question



















  • 1




    The "standard" way to solve this would be to have ProductV1 and ProductV2 then your Product class simply has an _impl attribute that is assigned to a ProductV<version> and all the methods are forwarded like def function(self): return self._impl.function(). In python you could even avoid defining them by using __getattr__. Also: ProductVX would simply define the basic operations and you can put in Product the facade methods that you can build on top of the basic methods.
    – Bakuriu
    2 days ago










  • I forgot to say: by "standard solution" I mean: this is what you'd do in most programming languages where you cannot use stuff like decorators for example. Also: if you have big classes using decorators makes your class quite big and hard to work with. It's easier to separate completely the version-specific implementations.
    – Bakuriu
    2 days ago












up vote
21
down vote

favorite
5









up vote
21
down vote

favorite
5






5





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 - please help.



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... seems like a decorator cannot do this kind operation or I just don't understand how to.



Is there any elegant way to do this?










share|improve this question















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 - please help.



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... seems like a decorator cannot do this kind operation or I just don't understand how to.



Is there any elegant way to do this?







python version-control python-3.6 python-decorators






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 2 days ago









BartoszKP

26.1k106299




26.1k106299










asked 2 days ago









Timmy Lin

1087




1087







  • 1




    The "standard" way to solve this would be to have ProductV1 and ProductV2 then your Product class simply has an _impl attribute that is assigned to a ProductV<version> and all the methods are forwarded like def function(self): return self._impl.function(). In python you could even avoid defining them by using __getattr__. Also: ProductVX would simply define the basic operations and you can put in Product the facade methods that you can build on top of the basic methods.
    – Bakuriu
    2 days ago










  • I forgot to say: by "standard solution" I mean: this is what you'd do in most programming languages where you cannot use stuff like decorators for example. Also: if you have big classes using decorators makes your class quite big and hard to work with. It's easier to separate completely the version-specific implementations.
    – Bakuriu
    2 days ago












  • 1




    The "standard" way to solve this would be to have ProductV1 and ProductV2 then your Product class simply has an _impl attribute that is assigned to a ProductV<version> and all the methods are forwarded like def function(self): return self._impl.function(). In python you could even avoid defining them by using __getattr__. Also: ProductVX would simply define the basic operations and you can put in Product the facade methods that you can build on top of the basic methods.
    – Bakuriu
    2 days ago










  • I forgot to say: by "standard solution" I mean: this is what you'd do in most programming languages where you cannot use stuff like decorators for example. Also: if you have big classes using decorators makes your class quite big and hard to work with. It's easier to separate completely the version-specific implementations.
    – Bakuriu
    2 days ago







1




1




The "standard" way to solve this would be to have ProductV1 and ProductV2 then your Product class simply has an _impl attribute that is assigned to a ProductV<version> and all the methods are forwarded like def function(self): return self._impl.function(). In python you could even avoid defining them by using __getattr__. Also: ProductVX would simply define the basic operations and you can put in Product the facade methods that you can build on top of the basic methods.
– Bakuriu
2 days ago




The "standard" way to solve this would be to have ProductV1 and ProductV2 then your Product class simply has an _impl attribute that is assigned to a ProductV<version> and all the methods are forwarded like def function(self): return self._impl.function(). In python you could even avoid defining them by using __getattr__. Also: ProductVX would simply define the basic operations and you can put in Product the facade methods that you can build on top of the basic methods.
– Bakuriu
2 days ago












I forgot to say: by "standard solution" I mean: this is what you'd do in most programming languages where you cannot use stuff like decorators for example. Also: if you have big classes using decorators makes your class quite big and hard to work with. It's easier to separate completely the version-specific implementations.
– Bakuriu
2 days ago




I forgot to say: by "standard solution" I mean: this is what you'd do in most programming languages where you cannot use stuff like decorators for example. Also: if you have big classes using decorators makes your class quite big and hard to work with. It's easier to separate completely the version-specific implementations.
– Bakuriu
2 days ago












7 Answers
7






active

oldest

votes

















up vote
23
down vote



accepted










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 the your functions by version, 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()





share|improve this answer


















  • 3




    You probably want f.__qualname__ to avoid conflict between Product.function and Ambassadorial.function...
    – Amadan
    2 days ago











  • OMG, this is my dream solution. Thank you for inspiring me!!!
    – Timmy Lin
    2 days ago










  • Python doesn't complain that there are two methods with the same name in a class? Which one does it use? (Yes I realise that the decorator returns the same function anyway, but Python doesn't know)
    – Bergi
    2 days ago










  • @Amadan Instead of using the qualified name, would it be possible to create a separate version_store per class?
    – Bergi
    2 days ago






  • 2




    @Bergi methods are just members on the class. Each declaration replaces the last version, but it doesn't matter because, like you said, they're all the same :)
    – Bi Rico
    2 days ago

















up vote
7
down vote













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 Product
elif client.version == '2.0':
from Productv2 import Product
else:
print(f'function not support self.version')

p = Product
p.function()





share|improve this answer






















  • Actually, I used similar way to do version control before by creating multiple py files (e.g. v1, v2, v3), which is easiest but these files contain too many "duplicated content".. that's why I am trying to combine them into one CLASS. Thank you for your advice!
    – Timmy Lin
    2 days ago






  • 2




    @TimmyLin In that case, you could have a base class, say Product that holds all the duplicated content, then have a Productv1 and Productv2 that inherits it and just holds what is different. That way there's no duplicated code.
    – Loocid
    2 days ago










  • And the MAIN reason is .. too many versions (but with small changes) in this product and it's still growing, so if I do this, the folder/files structure will become ugly eventually :|
    – Timmy Lin
    2 days ago










  • Ah in that case my suggestion cant go any further. Good luck.
    – Loocid
    2 days ago










  • Exactly, the B plan is to use inherit from a main class. But I still want to know if there's any cool and elegant way to do this. If there isn't, I will mark you the best answer! thank you!
    – Timmy Lin
    2 days ago

















up vote
5
down vote













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 = version

class 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_10
p1.function() # for version 1.0
print(p1.function) # <bound method func_10 of <__main__.Product_10 object at 0x0000000002A157F0>>
print(p2.__class__.__name__) # Product_20
p2.function() # for version 2.0
print(p2.function) # <bound method func_20 of <__main__.Product_20 object at 0x0000000002A15860>>





share|improve this answer




















  • cool! although it's a little bit complex, it could do the thing. however I am looking for a way that I don't need to separate functions into 2 variables p1, p2, but this is absolutely a good answer. Thank you!
    – Timmy Lin
    2 days ago






  • 1




    @TimmyLin Actually, the functions are not separated into two variables. p1 and p2 are separate instances of subclasses of Product, each with their own implementation of function based on the version (which is supposed to be your client.version). Basically, this example builds the class with the implementation of function that is required for the given version instead of having one class implementing all possible 'versions' of function. However, I think you picked the best answer for your requirement, this was mereley added for completeness sake :)
    – shmee
    2 days ago






  • 1




    BTW: you could replace ProductFactor with a Product class and define a __new__ method to do what the get_product_class does. In this way the code has less boiler-plate.
    – Bakuriu
    2 days ago

















up vote
4
down vote













In general, don't. Method overloading is discouraged in Python. If you have to differentiate on class level, read @Loocid's answer. I won't repeat his excellent post.



If you want in on a method level because the difference is small enough for that, try something like this:



class Product:

def method(self):
if self.version == "1.0":
return self._methodv1()
elif self.version == "2.0":
return self._methodv2()
else:
raise ValueError("No appropriate method for version ".format(self.version))

def _methodv1(self):
# implementation

def _methodv2(self):
# implementation


Note here:



  1. Use of methods starting with an underscore, to indicate those are
    the implementation.

  2. Keeping the methods nice and tidy without
    contamination between the versions

  3. Raising an error for unexpected versions (crash early and hard).

  4. In my not so humble opinion, this will be a lot clearer for other people reading your post than using decorators.

Or:



class Product:

def method_old(self):
# transform arguments to v2 method:
return self.method()

def method(self):
# implementation


  1. In case you want to totally deprecate previous useage, and want to drop version 1.0 support in the future.

  2. Be sure to give deprecation warnings, so to not surprise users of a library with sudden changes.

  3. Arguably the better solution if nobody else uses your code.

I get the vibe my first method would be more suitable to your problem at hand, but I wanted to include the second for posterity. If you edit your code 10 years from now, that one will make you happier. If you edit code using the current code tomorrow, the first method will make you happier.






share|improve this answer




















  • Thank you for the honest advice! Everyone here did help me a lot, it's struggle to say who's solution is the best. Let's say.. the project I am working on is .. extremely huge, we want the version difference can be listed out very CLEARLY and can be maintained easily. That's why I insist to use decorator to do this due to it's the clearest and beauty one. To be honest, if I am working on another smaller project, I will definitely choose your 2nd options and also @Loocid's one.
    – Timmy Lin
    2 days ago










  • We can only ever look at a small part at the time - in a huge project, only you can pick the right option, due to the style of the rest of the project. Best we can do is list the possibilities. Good luck with it !
    – Jacco van Dorp
    2 days ago










  • Designing a new framework for development is hard, I really like your first suggestion and I have discussed that with team, maybe there's a chance we will go that way or @BartoszKP's way. Both are excellent.
    – Timmy Lin
    yesterday










  • Glad that you have use for it :)
    – Jacco van Dorp
    yesterday

















up vote
0
down vote













You can use decorators for this



def v_decorate(func):
def func_wrapper(name):
return func(name)
return func_wrapper


And



@v_decorate
def get_version(name):
return "for version 0 ".format(name)


You can call it



get_version(1.0)

'for version 1.0 '

get_version(2.0)
'for version 2.0 '





share|improve this answer




















  • I am sorry, I am not sure if I understand this correctly. The v_decorate is to add an extra argument name to the original function? don't understand how to combine this to my same name functions.. Orz
    – Timmy Lin
    2 days ago











  • Doing this is nothing different from the first example I wrote in description.. passing version to v_decorate and put into called function is kinda extra steps. Modify my function to function(self): print(f'for version self.version') can do the exactly same thing without decorator..
    – Timmy Lin
    2 days ago







  • 4




    I don't see what this decorator actually accomplishes ?
    – Jacco van Dorp
    2 days ago

















up vote
0
down vote













I'm not a python developer but I can't help but wonder why you don't just do something like this:



class Product(object):
def __init__(self, version):
self.version = version
def function(self):
print('for version ' + self.version)





share|improve this answer




















  • Because this is just a example that make ppl easier to understand what I was trying to do. The function is not only printing things but do a lot of operations. Actually I don't even need to self.version to be passed into function method, I just need it to locate which function I want to load while program is running.
    – Timmy Lin
    yesterday


















up vote
0
down vote













Or you can do, dict.get to call a function and do print in lambda if nothing is right:



def func_1(self):
print('for version 1.0')

def func_2(self):
print('for version 2.0')
def function(self):
funcs = "1.0": self.func_1,
"2.0": self.func_2
funcs.get(self.version,lambda: print(f'function not support self.version'))()


Example:



class Product(object):

def __init__(self,version):
self.version = version

def func_1(self):
print('for version 1.0')

def func_2(self):
print('for version 2.0')
def function(self):
funcs = "1.0": self.func_1,
"2.0": self.func_2
funcs.get(self.version,lambda: print(f'function not support self.version'))()
Product('1.0').function()
Product('2.0').function()
Product('3.0').function()


Output:



for version 1.0
for version 2.0
function not support 3.0





share|improve this answer




















    Your Answer





    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52252054%2fsame-name-functions-in-same-class-elegant-way-to-determine-which-to-call%23new-answer', 'question_page');

    );

    Post as a guest






























    7 Answers
    7






    active

    oldest

    votes








    7 Answers
    7






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    23
    down vote



    accepted










    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 the your functions by version, 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()





    share|improve this answer


















    • 3




      You probably want f.__qualname__ to avoid conflict between Product.function and Ambassadorial.function...
      – Amadan
      2 days ago











    • OMG, this is my dream solution. Thank you for inspiring me!!!
      – Timmy Lin
      2 days ago










    • Python doesn't complain that there are two methods with the same name in a class? Which one does it use? (Yes I realise that the decorator returns the same function anyway, but Python doesn't know)
      – Bergi
      2 days ago










    • @Amadan Instead of using the qualified name, would it be possible to create a separate version_store per class?
      – Bergi
      2 days ago






    • 2




      @Bergi methods are just members on the class. Each declaration replaces the last version, but it doesn't matter because, like you said, they're all the same :)
      – Bi Rico
      2 days ago














    up vote
    23
    down vote



    accepted










    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 the your functions by version, 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()





    share|improve this answer


















    • 3




      You probably want f.__qualname__ to avoid conflict between Product.function and Ambassadorial.function...
      – Amadan
      2 days ago











    • OMG, this is my dream solution. Thank you for inspiring me!!!
      – Timmy Lin
      2 days ago










    • Python doesn't complain that there are two methods with the same name in a class? Which one does it use? (Yes I realise that the decorator returns the same function anyway, but Python doesn't know)
      – Bergi
      2 days ago










    • @Amadan Instead of using the qualified name, would it be possible to create a separate version_store per class?
      – Bergi
      2 days ago






    • 2




      @Bergi methods are just members on the class. Each declaration replaces the last version, but it doesn't matter because, like you said, they're all the same :)
      – Bi Rico
      2 days ago












    up vote
    23
    down vote



    accepted







    up vote
    23
    down vote



    accepted






    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 the your functions by version, 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()





    share|improve this answer














    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 the your functions by version, 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()






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 2 days ago

























    answered 2 days ago









    Bi Rico

    18.3k23457




    18.3k23457







    • 3




      You probably want f.__qualname__ to avoid conflict between Product.function and Ambassadorial.function...
      – Amadan
      2 days ago











    • OMG, this is my dream solution. Thank you for inspiring me!!!
      – Timmy Lin
      2 days ago










    • Python doesn't complain that there are two methods with the same name in a class? Which one does it use? (Yes I realise that the decorator returns the same function anyway, but Python doesn't know)
      – Bergi
      2 days ago










    • @Amadan Instead of using the qualified name, would it be possible to create a separate version_store per class?
      – Bergi
      2 days ago






    • 2




      @Bergi methods are just members on the class. Each declaration replaces the last version, but it doesn't matter because, like you said, they're all the same :)
      – Bi Rico
      2 days ago












    • 3




      You probably want f.__qualname__ to avoid conflict between Product.function and Ambassadorial.function...
      – Amadan
      2 days ago











    • OMG, this is my dream solution. Thank you for inspiring me!!!
      – Timmy Lin
      2 days ago










    • Python doesn't complain that there are two methods with the same name in a class? Which one does it use? (Yes I realise that the decorator returns the same function anyway, but Python doesn't know)
      – Bergi
      2 days ago










    • @Amadan Instead of using the qualified name, would it be possible to create a separate version_store per class?
      – Bergi
      2 days ago






    • 2




      @Bergi methods are just members on the class. Each declaration replaces the last version, but it doesn't matter because, like you said, they're all the same :)
      – Bi Rico
      2 days ago







    3




    3




    You probably want f.__qualname__ to avoid conflict between Product.function and Ambassadorial.function...
    – Amadan
    2 days ago





    You probably want f.__qualname__ to avoid conflict between Product.function and Ambassadorial.function...
    – Amadan
    2 days ago













    OMG, this is my dream solution. Thank you for inspiring me!!!
    – Timmy Lin
    2 days ago




    OMG, this is my dream solution. Thank you for inspiring me!!!
    – Timmy Lin
    2 days ago












    Python doesn't complain that there are two methods with the same name in a class? Which one does it use? (Yes I realise that the decorator returns the same function anyway, but Python doesn't know)
    – Bergi
    2 days ago




    Python doesn't complain that there are two methods with the same name in a class? Which one does it use? (Yes I realise that the decorator returns the same function anyway, but Python doesn't know)
    – Bergi
    2 days ago












    @Amadan Instead of using the qualified name, would it be possible to create a separate version_store per class?
    – Bergi
    2 days ago




    @Amadan Instead of using the qualified name, would it be possible to create a separate version_store per class?
    – Bergi
    2 days ago




    2




    2




    @Bergi methods are just members on the class. Each declaration replaces the last version, but it doesn't matter because, like you said, they're all the same :)
    – Bi Rico
    2 days ago




    @Bergi methods are just members on the class. Each declaration replaces the last version, but it doesn't matter because, like you said, they're all the same :)
    – Bi Rico
    2 days ago












    up vote
    7
    down vote













    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 Product
    elif client.version == '2.0':
    from Productv2 import Product
    else:
    print(f'function not support self.version')

    p = Product
    p.function()





    share|improve this answer






















    • Actually, I used similar way to do version control before by creating multiple py files (e.g. v1, v2, v3), which is easiest but these files contain too many "duplicated content".. that's why I am trying to combine them into one CLASS. Thank you for your advice!
      – Timmy Lin
      2 days ago






    • 2




      @TimmyLin In that case, you could have a base class, say Product that holds all the duplicated content, then have a Productv1 and Productv2 that inherits it and just holds what is different. That way there's no duplicated code.
      – Loocid
      2 days ago










    • And the MAIN reason is .. too many versions (but with small changes) in this product and it's still growing, so if I do this, the folder/files structure will become ugly eventually :|
      – Timmy Lin
      2 days ago










    • Ah in that case my suggestion cant go any further. Good luck.
      – Loocid
      2 days ago










    • Exactly, the B plan is to use inherit from a main class. But I still want to know if there's any cool and elegant way to do this. If there isn't, I will mark you the best answer! thank you!
      – Timmy Lin
      2 days ago














    up vote
    7
    down vote













    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 Product
    elif client.version == '2.0':
    from Productv2 import Product
    else:
    print(f'function not support self.version')

    p = Product
    p.function()





    share|improve this answer






















    • Actually, I used similar way to do version control before by creating multiple py files (e.g. v1, v2, v3), which is easiest but these files contain too many "duplicated content".. that's why I am trying to combine them into one CLASS. Thank you for your advice!
      – Timmy Lin
      2 days ago






    • 2




      @TimmyLin In that case, you could have a base class, say Product that holds all the duplicated content, then have a Productv1 and Productv2 that inherits it and just holds what is different. That way there's no duplicated code.
      – Loocid
      2 days ago










    • And the MAIN reason is .. too many versions (but with small changes) in this product and it's still growing, so if I do this, the folder/files structure will become ugly eventually :|
      – Timmy Lin
      2 days ago










    • Ah in that case my suggestion cant go any further. Good luck.
      – Loocid
      2 days ago










    • Exactly, the B plan is to use inherit from a main class. But I still want to know if there's any cool and elegant way to do this. If there isn't, I will mark you the best answer! thank you!
      – Timmy Lin
      2 days ago












    up vote
    7
    down vote










    up vote
    7
    down vote









    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 Product
    elif client.version == '2.0':
    from Productv2 import Product
    else:
    print(f'function not support self.version')

    p = Product
    p.function()





    share|improve this answer














    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 Product
    elif client.version == '2.0':
    from Productv2 import Product
    else:
    print(f'function not support self.version')

    p = Product
    p.function()






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 2 days ago

























    answered 2 days ago









    Loocid

    2,0721825




    2,0721825











    • Actually, I used similar way to do version control before by creating multiple py files (e.g. v1, v2, v3), which is easiest but these files contain too many "duplicated content".. that's why I am trying to combine them into one CLASS. Thank you for your advice!
      – Timmy Lin
      2 days ago






    • 2




      @TimmyLin In that case, you could have a base class, say Product that holds all the duplicated content, then have a Productv1 and Productv2 that inherits it and just holds what is different. That way there's no duplicated code.
      – Loocid
      2 days ago










    • And the MAIN reason is .. too many versions (but with small changes) in this product and it's still growing, so if I do this, the folder/files structure will become ugly eventually :|
      – Timmy Lin
      2 days ago










    • Ah in that case my suggestion cant go any further. Good luck.
      – Loocid
      2 days ago










    • Exactly, the B plan is to use inherit from a main class. But I still want to know if there's any cool and elegant way to do this. If there isn't, I will mark you the best answer! thank you!
      – Timmy Lin
      2 days ago
















    • Actually, I used similar way to do version control before by creating multiple py files (e.g. v1, v2, v3), which is easiest but these files contain too many "duplicated content".. that's why I am trying to combine them into one CLASS. Thank you for your advice!
      – Timmy Lin
      2 days ago






    • 2




      @TimmyLin In that case, you could have a base class, say Product that holds all the duplicated content, then have a Productv1 and Productv2 that inherits it and just holds what is different. That way there's no duplicated code.
      – Loocid
      2 days ago










    • And the MAIN reason is .. too many versions (but with small changes) in this product and it's still growing, so if I do this, the folder/files structure will become ugly eventually :|
      – Timmy Lin
      2 days ago










    • Ah in that case my suggestion cant go any further. Good luck.
      – Loocid
      2 days ago










    • Exactly, the B plan is to use inherit from a main class. But I still want to know if there's any cool and elegant way to do this. If there isn't, I will mark you the best answer! thank you!
      – Timmy Lin
      2 days ago















    Actually, I used similar way to do version control before by creating multiple py files (e.g. v1, v2, v3), which is easiest but these files contain too many "duplicated content".. that's why I am trying to combine them into one CLASS. Thank you for your advice!
    – Timmy Lin
    2 days ago




    Actually, I used similar way to do version control before by creating multiple py files (e.g. v1, v2, v3), which is easiest but these files contain too many "duplicated content".. that's why I am trying to combine them into one CLASS. Thank you for your advice!
    – Timmy Lin
    2 days ago




    2




    2




    @TimmyLin In that case, you could have a base class, say Product that holds all the duplicated content, then have a Productv1 and Productv2 that inherits it and just holds what is different. That way there's no duplicated code.
    – Loocid
    2 days ago




    @TimmyLin In that case, you could have a base class, say Product that holds all the duplicated content, then have a Productv1 and Productv2 that inherits it and just holds what is different. That way there's no duplicated code.
    – Loocid
    2 days ago












    And the MAIN reason is .. too many versions (but with small changes) in this product and it's still growing, so if I do this, the folder/files structure will become ugly eventually :|
    – Timmy Lin
    2 days ago




    And the MAIN reason is .. too many versions (but with small changes) in this product and it's still growing, so if I do this, the folder/files structure will become ugly eventually :|
    – Timmy Lin
    2 days ago












    Ah in that case my suggestion cant go any further. Good luck.
    – Loocid
    2 days ago




    Ah in that case my suggestion cant go any further. Good luck.
    – Loocid
    2 days ago












    Exactly, the B plan is to use inherit from a main class. But I still want to know if there's any cool and elegant way to do this. If there isn't, I will mark you the best answer! thank you!
    – Timmy Lin
    2 days ago




    Exactly, the B plan is to use inherit from a main class. But I still want to know if there's any cool and elegant way to do this. If there isn't, I will mark you the best answer! thank you!
    – Timmy Lin
    2 days ago










    up vote
    5
    down vote













    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 = version

    class 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_10
    p1.function() # for version 1.0
    print(p1.function) # <bound method func_10 of <__main__.Product_10 object at 0x0000000002A157F0>>
    print(p2.__class__.__name__) # Product_20
    p2.function() # for version 2.0
    print(p2.function) # <bound method func_20 of <__main__.Product_20 object at 0x0000000002A15860>>





    share|improve this answer




















    • cool! although it's a little bit complex, it could do the thing. however I am looking for a way that I don't need to separate functions into 2 variables p1, p2, but this is absolutely a good answer. Thank you!
      – Timmy Lin
      2 days ago






    • 1




      @TimmyLin Actually, the functions are not separated into two variables. p1 and p2 are separate instances of subclasses of Product, each with their own implementation of function based on the version (which is supposed to be your client.version). Basically, this example builds the class with the implementation of function that is required for the given version instead of having one class implementing all possible 'versions' of function. However, I think you picked the best answer for your requirement, this was mereley added for completeness sake :)
      – shmee
      2 days ago






    • 1




      BTW: you could replace ProductFactor with a Product class and define a __new__ method to do what the get_product_class does. In this way the code has less boiler-plate.
      – Bakuriu
      2 days ago














    up vote
    5
    down vote













    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 = version

    class 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_10
    p1.function() # for version 1.0
    print(p1.function) # <bound method func_10 of <__main__.Product_10 object at 0x0000000002A157F0>>
    print(p2.__class__.__name__) # Product_20
    p2.function() # for version 2.0
    print(p2.function) # <bound method func_20 of <__main__.Product_20 object at 0x0000000002A15860>>





    share|improve this answer




















    • cool! although it's a little bit complex, it could do the thing. however I am looking for a way that I don't need to separate functions into 2 variables p1, p2, but this is absolutely a good answer. Thank you!
      – Timmy Lin
      2 days ago






    • 1




      @TimmyLin Actually, the functions are not separated into two variables. p1 and p2 are separate instances of subclasses of Product, each with their own implementation of function based on the version (which is supposed to be your client.version). Basically, this example builds the class with the implementation of function that is required for the given version instead of having one class implementing all possible 'versions' of function. However, I think you picked the best answer for your requirement, this was mereley added for completeness sake :)
      – shmee
      2 days ago






    • 1




      BTW: you could replace ProductFactor with a Product class and define a __new__ method to do what the get_product_class does. In this way the code has less boiler-plate.
      – Bakuriu
      2 days ago












    up vote
    5
    down vote










    up vote
    5
    down vote









    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 = version

    class 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_10
    p1.function() # for version 1.0
    print(p1.function) # <bound method func_10 of <__main__.Product_10 object at 0x0000000002A157F0>>
    print(p2.__class__.__name__) # Product_20
    p2.function() # for version 2.0
    print(p2.function) # <bound method func_20 of <__main__.Product_20 object at 0x0000000002A15860>>





    share|improve this answer












    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 = version

    class 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_10
    p1.function() # for version 1.0
    print(p1.function) # <bound method func_10 of <__main__.Product_10 object at 0x0000000002A157F0>>
    print(p2.__class__.__name__) # Product_20
    p2.function() # for version 2.0
    print(p2.function) # <bound method func_20 of <__main__.Product_20 object at 0x0000000002A15860>>






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered 2 days ago









    shmee

    1,046511




    1,046511











    • cool! although it's a little bit complex, it could do the thing. however I am looking for a way that I don't need to separate functions into 2 variables p1, p2, but this is absolutely a good answer. Thank you!
      – Timmy Lin
      2 days ago






    • 1




      @TimmyLin Actually, the functions are not separated into two variables. p1 and p2 are separate instances of subclasses of Product, each with their own implementation of function based on the version (which is supposed to be your client.version). Basically, this example builds the class with the implementation of function that is required for the given version instead of having one class implementing all possible 'versions' of function. However, I think you picked the best answer for your requirement, this was mereley added for completeness sake :)
      – shmee
      2 days ago






    • 1




      BTW: you could replace ProductFactor with a Product class and define a __new__ method to do what the get_product_class does. In this way the code has less boiler-plate.
      – Bakuriu
      2 days ago
















    • cool! although it's a little bit complex, it could do the thing. however I am looking for a way that I don't need to separate functions into 2 variables p1, p2, but this is absolutely a good answer. Thank you!
      – Timmy Lin
      2 days ago






    • 1




      @TimmyLin Actually, the functions are not separated into two variables. p1 and p2 are separate instances of subclasses of Product, each with their own implementation of function based on the version (which is supposed to be your client.version). Basically, this example builds the class with the implementation of function that is required for the given version instead of having one class implementing all possible 'versions' of function. However, I think you picked the best answer for your requirement, this was mereley added for completeness sake :)
      – shmee
      2 days ago






    • 1




      BTW: you could replace ProductFactor with a Product class and define a __new__ method to do what the get_product_class does. In this way the code has less boiler-plate.
      – Bakuriu
      2 days ago















    cool! although it's a little bit complex, it could do the thing. however I am looking for a way that I don't need to separate functions into 2 variables p1, p2, but this is absolutely a good answer. Thank you!
    – Timmy Lin
    2 days ago




    cool! although it's a little bit complex, it could do the thing. however I am looking for a way that I don't need to separate functions into 2 variables p1, p2, but this is absolutely a good answer. Thank you!
    – Timmy Lin
    2 days ago




    1




    1




    @TimmyLin Actually, the functions are not separated into two variables. p1 and p2 are separate instances of subclasses of Product, each with their own implementation of function based on the version (which is supposed to be your client.version). Basically, this example builds the class with the implementation of function that is required for the given version instead of having one class implementing all possible 'versions' of function. However, I think you picked the best answer for your requirement, this was mereley added for completeness sake :)
    – shmee
    2 days ago




    @TimmyLin Actually, the functions are not separated into two variables. p1 and p2 are separate instances of subclasses of Product, each with their own implementation of function based on the version (which is supposed to be your client.version). Basically, this example builds the class with the implementation of function that is required for the given version instead of having one class implementing all possible 'versions' of function. However, I think you picked the best answer for your requirement, this was mereley added for completeness sake :)
    – shmee
    2 days ago




    1




    1




    BTW: you could replace ProductFactor with a Product class and define a __new__ method to do what the get_product_class does. In this way the code has less boiler-plate.
    – Bakuriu
    2 days ago




    BTW: you could replace ProductFactor with a Product class and define a __new__ method to do what the get_product_class does. In this way the code has less boiler-plate.
    – Bakuriu
    2 days ago










    up vote
    4
    down vote













    In general, don't. Method overloading is discouraged in Python. If you have to differentiate on class level, read @Loocid's answer. I won't repeat his excellent post.



    If you want in on a method level because the difference is small enough for that, try something like this:



    class Product:

    def method(self):
    if self.version == "1.0":
    return self._methodv1()
    elif self.version == "2.0":
    return self._methodv2()
    else:
    raise ValueError("No appropriate method for version ".format(self.version))

    def _methodv1(self):
    # implementation

    def _methodv2(self):
    # implementation


    Note here:



    1. Use of methods starting with an underscore, to indicate those are
      the implementation.

    2. Keeping the methods nice and tidy without
      contamination between the versions

    3. Raising an error for unexpected versions (crash early and hard).

    4. In my not so humble opinion, this will be a lot clearer for other people reading your post than using decorators.

    Or:



    class Product:

    def method_old(self):
    # transform arguments to v2 method:
    return self.method()

    def method(self):
    # implementation


    1. In case you want to totally deprecate previous useage, and want to drop version 1.0 support in the future.

    2. Be sure to give deprecation warnings, so to not surprise users of a library with sudden changes.

    3. Arguably the better solution if nobody else uses your code.

    I get the vibe my first method would be more suitable to your problem at hand, but I wanted to include the second for posterity. If you edit your code 10 years from now, that one will make you happier. If you edit code using the current code tomorrow, the first method will make you happier.






    share|improve this answer




















    • Thank you for the honest advice! Everyone here did help me a lot, it's struggle to say who's solution is the best. Let's say.. the project I am working on is .. extremely huge, we want the version difference can be listed out very CLEARLY and can be maintained easily. That's why I insist to use decorator to do this due to it's the clearest and beauty one. To be honest, if I am working on another smaller project, I will definitely choose your 2nd options and also @Loocid's one.
      – Timmy Lin
      2 days ago










    • We can only ever look at a small part at the time - in a huge project, only you can pick the right option, due to the style of the rest of the project. Best we can do is list the possibilities. Good luck with it !
      – Jacco van Dorp
      2 days ago










    • Designing a new framework for development is hard, I really like your first suggestion and I have discussed that with team, maybe there's a chance we will go that way or @BartoszKP's way. Both are excellent.
      – Timmy Lin
      yesterday










    • Glad that you have use for it :)
      – Jacco van Dorp
      yesterday














    up vote
    4
    down vote













    In general, don't. Method overloading is discouraged in Python. If you have to differentiate on class level, read @Loocid's answer. I won't repeat his excellent post.



    If you want in on a method level because the difference is small enough for that, try something like this:



    class Product:

    def method(self):
    if self.version == "1.0":
    return self._methodv1()
    elif self.version == "2.0":
    return self._methodv2()
    else:
    raise ValueError("No appropriate method for version ".format(self.version))

    def _methodv1(self):
    # implementation

    def _methodv2(self):
    # implementation


    Note here:



    1. Use of methods starting with an underscore, to indicate those are
      the implementation.

    2. Keeping the methods nice and tidy without
      contamination between the versions

    3. Raising an error for unexpected versions (crash early and hard).

    4. In my not so humble opinion, this will be a lot clearer for other people reading your post than using decorators.

    Or:



    class Product:

    def method_old(self):
    # transform arguments to v2 method:
    return self.method()

    def method(self):
    # implementation


    1. In case you want to totally deprecate previous useage, and want to drop version 1.0 support in the future.

    2. Be sure to give deprecation warnings, so to not surprise users of a library with sudden changes.

    3. Arguably the better solution if nobody else uses your code.

    I get the vibe my first method would be more suitable to your problem at hand, but I wanted to include the second for posterity. If you edit your code 10 years from now, that one will make you happier. If you edit code using the current code tomorrow, the first method will make you happier.






    share|improve this answer




















    • Thank you for the honest advice! Everyone here did help me a lot, it's struggle to say who's solution is the best. Let's say.. the project I am working on is .. extremely huge, we want the version difference can be listed out very CLEARLY and can be maintained easily. That's why I insist to use decorator to do this due to it's the clearest and beauty one. To be honest, if I am working on another smaller project, I will definitely choose your 2nd options and also @Loocid's one.
      – Timmy Lin
      2 days ago










    • We can only ever look at a small part at the time - in a huge project, only you can pick the right option, due to the style of the rest of the project. Best we can do is list the possibilities. Good luck with it !
      – Jacco van Dorp
      2 days ago










    • Designing a new framework for development is hard, I really like your first suggestion and I have discussed that with team, maybe there's a chance we will go that way or @BartoszKP's way. Both are excellent.
      – Timmy Lin
      yesterday










    • Glad that you have use for it :)
      – Jacco van Dorp
      yesterday












    up vote
    4
    down vote










    up vote
    4
    down vote









    In general, don't. Method overloading is discouraged in Python. If you have to differentiate on class level, read @Loocid's answer. I won't repeat his excellent post.



    If you want in on a method level because the difference is small enough for that, try something like this:



    class Product:

    def method(self):
    if self.version == "1.0":
    return self._methodv1()
    elif self.version == "2.0":
    return self._methodv2()
    else:
    raise ValueError("No appropriate method for version ".format(self.version))

    def _methodv1(self):
    # implementation

    def _methodv2(self):
    # implementation


    Note here:



    1. Use of methods starting with an underscore, to indicate those are
      the implementation.

    2. Keeping the methods nice and tidy without
      contamination between the versions

    3. Raising an error for unexpected versions (crash early and hard).

    4. In my not so humble opinion, this will be a lot clearer for other people reading your post than using decorators.

    Or:



    class Product:

    def method_old(self):
    # transform arguments to v2 method:
    return self.method()

    def method(self):
    # implementation


    1. In case you want to totally deprecate previous useage, and want to drop version 1.0 support in the future.

    2. Be sure to give deprecation warnings, so to not surprise users of a library with sudden changes.

    3. Arguably the better solution if nobody else uses your code.

    I get the vibe my first method would be more suitable to your problem at hand, but I wanted to include the second for posterity. If you edit your code 10 years from now, that one will make you happier. If you edit code using the current code tomorrow, the first method will make you happier.






    share|improve this answer












    In general, don't. Method overloading is discouraged in Python. If you have to differentiate on class level, read @Loocid's answer. I won't repeat his excellent post.



    If you want in on a method level because the difference is small enough for that, try something like this:



    class Product:

    def method(self):
    if self.version == "1.0":
    return self._methodv1()
    elif self.version == "2.0":
    return self._methodv2()
    else:
    raise ValueError("No appropriate method for version ".format(self.version))

    def _methodv1(self):
    # implementation

    def _methodv2(self):
    # implementation


    Note here:



    1. Use of methods starting with an underscore, to indicate those are
      the implementation.

    2. Keeping the methods nice and tidy without
      contamination between the versions

    3. Raising an error for unexpected versions (crash early and hard).

    4. In my not so humble opinion, this will be a lot clearer for other people reading your post than using decorators.

    Or:



    class Product:

    def method_old(self):
    # transform arguments to v2 method:
    return self.method()

    def method(self):
    # implementation


    1. In case you want to totally deprecate previous useage, and want to drop version 1.0 support in the future.

    2. Be sure to give deprecation warnings, so to not surprise users of a library with sudden changes.

    3. Arguably the better solution if nobody else uses your code.

    I get the vibe my first method would be more suitable to your problem at hand, but I wanted to include the second for posterity. If you edit your code 10 years from now, that one will make you happier. If you edit code using the current code tomorrow, the first method will make you happier.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered 2 days ago









    Jacco van Dorp

    1595




    1595











    • Thank you for the honest advice! Everyone here did help me a lot, it's struggle to say who's solution is the best. Let's say.. the project I am working on is .. extremely huge, we want the version difference can be listed out very CLEARLY and can be maintained easily. That's why I insist to use decorator to do this due to it's the clearest and beauty one. To be honest, if I am working on another smaller project, I will definitely choose your 2nd options and also @Loocid's one.
      – Timmy Lin
      2 days ago










    • We can only ever look at a small part at the time - in a huge project, only you can pick the right option, due to the style of the rest of the project. Best we can do is list the possibilities. Good luck with it !
      – Jacco van Dorp
      2 days ago










    • Designing a new framework for development is hard, I really like your first suggestion and I have discussed that with team, maybe there's a chance we will go that way or @BartoszKP's way. Both are excellent.
      – Timmy Lin
      yesterday










    • Glad that you have use for it :)
      – Jacco van Dorp
      yesterday
















    • Thank you for the honest advice! Everyone here did help me a lot, it's struggle to say who's solution is the best. Let's say.. the project I am working on is .. extremely huge, we want the version difference can be listed out very CLEARLY and can be maintained easily. That's why I insist to use decorator to do this due to it's the clearest and beauty one. To be honest, if I am working on another smaller project, I will definitely choose your 2nd options and also @Loocid's one.
      – Timmy Lin
      2 days ago










    • We can only ever look at a small part at the time - in a huge project, only you can pick the right option, due to the style of the rest of the project. Best we can do is list the possibilities. Good luck with it !
      – Jacco van Dorp
      2 days ago










    • Designing a new framework for development is hard, I really like your first suggestion and I have discussed that with team, maybe there's a chance we will go that way or @BartoszKP's way. Both are excellent.
      – Timmy Lin
      yesterday










    • Glad that you have use for it :)
      – Jacco van Dorp
      yesterday















    Thank you for the honest advice! Everyone here did help me a lot, it's struggle to say who's solution is the best. Let's say.. the project I am working on is .. extremely huge, we want the version difference can be listed out very CLEARLY and can be maintained easily. That's why I insist to use decorator to do this due to it's the clearest and beauty one. To be honest, if I am working on another smaller project, I will definitely choose your 2nd options and also @Loocid's one.
    – Timmy Lin
    2 days ago




    Thank you for the honest advice! Everyone here did help me a lot, it's struggle to say who's solution is the best. Let's say.. the project I am working on is .. extremely huge, we want the version difference can be listed out very CLEARLY and can be maintained easily. That's why I insist to use decorator to do this due to it's the clearest and beauty one. To be honest, if I am working on another smaller project, I will definitely choose your 2nd options and also @Loocid's one.
    – Timmy Lin
    2 days ago












    We can only ever look at a small part at the time - in a huge project, only you can pick the right option, due to the style of the rest of the project. Best we can do is list the possibilities. Good luck with it !
    – Jacco van Dorp
    2 days ago




    We can only ever look at a small part at the time - in a huge project, only you can pick the right option, due to the style of the rest of the project. Best we can do is list the possibilities. Good luck with it !
    – Jacco van Dorp
    2 days ago












    Designing a new framework for development is hard, I really like your first suggestion and I have discussed that with team, maybe there's a chance we will go that way or @BartoszKP's way. Both are excellent.
    – Timmy Lin
    yesterday




    Designing a new framework for development is hard, I really like your first suggestion and I have discussed that with team, maybe there's a chance we will go that way or @BartoszKP's way. Both are excellent.
    – Timmy Lin
    yesterday












    Glad that you have use for it :)
    – Jacco van Dorp
    yesterday




    Glad that you have use for it :)
    – Jacco van Dorp
    yesterday










    up vote
    0
    down vote













    You can use decorators for this



    def v_decorate(func):
    def func_wrapper(name):
    return func(name)
    return func_wrapper


    And



    @v_decorate
    def get_version(name):
    return "for version 0 ".format(name)


    You can call it



    get_version(1.0)

    'for version 1.0 '

    get_version(2.0)
    'for version 2.0 '





    share|improve this answer




















    • I am sorry, I am not sure if I understand this correctly. The v_decorate is to add an extra argument name to the original function? don't understand how to combine this to my same name functions.. Orz
      – Timmy Lin
      2 days ago











    • Doing this is nothing different from the first example I wrote in description.. passing version to v_decorate and put into called function is kinda extra steps. Modify my function to function(self): print(f'for version self.version') can do the exactly same thing without decorator..
      – Timmy Lin
      2 days ago







    • 4




      I don't see what this decorator actually accomplishes ?
      – Jacco van Dorp
      2 days ago














    up vote
    0
    down vote













    You can use decorators for this



    def v_decorate(func):
    def func_wrapper(name):
    return func(name)
    return func_wrapper


    And



    @v_decorate
    def get_version(name):
    return "for version 0 ".format(name)


    You can call it



    get_version(1.0)

    'for version 1.0 '

    get_version(2.0)
    'for version 2.0 '





    share|improve this answer




















    • I am sorry, I am not sure if I understand this correctly. The v_decorate is to add an extra argument name to the original function? don't understand how to combine this to my same name functions.. Orz
      – Timmy Lin
      2 days ago











    • Doing this is nothing different from the first example I wrote in description.. passing version to v_decorate and put into called function is kinda extra steps. Modify my function to function(self): print(f'for version self.version') can do the exactly same thing without decorator..
      – Timmy Lin
      2 days ago







    • 4




      I don't see what this decorator actually accomplishes ?
      – Jacco van Dorp
      2 days ago












    up vote
    0
    down vote










    up vote
    0
    down vote









    You can use decorators for this



    def v_decorate(func):
    def func_wrapper(name):
    return func(name)
    return func_wrapper


    And



    @v_decorate
    def get_version(name):
    return "for version 0 ".format(name)


    You can call it



    get_version(1.0)

    'for version 1.0 '

    get_version(2.0)
    'for version 2.0 '





    share|improve this answer












    You can use decorators for this



    def v_decorate(func):
    def func_wrapper(name):
    return func(name)
    return func_wrapper


    And



    @v_decorate
    def get_version(name):
    return "for version 0 ".format(name)


    You can call it



    get_version(1.0)

    'for version 1.0 '

    get_version(2.0)
    'for version 2.0 '






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered 2 days ago









    Richard Rublev

    2,78331832




    2,78331832











    • I am sorry, I am not sure if I understand this correctly. The v_decorate is to add an extra argument name to the original function? don't understand how to combine this to my same name functions.. Orz
      – Timmy Lin
      2 days ago











    • Doing this is nothing different from the first example I wrote in description.. passing version to v_decorate and put into called function is kinda extra steps. Modify my function to function(self): print(f'for version self.version') can do the exactly same thing without decorator..
      – Timmy Lin
      2 days ago







    • 4




      I don't see what this decorator actually accomplishes ?
      – Jacco van Dorp
      2 days ago
















    • I am sorry, I am not sure if I understand this correctly. The v_decorate is to add an extra argument name to the original function? don't understand how to combine this to my same name functions.. Orz
      – Timmy Lin
      2 days ago











    • Doing this is nothing different from the first example I wrote in description.. passing version to v_decorate and put into called function is kinda extra steps. Modify my function to function(self): print(f'for version self.version') can do the exactly same thing without decorator..
      – Timmy Lin
      2 days ago







    • 4




      I don't see what this decorator actually accomplishes ?
      – Jacco van Dorp
      2 days ago















    I am sorry, I am not sure if I understand this correctly. The v_decorate is to add an extra argument name to the original function? don't understand how to combine this to my same name functions.. Orz
    – Timmy Lin
    2 days ago





    I am sorry, I am not sure if I understand this correctly. The v_decorate is to add an extra argument name to the original function? don't understand how to combine this to my same name functions.. Orz
    – Timmy Lin
    2 days ago













    Doing this is nothing different from the first example I wrote in description.. passing version to v_decorate and put into called function is kinda extra steps. Modify my function to function(self): print(f'for version self.version') can do the exactly same thing without decorator..
    – Timmy Lin
    2 days ago





    Doing this is nothing different from the first example I wrote in description.. passing version to v_decorate and put into called function is kinda extra steps. Modify my function to function(self): print(f'for version self.version') can do the exactly same thing without decorator..
    – Timmy Lin
    2 days ago





    4




    4




    I don't see what this decorator actually accomplishes ?
    – Jacco van Dorp
    2 days ago




    I don't see what this decorator actually accomplishes ?
    – Jacco van Dorp
    2 days ago










    up vote
    0
    down vote













    I'm not a python developer but I can't help but wonder why you don't just do something like this:



    class Product(object):
    def __init__(self, version):
    self.version = version
    def function(self):
    print('for version ' + self.version)





    share|improve this answer




















    • Because this is just a example that make ppl easier to understand what I was trying to do. The function is not only printing things but do a lot of operations. Actually I don't even need to self.version to be passed into function method, I just need it to locate which function I want to load while program is running.
      – Timmy Lin
      yesterday















    up vote
    0
    down vote













    I'm not a python developer but I can't help but wonder why you don't just do something like this:



    class Product(object):
    def __init__(self, version):
    self.version = version
    def function(self):
    print('for version ' + self.version)





    share|improve this answer




















    • Because this is just a example that make ppl easier to understand what I was trying to do. The function is not only printing things but do a lot of operations. Actually I don't even need to self.version to be passed into function method, I just need it to locate which function I want to load while program is running.
      – Timmy Lin
      yesterday













    up vote
    0
    down vote










    up vote
    0
    down vote









    I'm not a python developer but I can't help but wonder why you don't just do something like this:



    class Product(object):
    def __init__(self, version):
    self.version = version
    def function(self):
    print('for version ' + self.version)





    share|improve this answer












    I'm not a python developer but I can't help but wonder why you don't just do something like this:



    class Product(object):
    def __init__(self, version):
    self.version = version
    def function(self):
    print('for version ' + self.version)






    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered 2 days ago









    Jack

    560415




    560415











    • Because this is just a example that make ppl easier to understand what I was trying to do. The function is not only printing things but do a lot of operations. Actually I don't even need to self.version to be passed into function method, I just need it to locate which function I want to load while program is running.
      – Timmy Lin
      yesterday

















    • Because this is just a example that make ppl easier to understand what I was trying to do. The function is not only printing things but do a lot of operations. Actually I don't even need to self.version to be passed into function method, I just need it to locate which function I want to load while program is running.
      – Timmy Lin
      yesterday
















    Because this is just a example that make ppl easier to understand what I was trying to do. The function is not only printing things but do a lot of operations. Actually I don't even need to self.version to be passed into function method, I just need it to locate which function I want to load while program is running.
    – Timmy Lin
    yesterday





    Because this is just a example that make ppl easier to understand what I was trying to do. The function is not only printing things but do a lot of operations. Actually I don't even need to self.version to be passed into function method, I just need it to locate which function I want to load while program is running.
    – Timmy Lin
    yesterday











    up vote
    0
    down vote













    Or you can do, dict.get to call a function and do print in lambda if nothing is right:



    def func_1(self):
    print('for version 1.0')

    def func_2(self):
    print('for version 2.0')
    def function(self):
    funcs = "1.0": self.func_1,
    "2.0": self.func_2
    funcs.get(self.version,lambda: print(f'function not support self.version'))()


    Example:



    class Product(object):

    def __init__(self,version):
    self.version = version

    def func_1(self):
    print('for version 1.0')

    def func_2(self):
    print('for version 2.0')
    def function(self):
    funcs = "1.0": self.func_1,
    "2.0": self.func_2
    funcs.get(self.version,lambda: print(f'function not support self.version'))()
    Product('1.0').function()
    Product('2.0').function()
    Product('3.0').function()


    Output:



    for version 1.0
    for version 2.0
    function not support 3.0





    share|improve this answer
























      up vote
      0
      down vote













      Or you can do, dict.get to call a function and do print in lambda if nothing is right:



      def func_1(self):
      print('for version 1.0')

      def func_2(self):
      print('for version 2.0')
      def function(self):
      funcs = "1.0": self.func_1,
      "2.0": self.func_2
      funcs.get(self.version,lambda: print(f'function not support self.version'))()


      Example:



      class Product(object):

      def __init__(self,version):
      self.version = version

      def func_1(self):
      print('for version 1.0')

      def func_2(self):
      print('for version 2.0')
      def function(self):
      funcs = "1.0": self.func_1,
      "2.0": self.func_2
      funcs.get(self.version,lambda: print(f'function not support self.version'))()
      Product('1.0').function()
      Product('2.0').function()
      Product('3.0').function()


      Output:



      for version 1.0
      for version 2.0
      function not support 3.0





      share|improve this answer






















        up vote
        0
        down vote










        up vote
        0
        down vote









        Or you can do, dict.get to call a function and do print in lambda if nothing is right:



        def func_1(self):
        print('for version 1.0')

        def func_2(self):
        print('for version 2.0')
        def function(self):
        funcs = "1.0": self.func_1,
        "2.0": self.func_2
        funcs.get(self.version,lambda: print(f'function not support self.version'))()


        Example:



        class Product(object):

        def __init__(self,version):
        self.version = version

        def func_1(self):
        print('for version 1.0')

        def func_2(self):
        print('for version 2.0')
        def function(self):
        funcs = "1.0": self.func_1,
        "2.0": self.func_2
        funcs.get(self.version,lambda: print(f'function not support self.version'))()
        Product('1.0').function()
        Product('2.0').function()
        Product('3.0').function()


        Output:



        for version 1.0
        for version 2.0
        function not support 3.0





        share|improve this answer












        Or you can do, dict.get to call a function and do print in lambda if nothing is right:



        def func_1(self):
        print('for version 1.0')

        def func_2(self):
        print('for version 2.0')
        def function(self):
        funcs = "1.0": self.func_1,
        "2.0": self.func_2
        funcs.get(self.version,lambda: print(f'function not support self.version'))()


        Example:



        class Product(object):

        def __init__(self,version):
        self.version = version

        def func_1(self):
        print('for version 1.0')

        def func_2(self):
        print('for version 2.0')
        def function(self):
        funcs = "1.0": self.func_1,
        "2.0": self.func_2
        funcs.get(self.version,lambda: print(f'function not support self.version'))()
        Product('1.0').function()
        Product('2.0').function()
        Product('3.0').function()


        Output:



        for version 1.0
        for version 2.0
        function not support 3.0






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered yesterday









        U9-Forward

        4,9652428




        4,9652428



























             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52252054%2fsame-name-functions-in-same-class-elegant-way-to-determine-which-to-call%23new-answer', 'question_page');

            );

            Post as a guest













































































            Comments

            Popular posts from this blog

            What does second last employer means? [closed]

            List of Gilmore Girls characters

            Confectionery