Create a “normal” class from class with all `static` methods





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















Once upon a time I wrote a Singleton class. The implementation is a class consisting only of static methods - I added an exception on __init__ for illustration purposes only, I do not even have an __init__, but will need one later:



class A:
x = 3
def __init__(self): raise Exception('Oh no you did not!')
@staticmethod
def m1():
print(A.x)
@staticmethod
def m2(n):
A.y=8


Fast forward some years, and now I need to create instances of the Singleton - please no judgement :). The requirements:




  1. I cannot forego the Singleton version. I used it too many times, so I cannot just rewrite it.

  2. The new class should access an object variable where the original accessed a class one

  3. All staticmethod decorators need to be removed

  4. All methods need an additional self argument.

  5. Need to define an __init__ method

  6. I do not want to copy paste and fix the paste - the class is long, and will be subject to future changes that should always apply to both versions, holding to the above requirements. As such construction of the new version should be dynamic, and rely on the original version (I already screwed myself once not thinking ahead).


Solutions may be implemented in the original class, but I think it might be impossible, so a function taking the original class and spewing out a new one would probably be the way to go:



class A:
x = 3 #No need to touch class variable definitions.
def __init__(self): pass #Maybe the init method will be an argument

def m1(self):
print(self.x)

def m2(self,n):
self.y = n


Any solution (hacky or not) that dynamically creates stuff is fine. I am currently looking at building this using inspect, though I am not sure it will pan out.










share|improve this question


















  • 5





    I agree with "I already screwed myself once not thinking ahead", which is exactly why I disagree with "I used it too many times, so I cannot just rewrite it". Fix it now. Refactor the code you already have. Doing anything else (eg coming up with hacky workarounds) is simply shooting yourself in the foot. Even if you get a workaround to work now it can come around and bite you later

    – DeepSpace
    Jan 4 at 14:47













  • @DeepSpace I wish, and completely agree. My time/usage breadth->0 right now. I cannot afford to start refactoring right now with a chance of breaking something that works. I do hope to get to a full refactor in a few weeks time, but this is something I will be solving today, one way or another. The good thing is any new code using the new objects will likely be unaffected by a refactor later, though, as you hint, I can never be sure.

    – kabanus
    Jan 4 at 14:58






  • 1





    How many static methods are we talking about? I can't imagine it will take that long to just copy it and make the necessary changes by hand. The statements "will be subject to future changes that should always apply to both versions" and "I hope to get to a full refactor in a few weeks" are somewhat mutually exclusive; commit to the refactor in lieu of trying to keep two parallel code bases in sync.

    – chepner
    Jan 4 at 15:03













  • You can use static/class methods as instace methods (no need to rewrite them, if that helps). Also, shooting ideas, you can use a child class with instance methods passing them with super(), until you fix them

    – Mstaino
    Jan 4 at 15:03











  • @Mstaino A is hard-coded in the static methods; how do you plan on using those as instance methods?

    – chepner
    Jan 4 at 15:06


















0















Once upon a time I wrote a Singleton class. The implementation is a class consisting only of static methods - I added an exception on __init__ for illustration purposes only, I do not even have an __init__, but will need one later:



class A:
x = 3
def __init__(self): raise Exception('Oh no you did not!')
@staticmethod
def m1():
print(A.x)
@staticmethod
def m2(n):
A.y=8


Fast forward some years, and now I need to create instances of the Singleton - please no judgement :). The requirements:




  1. I cannot forego the Singleton version. I used it too many times, so I cannot just rewrite it.

  2. The new class should access an object variable where the original accessed a class one

  3. All staticmethod decorators need to be removed

  4. All methods need an additional self argument.

  5. Need to define an __init__ method

  6. I do not want to copy paste and fix the paste - the class is long, and will be subject to future changes that should always apply to both versions, holding to the above requirements. As such construction of the new version should be dynamic, and rely on the original version (I already screwed myself once not thinking ahead).


Solutions may be implemented in the original class, but I think it might be impossible, so a function taking the original class and spewing out a new one would probably be the way to go:



class A:
x = 3 #No need to touch class variable definitions.
def __init__(self): pass #Maybe the init method will be an argument

def m1(self):
print(self.x)

def m2(self,n):
self.y = n


Any solution (hacky or not) that dynamically creates stuff is fine. I am currently looking at building this using inspect, though I am not sure it will pan out.










share|improve this question


















  • 5





    I agree with "I already screwed myself once not thinking ahead", which is exactly why I disagree with "I used it too many times, so I cannot just rewrite it". Fix it now. Refactor the code you already have. Doing anything else (eg coming up with hacky workarounds) is simply shooting yourself in the foot. Even if you get a workaround to work now it can come around and bite you later

    – DeepSpace
    Jan 4 at 14:47













  • @DeepSpace I wish, and completely agree. My time/usage breadth->0 right now. I cannot afford to start refactoring right now with a chance of breaking something that works. I do hope to get to a full refactor in a few weeks time, but this is something I will be solving today, one way or another. The good thing is any new code using the new objects will likely be unaffected by a refactor later, though, as you hint, I can never be sure.

    – kabanus
    Jan 4 at 14:58






  • 1





    How many static methods are we talking about? I can't imagine it will take that long to just copy it and make the necessary changes by hand. The statements "will be subject to future changes that should always apply to both versions" and "I hope to get to a full refactor in a few weeks" are somewhat mutually exclusive; commit to the refactor in lieu of trying to keep two parallel code bases in sync.

    – chepner
    Jan 4 at 15:03













  • You can use static/class methods as instace methods (no need to rewrite them, if that helps). Also, shooting ideas, you can use a child class with instance methods passing them with super(), until you fix them

    – Mstaino
    Jan 4 at 15:03











  • @Mstaino A is hard-coded in the static methods; how do you plan on using those as instance methods?

    – chepner
    Jan 4 at 15:06














0












0








0








Once upon a time I wrote a Singleton class. The implementation is a class consisting only of static methods - I added an exception on __init__ for illustration purposes only, I do not even have an __init__, but will need one later:



class A:
x = 3
def __init__(self): raise Exception('Oh no you did not!')
@staticmethod
def m1():
print(A.x)
@staticmethod
def m2(n):
A.y=8


Fast forward some years, and now I need to create instances of the Singleton - please no judgement :). The requirements:




  1. I cannot forego the Singleton version. I used it too many times, so I cannot just rewrite it.

  2. The new class should access an object variable where the original accessed a class one

  3. All staticmethod decorators need to be removed

  4. All methods need an additional self argument.

  5. Need to define an __init__ method

  6. I do not want to copy paste and fix the paste - the class is long, and will be subject to future changes that should always apply to both versions, holding to the above requirements. As such construction of the new version should be dynamic, and rely on the original version (I already screwed myself once not thinking ahead).


Solutions may be implemented in the original class, but I think it might be impossible, so a function taking the original class and spewing out a new one would probably be the way to go:



class A:
x = 3 #No need to touch class variable definitions.
def __init__(self): pass #Maybe the init method will be an argument

def m1(self):
print(self.x)

def m2(self,n):
self.y = n


Any solution (hacky or not) that dynamically creates stuff is fine. I am currently looking at building this using inspect, though I am not sure it will pan out.










share|improve this question














Once upon a time I wrote a Singleton class. The implementation is a class consisting only of static methods - I added an exception on __init__ for illustration purposes only, I do not even have an __init__, but will need one later:



class A:
x = 3
def __init__(self): raise Exception('Oh no you did not!')
@staticmethod
def m1():
print(A.x)
@staticmethod
def m2(n):
A.y=8


Fast forward some years, and now I need to create instances of the Singleton - please no judgement :). The requirements:




  1. I cannot forego the Singleton version. I used it too many times, so I cannot just rewrite it.

  2. The new class should access an object variable where the original accessed a class one

  3. All staticmethod decorators need to be removed

  4. All methods need an additional self argument.

  5. Need to define an __init__ method

  6. I do not want to copy paste and fix the paste - the class is long, and will be subject to future changes that should always apply to both versions, holding to the above requirements. As such construction of the new version should be dynamic, and rely on the original version (I already screwed myself once not thinking ahead).


Solutions may be implemented in the original class, but I think it might be impossible, so a function taking the original class and spewing out a new one would probably be the way to go:



class A:
x = 3 #No need to touch class variable definitions.
def __init__(self): pass #Maybe the init method will be an argument

def m1(self):
print(self.x)

def m2(self,n):
self.y = n


Any solution (hacky or not) that dynamically creates stuff is fine. I am currently looking at building this using inspect, though I am not sure it will pan out.







python python-3.x






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Jan 4 at 14:38









kabanuskabanus

12.7k31543




12.7k31543








  • 5





    I agree with "I already screwed myself once not thinking ahead", which is exactly why I disagree with "I used it too many times, so I cannot just rewrite it". Fix it now. Refactor the code you already have. Doing anything else (eg coming up with hacky workarounds) is simply shooting yourself in the foot. Even if you get a workaround to work now it can come around and bite you later

    – DeepSpace
    Jan 4 at 14:47













  • @DeepSpace I wish, and completely agree. My time/usage breadth->0 right now. I cannot afford to start refactoring right now with a chance of breaking something that works. I do hope to get to a full refactor in a few weeks time, but this is something I will be solving today, one way or another. The good thing is any new code using the new objects will likely be unaffected by a refactor later, though, as you hint, I can never be sure.

    – kabanus
    Jan 4 at 14:58






  • 1





    How many static methods are we talking about? I can't imagine it will take that long to just copy it and make the necessary changes by hand. The statements "will be subject to future changes that should always apply to both versions" and "I hope to get to a full refactor in a few weeks" are somewhat mutually exclusive; commit to the refactor in lieu of trying to keep two parallel code bases in sync.

    – chepner
    Jan 4 at 15:03













  • You can use static/class methods as instace methods (no need to rewrite them, if that helps). Also, shooting ideas, you can use a child class with instance methods passing them with super(), until you fix them

    – Mstaino
    Jan 4 at 15:03











  • @Mstaino A is hard-coded in the static methods; how do you plan on using those as instance methods?

    – chepner
    Jan 4 at 15:06














  • 5





    I agree with "I already screwed myself once not thinking ahead", which is exactly why I disagree with "I used it too many times, so I cannot just rewrite it". Fix it now. Refactor the code you already have. Doing anything else (eg coming up with hacky workarounds) is simply shooting yourself in the foot. Even if you get a workaround to work now it can come around and bite you later

    – DeepSpace
    Jan 4 at 14:47













  • @DeepSpace I wish, and completely agree. My time/usage breadth->0 right now. I cannot afford to start refactoring right now with a chance of breaking something that works. I do hope to get to a full refactor in a few weeks time, but this is something I will be solving today, one way or another. The good thing is any new code using the new objects will likely be unaffected by a refactor later, though, as you hint, I can never be sure.

    – kabanus
    Jan 4 at 14:58






  • 1





    How many static methods are we talking about? I can't imagine it will take that long to just copy it and make the necessary changes by hand. The statements "will be subject to future changes that should always apply to both versions" and "I hope to get to a full refactor in a few weeks" are somewhat mutually exclusive; commit to the refactor in lieu of trying to keep two parallel code bases in sync.

    – chepner
    Jan 4 at 15:03













  • You can use static/class methods as instace methods (no need to rewrite them, if that helps). Also, shooting ideas, you can use a child class with instance methods passing them with super(), until you fix them

    – Mstaino
    Jan 4 at 15:03











  • @Mstaino A is hard-coded in the static methods; how do you plan on using those as instance methods?

    – chepner
    Jan 4 at 15:06








5




5





I agree with "I already screwed myself once not thinking ahead", which is exactly why I disagree with "I used it too many times, so I cannot just rewrite it". Fix it now. Refactor the code you already have. Doing anything else (eg coming up with hacky workarounds) is simply shooting yourself in the foot. Even if you get a workaround to work now it can come around and bite you later

– DeepSpace
Jan 4 at 14:47







I agree with "I already screwed myself once not thinking ahead", which is exactly why I disagree with "I used it too many times, so I cannot just rewrite it". Fix it now. Refactor the code you already have. Doing anything else (eg coming up with hacky workarounds) is simply shooting yourself in the foot. Even if you get a workaround to work now it can come around and bite you later

– DeepSpace
Jan 4 at 14:47















@DeepSpace I wish, and completely agree. My time/usage breadth->0 right now. I cannot afford to start refactoring right now with a chance of breaking something that works. I do hope to get to a full refactor in a few weeks time, but this is something I will be solving today, one way or another. The good thing is any new code using the new objects will likely be unaffected by a refactor later, though, as you hint, I can never be sure.

– kabanus
Jan 4 at 14:58





@DeepSpace I wish, and completely agree. My time/usage breadth->0 right now. I cannot afford to start refactoring right now with a chance of breaking something that works. I do hope to get to a full refactor in a few weeks time, but this is something I will be solving today, one way or another. The good thing is any new code using the new objects will likely be unaffected by a refactor later, though, as you hint, I can never be sure.

– kabanus
Jan 4 at 14:58




1




1





How many static methods are we talking about? I can't imagine it will take that long to just copy it and make the necessary changes by hand. The statements "will be subject to future changes that should always apply to both versions" and "I hope to get to a full refactor in a few weeks" are somewhat mutually exclusive; commit to the refactor in lieu of trying to keep two parallel code bases in sync.

– chepner
Jan 4 at 15:03







How many static methods are we talking about? I can't imagine it will take that long to just copy it and make the necessary changes by hand. The statements "will be subject to future changes that should always apply to both versions" and "I hope to get to a full refactor in a few weeks" are somewhat mutually exclusive; commit to the refactor in lieu of trying to keep two parallel code bases in sync.

– chepner
Jan 4 at 15:03















You can use static/class methods as instace methods (no need to rewrite them, if that helps). Also, shooting ideas, you can use a child class with instance methods passing them with super(), until you fix them

– Mstaino
Jan 4 at 15:03





You can use static/class methods as instace methods (no need to rewrite them, if that helps). Also, shooting ideas, you can use a child class with instance methods passing them with super(), until you fix them

– Mstaino
Jan 4 at 15:03













@Mstaino A is hard-coded in the static methods; how do you plan on using those as instance methods?

– chepner
Jan 4 at 15:06





@Mstaino A is hard-coded in the static methods; how do you plan on using those as instance methods?

– chepner
Jan 4 at 15:06












4 Answers
4






active

oldest

votes


















2














I'm not sure this is sufficient, but I think the following modification can be used both as your original singleton and as a normal class. There's a fair amount of boilerplate, but it's isolated to the class, not the code that uses the class.



class A:

def __init__(self):
pass

def m1(*args):
# A.m1() means args will be empty
if args and isinstance(args[0], A):
self = args[0]
else:
self = A

print(self.x)

def m2(*args):
if isinstance(args[0], A):
self, n = args
else:
self = A
n = args[0]

self.y = n


Essentially, you'll do the following to each method:




  1. Strip the staticmethod decorator

  2. Replace each method's argument list with *args

  3. Manually identify if the first argument (if any) is an instance of A. If it is not, set self = A, otherwise, self = args[0].

  4. Manually create local variables for each of the old parameters, using the appropriate element of *args based on what you find in step 3.


For example, A.m1() results in print(A.x), while a = A(); a.mi() results in print(a.x). Likewise, A.m2(8) is A.y = 8 while a.m2(8) is a.y = 8.



I would be hesitant to try to automate this further; you'll probably spend more time identifying and trying to work around corner cases than you would by updating each method manually.






share|improve this answer































    2














    It will be hard to convert a static singleton class where all side effects can only affect the class itself to a normal class where side effects would only affect the instance objects. But it is possible to do the opposite: convert a normal class to a singleton static class simply by making the static class own a unique instance of the normal class and delegates all its methods call and attribute accesses to it.



    A metaclass could do the job. This one creates a special attribute _own to hold an instance of its model class, explicitely creates methods for it with the appropriate signature (it also keeps docstrings if any) just delegating calls to _own, and also delegates all attribute accesses to _own



    import inspect

    class Singletoner(type):
    def __getattr__(self, attr): # delegates attribute accesses
    return getattr(self._own, attr)
    def __new__(cls, name, bases, namespace, **kwds):
    obj = type.__new__(cls, name, bases, namespace)
    X = kwds['model'] # the model class is expected with the model keyword
    obj._own = X()
    for name, func in inspect.getmembers(X, inspect.isfunction):
    if name != '__init__':
    _trans(name, func, obj) # tranfers all methods other than __init__
    return obj

    def _trans(name, func, clazz):
    def f(*args,**kwargs):
    return func(clazz._own, *args, **kwargs)
    sig = inspect.signature(func) # copy signature just removing the initial param
    parameters = sig.parameters
    params = [t[1] for t in list(sig.parameters.items())[1:]]
    f.__signature__ = sig.replace(parameters = params)
    f.__doc__ = func.__doc__
    setattr(clazz, name, f)


    With your example, the non singleton class would b:



    class A:
    x = 3
    def __init__(self): pass
    def m1(self):
    print(self.x)
    def m2(self, n):
    self.y=n


    Its singleton delegator could be declared as:



    class B(metaclass=Singletoner, model=A):
    pass


    You can they use it simply:



    >>> B.m1()
    3
    >>> B.m2(6)
    >>> B.x
    3
    >>> B.y
    6
    >>> import inspect
    >>> print(inspect.signature(B.m2))
    (n)
    >>> print(inspect.signature(B.m1))
    ()





    share|improve this answer































      1














      To me it seems the biggest problem is having the method call self.x instead of A.x This is gonna be a silly idea, but you said hacky fixes are okay, so could we just backup all the values for class attributes, change them to match the instance attributes, then call the staticmethod, then restore all the values? If you would allow that, something like this might work:



      import types

      class A:
      x=3

      def __init__(self):
      pass

      @staticmethod
      def m1():
      print(A.x)
      @staticmethod
      def m2(n):
      A.y = n

      def __getattribute__(self, name):
      Aattr = getattr(type(self),name) # get the class attribute of the same name to see if it is a function
      if isinstance(Aattr,types.FunctionType):
      def hackyfunction(self,*args,**kwargs):
      ... # copy all previous values of A attributes, replace them with instance attributes
      returnvalue = Aattr(*args, **kwargs)
      ... # change everything back
      return returnvalue
      method = types.MethodType(hackyfunction, self)
      return method
      # now it can't be a function, so just return normally. self.name will default to A.name if there is no instance attribute
      return object.__getattribute__(self,name)





      share|improve this answer































        0














        Thank you all for your great ideas, they helped me implement what I wanted, before I hit a duh moment:



        I renamed the original class, fixed it to work normally, and created an instance of it with the same old name.



        All code that imported the file used the same name as is, with no modification whatsoever. I really should have thought of this before. Seriously.





        In case someone really wants the fruit of everyone's work, this is what I did using all the ideas (somewhat tested)



        import inspect
        import re
        def method_remove_static(m,cls_name):
        source = inspect.getsourcelines(m)[0]
        for i in range(len(source)):
        if 'staticmethod' in source[i]:
        del source[i]
        break
        for j in range(i,len(source)):
        if ' def ' in source[i]:
        source[i] = source[i].replace('(','(self,',1).lstrip()
        break

        return re.sub(r'(?<!w)%s.'%cls_name,'self.',''.join(source))

        def class_remove_indentation(cls):
        source = inspect.getsourcelines(cls)[0]
        for i in range(len(source)):
        if ' class ' in source[i]:
        source[i] = source[i].lstrip()
        break
        return ''.join(source)

        def regular_var(x):
        return (not inspect.ismethod(x) and
        not inspect.isbuiltin(x) and
        not inspect.ismethoddescriptor(x) and
        not inspect.isclass(x) and
        not inspect.isfunction(x))

        #MAIN FUNCTION
        def class_remove_static(cls,init = None,context = {}):
        class newCls:
        if init is not None:
        __init__ = init

        #Inner classes
        for name,incls in inspect.getmembers(cls,predicate=lambda x: inspect.isclass(x)):
        if name == "__class__": continue
        exec(class_remove_indentation(incls),context)
        setattr(newCls,name,context[name])

        __init__ = init
        #static methods are listed as functions
        for name,method in inspect.getmembers(cls,predicate=inspect.isfunction):
        if name == "__init__": continue
        exec(method_remove_static(method,cls.__name__),context)
        setattr(newCls,name,context[name])

        #Class variables defined at time of call (almost)
        for name,var in inspect.getmembers(cls,predicate=regular_var):
        if (name == '__doc__' or name == '__module__' or
        name == '__weakref__' or name =='__dict__'): continue
        setattr(newCls,name,var)

        return newCls


        This literally re-compiles the source code. I am sure the regular expression sub can break some use-cases, but it worked for me. Provide your locals() as context if your class is based on variables in the module you are using this, and an optional init function that must accept at least one parameter (colloquially named self).



        The is a simple search and replace, with the very un-loved exec. Use at your own discretion if you really need it.






        share|improve this answer
























        • Note this solution is highly specialized. For one, I only have static methods, no regular ones, and the regular expression I am sure might break on some examples.

          – kabanus
          Jan 7 at 19:44












        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',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        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%2f54041039%2fcreate-a-normal-class-from-class-with-all-static-methods%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        4 Answers
        4






        active

        oldest

        votes








        4 Answers
        4






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        2














        I'm not sure this is sufficient, but I think the following modification can be used both as your original singleton and as a normal class. There's a fair amount of boilerplate, but it's isolated to the class, not the code that uses the class.



        class A:

        def __init__(self):
        pass

        def m1(*args):
        # A.m1() means args will be empty
        if args and isinstance(args[0], A):
        self = args[0]
        else:
        self = A

        print(self.x)

        def m2(*args):
        if isinstance(args[0], A):
        self, n = args
        else:
        self = A
        n = args[0]

        self.y = n


        Essentially, you'll do the following to each method:




        1. Strip the staticmethod decorator

        2. Replace each method's argument list with *args

        3. Manually identify if the first argument (if any) is an instance of A. If it is not, set self = A, otherwise, self = args[0].

        4. Manually create local variables for each of the old parameters, using the appropriate element of *args based on what you find in step 3.


        For example, A.m1() results in print(A.x), while a = A(); a.mi() results in print(a.x). Likewise, A.m2(8) is A.y = 8 while a.m2(8) is a.y = 8.



        I would be hesitant to try to automate this further; you'll probably spend more time identifying and trying to work around corner cases than you would by updating each method manually.






        share|improve this answer




























          2














          I'm not sure this is sufficient, but I think the following modification can be used both as your original singleton and as a normal class. There's a fair amount of boilerplate, but it's isolated to the class, not the code that uses the class.



          class A:

          def __init__(self):
          pass

          def m1(*args):
          # A.m1() means args will be empty
          if args and isinstance(args[0], A):
          self = args[0]
          else:
          self = A

          print(self.x)

          def m2(*args):
          if isinstance(args[0], A):
          self, n = args
          else:
          self = A
          n = args[0]

          self.y = n


          Essentially, you'll do the following to each method:




          1. Strip the staticmethod decorator

          2. Replace each method's argument list with *args

          3. Manually identify if the first argument (if any) is an instance of A. If it is not, set self = A, otherwise, self = args[0].

          4. Manually create local variables for each of the old parameters, using the appropriate element of *args based on what you find in step 3.


          For example, A.m1() results in print(A.x), while a = A(); a.mi() results in print(a.x). Likewise, A.m2(8) is A.y = 8 while a.m2(8) is a.y = 8.



          I would be hesitant to try to automate this further; you'll probably spend more time identifying and trying to work around corner cases than you would by updating each method manually.






          share|improve this answer


























            2












            2








            2







            I'm not sure this is sufficient, but I think the following modification can be used both as your original singleton and as a normal class. There's a fair amount of boilerplate, but it's isolated to the class, not the code that uses the class.



            class A:

            def __init__(self):
            pass

            def m1(*args):
            # A.m1() means args will be empty
            if args and isinstance(args[0], A):
            self = args[0]
            else:
            self = A

            print(self.x)

            def m2(*args):
            if isinstance(args[0], A):
            self, n = args
            else:
            self = A
            n = args[0]

            self.y = n


            Essentially, you'll do the following to each method:




            1. Strip the staticmethod decorator

            2. Replace each method's argument list with *args

            3. Manually identify if the first argument (if any) is an instance of A. If it is not, set self = A, otherwise, self = args[0].

            4. Manually create local variables for each of the old parameters, using the appropriate element of *args based on what you find in step 3.


            For example, A.m1() results in print(A.x), while a = A(); a.mi() results in print(a.x). Likewise, A.m2(8) is A.y = 8 while a.m2(8) is a.y = 8.



            I would be hesitant to try to automate this further; you'll probably spend more time identifying and trying to work around corner cases than you would by updating each method manually.






            share|improve this answer













            I'm not sure this is sufficient, but I think the following modification can be used both as your original singleton and as a normal class. There's a fair amount of boilerplate, but it's isolated to the class, not the code that uses the class.



            class A:

            def __init__(self):
            pass

            def m1(*args):
            # A.m1() means args will be empty
            if args and isinstance(args[0], A):
            self = args[0]
            else:
            self = A

            print(self.x)

            def m2(*args):
            if isinstance(args[0], A):
            self, n = args
            else:
            self = A
            n = args[0]

            self.y = n


            Essentially, you'll do the following to each method:




            1. Strip the staticmethod decorator

            2. Replace each method's argument list with *args

            3. Manually identify if the first argument (if any) is an instance of A. If it is not, set self = A, otherwise, self = args[0].

            4. Manually create local variables for each of the old parameters, using the appropriate element of *args based on what you find in step 3.


            For example, A.m1() results in print(A.x), while a = A(); a.mi() results in print(a.x). Likewise, A.m2(8) is A.y = 8 while a.m2(8) is a.y = 8.



            I would be hesitant to try to automate this further; you'll probably spend more time identifying and trying to work around corner cases than you would by updating each method manually.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Jan 4 at 15:26









            chepnerchepner

            263k36253345




            263k36253345

























                2














                It will be hard to convert a static singleton class where all side effects can only affect the class itself to a normal class where side effects would only affect the instance objects. But it is possible to do the opposite: convert a normal class to a singleton static class simply by making the static class own a unique instance of the normal class and delegates all its methods call and attribute accesses to it.



                A metaclass could do the job. This one creates a special attribute _own to hold an instance of its model class, explicitely creates methods for it with the appropriate signature (it also keeps docstrings if any) just delegating calls to _own, and also delegates all attribute accesses to _own



                import inspect

                class Singletoner(type):
                def __getattr__(self, attr): # delegates attribute accesses
                return getattr(self._own, attr)
                def __new__(cls, name, bases, namespace, **kwds):
                obj = type.__new__(cls, name, bases, namespace)
                X = kwds['model'] # the model class is expected with the model keyword
                obj._own = X()
                for name, func in inspect.getmembers(X, inspect.isfunction):
                if name != '__init__':
                _trans(name, func, obj) # tranfers all methods other than __init__
                return obj

                def _trans(name, func, clazz):
                def f(*args,**kwargs):
                return func(clazz._own, *args, **kwargs)
                sig = inspect.signature(func) # copy signature just removing the initial param
                parameters = sig.parameters
                params = [t[1] for t in list(sig.parameters.items())[1:]]
                f.__signature__ = sig.replace(parameters = params)
                f.__doc__ = func.__doc__
                setattr(clazz, name, f)


                With your example, the non singleton class would b:



                class A:
                x = 3
                def __init__(self): pass
                def m1(self):
                print(self.x)
                def m2(self, n):
                self.y=n


                Its singleton delegator could be declared as:



                class B(metaclass=Singletoner, model=A):
                pass


                You can they use it simply:



                >>> B.m1()
                3
                >>> B.m2(6)
                >>> B.x
                3
                >>> B.y
                6
                >>> import inspect
                >>> print(inspect.signature(B.m2))
                (n)
                >>> print(inspect.signature(B.m1))
                ()





                share|improve this answer




























                  2














                  It will be hard to convert a static singleton class where all side effects can only affect the class itself to a normal class where side effects would only affect the instance objects. But it is possible to do the opposite: convert a normal class to a singleton static class simply by making the static class own a unique instance of the normal class and delegates all its methods call and attribute accesses to it.



                  A metaclass could do the job. This one creates a special attribute _own to hold an instance of its model class, explicitely creates methods for it with the appropriate signature (it also keeps docstrings if any) just delegating calls to _own, and also delegates all attribute accesses to _own



                  import inspect

                  class Singletoner(type):
                  def __getattr__(self, attr): # delegates attribute accesses
                  return getattr(self._own, attr)
                  def __new__(cls, name, bases, namespace, **kwds):
                  obj = type.__new__(cls, name, bases, namespace)
                  X = kwds['model'] # the model class is expected with the model keyword
                  obj._own = X()
                  for name, func in inspect.getmembers(X, inspect.isfunction):
                  if name != '__init__':
                  _trans(name, func, obj) # tranfers all methods other than __init__
                  return obj

                  def _trans(name, func, clazz):
                  def f(*args,**kwargs):
                  return func(clazz._own, *args, **kwargs)
                  sig = inspect.signature(func) # copy signature just removing the initial param
                  parameters = sig.parameters
                  params = [t[1] for t in list(sig.parameters.items())[1:]]
                  f.__signature__ = sig.replace(parameters = params)
                  f.__doc__ = func.__doc__
                  setattr(clazz, name, f)


                  With your example, the non singleton class would b:



                  class A:
                  x = 3
                  def __init__(self): pass
                  def m1(self):
                  print(self.x)
                  def m2(self, n):
                  self.y=n


                  Its singleton delegator could be declared as:



                  class B(metaclass=Singletoner, model=A):
                  pass


                  You can they use it simply:



                  >>> B.m1()
                  3
                  >>> B.m2(6)
                  >>> B.x
                  3
                  >>> B.y
                  6
                  >>> import inspect
                  >>> print(inspect.signature(B.m2))
                  (n)
                  >>> print(inspect.signature(B.m1))
                  ()





                  share|improve this answer


























                    2












                    2








                    2







                    It will be hard to convert a static singleton class where all side effects can only affect the class itself to a normal class where side effects would only affect the instance objects. But it is possible to do the opposite: convert a normal class to a singleton static class simply by making the static class own a unique instance of the normal class and delegates all its methods call and attribute accesses to it.



                    A metaclass could do the job. This one creates a special attribute _own to hold an instance of its model class, explicitely creates methods for it with the appropriate signature (it also keeps docstrings if any) just delegating calls to _own, and also delegates all attribute accesses to _own



                    import inspect

                    class Singletoner(type):
                    def __getattr__(self, attr): # delegates attribute accesses
                    return getattr(self._own, attr)
                    def __new__(cls, name, bases, namespace, **kwds):
                    obj = type.__new__(cls, name, bases, namespace)
                    X = kwds['model'] # the model class is expected with the model keyword
                    obj._own = X()
                    for name, func in inspect.getmembers(X, inspect.isfunction):
                    if name != '__init__':
                    _trans(name, func, obj) # tranfers all methods other than __init__
                    return obj

                    def _trans(name, func, clazz):
                    def f(*args,**kwargs):
                    return func(clazz._own, *args, **kwargs)
                    sig = inspect.signature(func) # copy signature just removing the initial param
                    parameters = sig.parameters
                    params = [t[1] for t in list(sig.parameters.items())[1:]]
                    f.__signature__ = sig.replace(parameters = params)
                    f.__doc__ = func.__doc__
                    setattr(clazz, name, f)


                    With your example, the non singleton class would b:



                    class A:
                    x = 3
                    def __init__(self): pass
                    def m1(self):
                    print(self.x)
                    def m2(self, n):
                    self.y=n


                    Its singleton delegator could be declared as:



                    class B(metaclass=Singletoner, model=A):
                    pass


                    You can they use it simply:



                    >>> B.m1()
                    3
                    >>> B.m2(6)
                    >>> B.x
                    3
                    >>> B.y
                    6
                    >>> import inspect
                    >>> print(inspect.signature(B.m2))
                    (n)
                    >>> print(inspect.signature(B.m1))
                    ()





                    share|improve this answer













                    It will be hard to convert a static singleton class where all side effects can only affect the class itself to a normal class where side effects would only affect the instance objects. But it is possible to do the opposite: convert a normal class to a singleton static class simply by making the static class own a unique instance of the normal class and delegates all its methods call and attribute accesses to it.



                    A metaclass could do the job. This one creates a special attribute _own to hold an instance of its model class, explicitely creates methods for it with the appropriate signature (it also keeps docstrings if any) just delegating calls to _own, and also delegates all attribute accesses to _own



                    import inspect

                    class Singletoner(type):
                    def __getattr__(self, attr): # delegates attribute accesses
                    return getattr(self._own, attr)
                    def __new__(cls, name, bases, namespace, **kwds):
                    obj = type.__new__(cls, name, bases, namespace)
                    X = kwds['model'] # the model class is expected with the model keyword
                    obj._own = X()
                    for name, func in inspect.getmembers(X, inspect.isfunction):
                    if name != '__init__':
                    _trans(name, func, obj) # tranfers all methods other than __init__
                    return obj

                    def _trans(name, func, clazz):
                    def f(*args,**kwargs):
                    return func(clazz._own, *args, **kwargs)
                    sig = inspect.signature(func) # copy signature just removing the initial param
                    parameters = sig.parameters
                    params = [t[1] for t in list(sig.parameters.items())[1:]]
                    f.__signature__ = sig.replace(parameters = params)
                    f.__doc__ = func.__doc__
                    setattr(clazz, name, f)


                    With your example, the non singleton class would b:



                    class A:
                    x = 3
                    def __init__(self): pass
                    def m1(self):
                    print(self.x)
                    def m2(self, n):
                    self.y=n


                    Its singleton delegator could be declared as:



                    class B(metaclass=Singletoner, model=A):
                    pass


                    You can they use it simply:



                    >>> B.m1()
                    3
                    >>> B.m2(6)
                    >>> B.x
                    3
                    >>> B.y
                    6
                    >>> import inspect
                    >>> print(inspect.signature(B.m2))
                    (n)
                    >>> print(inspect.signature(B.m1))
                    ()






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 4 at 17:12









                    Serge BallestaSerge Ballesta

                    82k963136




                    82k963136























                        1














                        To me it seems the biggest problem is having the method call self.x instead of A.x This is gonna be a silly idea, but you said hacky fixes are okay, so could we just backup all the values for class attributes, change them to match the instance attributes, then call the staticmethod, then restore all the values? If you would allow that, something like this might work:



                        import types

                        class A:
                        x=3

                        def __init__(self):
                        pass

                        @staticmethod
                        def m1():
                        print(A.x)
                        @staticmethod
                        def m2(n):
                        A.y = n

                        def __getattribute__(self, name):
                        Aattr = getattr(type(self),name) # get the class attribute of the same name to see if it is a function
                        if isinstance(Aattr,types.FunctionType):
                        def hackyfunction(self,*args,**kwargs):
                        ... # copy all previous values of A attributes, replace them with instance attributes
                        returnvalue = Aattr(*args, **kwargs)
                        ... # change everything back
                        return returnvalue
                        method = types.MethodType(hackyfunction, self)
                        return method
                        # now it can't be a function, so just return normally. self.name will default to A.name if there is no instance attribute
                        return object.__getattribute__(self,name)





                        share|improve this answer




























                          1














                          To me it seems the biggest problem is having the method call self.x instead of A.x This is gonna be a silly idea, but you said hacky fixes are okay, so could we just backup all the values for class attributes, change them to match the instance attributes, then call the staticmethod, then restore all the values? If you would allow that, something like this might work:



                          import types

                          class A:
                          x=3

                          def __init__(self):
                          pass

                          @staticmethod
                          def m1():
                          print(A.x)
                          @staticmethod
                          def m2(n):
                          A.y = n

                          def __getattribute__(self, name):
                          Aattr = getattr(type(self),name) # get the class attribute of the same name to see if it is a function
                          if isinstance(Aattr,types.FunctionType):
                          def hackyfunction(self,*args,**kwargs):
                          ... # copy all previous values of A attributes, replace them with instance attributes
                          returnvalue = Aattr(*args, **kwargs)
                          ... # change everything back
                          return returnvalue
                          method = types.MethodType(hackyfunction, self)
                          return method
                          # now it can't be a function, so just return normally. self.name will default to A.name if there is no instance attribute
                          return object.__getattribute__(self,name)





                          share|improve this answer


























                            1












                            1








                            1







                            To me it seems the biggest problem is having the method call self.x instead of A.x This is gonna be a silly idea, but you said hacky fixes are okay, so could we just backup all the values for class attributes, change them to match the instance attributes, then call the staticmethod, then restore all the values? If you would allow that, something like this might work:



                            import types

                            class A:
                            x=3

                            def __init__(self):
                            pass

                            @staticmethod
                            def m1():
                            print(A.x)
                            @staticmethod
                            def m2(n):
                            A.y = n

                            def __getattribute__(self, name):
                            Aattr = getattr(type(self),name) # get the class attribute of the same name to see if it is a function
                            if isinstance(Aattr,types.FunctionType):
                            def hackyfunction(self,*args,**kwargs):
                            ... # copy all previous values of A attributes, replace them with instance attributes
                            returnvalue = Aattr(*args, **kwargs)
                            ... # change everything back
                            return returnvalue
                            method = types.MethodType(hackyfunction, self)
                            return method
                            # now it can't be a function, so just return normally. self.name will default to A.name if there is no instance attribute
                            return object.__getattribute__(self,name)





                            share|improve this answer













                            To me it seems the biggest problem is having the method call self.x instead of A.x This is gonna be a silly idea, but you said hacky fixes are okay, so could we just backup all the values for class attributes, change them to match the instance attributes, then call the staticmethod, then restore all the values? If you would allow that, something like this might work:



                            import types

                            class A:
                            x=3

                            def __init__(self):
                            pass

                            @staticmethod
                            def m1():
                            print(A.x)
                            @staticmethod
                            def m2(n):
                            A.y = n

                            def __getattribute__(self, name):
                            Aattr = getattr(type(self),name) # get the class attribute of the same name to see if it is a function
                            if isinstance(Aattr,types.FunctionType):
                            def hackyfunction(self,*args,**kwargs):
                            ... # copy all previous values of A attributes, replace them with instance attributes
                            returnvalue = Aattr(*args, **kwargs)
                            ... # change everything back
                            return returnvalue
                            method = types.MethodType(hackyfunction, self)
                            return method
                            # now it can't be a function, so just return normally. self.name will default to A.name if there is no instance attribute
                            return object.__getattribute__(self,name)






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Jan 4 at 17:19









                            quacodasquacodas

                            738




                            738























                                0














                                Thank you all for your great ideas, they helped me implement what I wanted, before I hit a duh moment:



                                I renamed the original class, fixed it to work normally, and created an instance of it with the same old name.



                                All code that imported the file used the same name as is, with no modification whatsoever. I really should have thought of this before. Seriously.





                                In case someone really wants the fruit of everyone's work, this is what I did using all the ideas (somewhat tested)



                                import inspect
                                import re
                                def method_remove_static(m,cls_name):
                                source = inspect.getsourcelines(m)[0]
                                for i in range(len(source)):
                                if 'staticmethod' in source[i]:
                                del source[i]
                                break
                                for j in range(i,len(source)):
                                if ' def ' in source[i]:
                                source[i] = source[i].replace('(','(self,',1).lstrip()
                                break

                                return re.sub(r'(?<!w)%s.'%cls_name,'self.',''.join(source))

                                def class_remove_indentation(cls):
                                source = inspect.getsourcelines(cls)[0]
                                for i in range(len(source)):
                                if ' class ' in source[i]:
                                source[i] = source[i].lstrip()
                                break
                                return ''.join(source)

                                def regular_var(x):
                                return (not inspect.ismethod(x) and
                                not inspect.isbuiltin(x) and
                                not inspect.ismethoddescriptor(x) and
                                not inspect.isclass(x) and
                                not inspect.isfunction(x))

                                #MAIN FUNCTION
                                def class_remove_static(cls,init = None,context = {}):
                                class newCls:
                                if init is not None:
                                __init__ = init

                                #Inner classes
                                for name,incls in inspect.getmembers(cls,predicate=lambda x: inspect.isclass(x)):
                                if name == "__class__": continue
                                exec(class_remove_indentation(incls),context)
                                setattr(newCls,name,context[name])

                                __init__ = init
                                #static methods are listed as functions
                                for name,method in inspect.getmembers(cls,predicate=inspect.isfunction):
                                if name == "__init__": continue
                                exec(method_remove_static(method,cls.__name__),context)
                                setattr(newCls,name,context[name])

                                #Class variables defined at time of call (almost)
                                for name,var in inspect.getmembers(cls,predicate=regular_var):
                                if (name == '__doc__' or name == '__module__' or
                                name == '__weakref__' or name =='__dict__'): continue
                                setattr(newCls,name,var)

                                return newCls


                                This literally re-compiles the source code. I am sure the regular expression sub can break some use-cases, but it worked for me. Provide your locals() as context if your class is based on variables in the module you are using this, and an optional init function that must accept at least one parameter (colloquially named self).



                                The is a simple search and replace, with the very un-loved exec. Use at your own discretion if you really need it.






                                share|improve this answer
























                                • Note this solution is highly specialized. For one, I only have static methods, no regular ones, and the regular expression I am sure might break on some examples.

                                  – kabanus
                                  Jan 7 at 19:44
















                                0














                                Thank you all for your great ideas, they helped me implement what I wanted, before I hit a duh moment:



                                I renamed the original class, fixed it to work normally, and created an instance of it with the same old name.



                                All code that imported the file used the same name as is, with no modification whatsoever. I really should have thought of this before. Seriously.





                                In case someone really wants the fruit of everyone's work, this is what I did using all the ideas (somewhat tested)



                                import inspect
                                import re
                                def method_remove_static(m,cls_name):
                                source = inspect.getsourcelines(m)[0]
                                for i in range(len(source)):
                                if 'staticmethod' in source[i]:
                                del source[i]
                                break
                                for j in range(i,len(source)):
                                if ' def ' in source[i]:
                                source[i] = source[i].replace('(','(self,',1).lstrip()
                                break

                                return re.sub(r'(?<!w)%s.'%cls_name,'self.',''.join(source))

                                def class_remove_indentation(cls):
                                source = inspect.getsourcelines(cls)[0]
                                for i in range(len(source)):
                                if ' class ' in source[i]:
                                source[i] = source[i].lstrip()
                                break
                                return ''.join(source)

                                def regular_var(x):
                                return (not inspect.ismethod(x) and
                                not inspect.isbuiltin(x) and
                                not inspect.ismethoddescriptor(x) and
                                not inspect.isclass(x) and
                                not inspect.isfunction(x))

                                #MAIN FUNCTION
                                def class_remove_static(cls,init = None,context = {}):
                                class newCls:
                                if init is not None:
                                __init__ = init

                                #Inner classes
                                for name,incls in inspect.getmembers(cls,predicate=lambda x: inspect.isclass(x)):
                                if name == "__class__": continue
                                exec(class_remove_indentation(incls),context)
                                setattr(newCls,name,context[name])

                                __init__ = init
                                #static methods are listed as functions
                                for name,method in inspect.getmembers(cls,predicate=inspect.isfunction):
                                if name == "__init__": continue
                                exec(method_remove_static(method,cls.__name__),context)
                                setattr(newCls,name,context[name])

                                #Class variables defined at time of call (almost)
                                for name,var in inspect.getmembers(cls,predicate=regular_var):
                                if (name == '__doc__' or name == '__module__' or
                                name == '__weakref__' or name =='__dict__'): continue
                                setattr(newCls,name,var)

                                return newCls


                                This literally re-compiles the source code. I am sure the regular expression sub can break some use-cases, but it worked for me. Provide your locals() as context if your class is based on variables in the module you are using this, and an optional init function that must accept at least one parameter (colloquially named self).



                                The is a simple search and replace, with the very un-loved exec. Use at your own discretion if you really need it.






                                share|improve this answer
























                                • Note this solution is highly specialized. For one, I only have static methods, no regular ones, and the regular expression I am sure might break on some examples.

                                  – kabanus
                                  Jan 7 at 19:44














                                0












                                0








                                0







                                Thank you all for your great ideas, they helped me implement what I wanted, before I hit a duh moment:



                                I renamed the original class, fixed it to work normally, and created an instance of it with the same old name.



                                All code that imported the file used the same name as is, with no modification whatsoever. I really should have thought of this before. Seriously.





                                In case someone really wants the fruit of everyone's work, this is what I did using all the ideas (somewhat tested)



                                import inspect
                                import re
                                def method_remove_static(m,cls_name):
                                source = inspect.getsourcelines(m)[0]
                                for i in range(len(source)):
                                if 'staticmethod' in source[i]:
                                del source[i]
                                break
                                for j in range(i,len(source)):
                                if ' def ' in source[i]:
                                source[i] = source[i].replace('(','(self,',1).lstrip()
                                break

                                return re.sub(r'(?<!w)%s.'%cls_name,'self.',''.join(source))

                                def class_remove_indentation(cls):
                                source = inspect.getsourcelines(cls)[0]
                                for i in range(len(source)):
                                if ' class ' in source[i]:
                                source[i] = source[i].lstrip()
                                break
                                return ''.join(source)

                                def regular_var(x):
                                return (not inspect.ismethod(x) and
                                not inspect.isbuiltin(x) and
                                not inspect.ismethoddescriptor(x) and
                                not inspect.isclass(x) and
                                not inspect.isfunction(x))

                                #MAIN FUNCTION
                                def class_remove_static(cls,init = None,context = {}):
                                class newCls:
                                if init is not None:
                                __init__ = init

                                #Inner classes
                                for name,incls in inspect.getmembers(cls,predicate=lambda x: inspect.isclass(x)):
                                if name == "__class__": continue
                                exec(class_remove_indentation(incls),context)
                                setattr(newCls,name,context[name])

                                __init__ = init
                                #static methods are listed as functions
                                for name,method in inspect.getmembers(cls,predicate=inspect.isfunction):
                                if name == "__init__": continue
                                exec(method_remove_static(method,cls.__name__),context)
                                setattr(newCls,name,context[name])

                                #Class variables defined at time of call (almost)
                                for name,var in inspect.getmembers(cls,predicate=regular_var):
                                if (name == '__doc__' or name == '__module__' or
                                name == '__weakref__' or name =='__dict__'): continue
                                setattr(newCls,name,var)

                                return newCls


                                This literally re-compiles the source code. I am sure the regular expression sub can break some use-cases, but it worked for me. Provide your locals() as context if your class is based on variables in the module you are using this, and an optional init function that must accept at least one parameter (colloquially named self).



                                The is a simple search and replace, with the very un-loved exec. Use at your own discretion if you really need it.






                                share|improve this answer













                                Thank you all for your great ideas, they helped me implement what I wanted, before I hit a duh moment:



                                I renamed the original class, fixed it to work normally, and created an instance of it with the same old name.



                                All code that imported the file used the same name as is, with no modification whatsoever. I really should have thought of this before. Seriously.





                                In case someone really wants the fruit of everyone's work, this is what I did using all the ideas (somewhat tested)



                                import inspect
                                import re
                                def method_remove_static(m,cls_name):
                                source = inspect.getsourcelines(m)[0]
                                for i in range(len(source)):
                                if 'staticmethod' in source[i]:
                                del source[i]
                                break
                                for j in range(i,len(source)):
                                if ' def ' in source[i]:
                                source[i] = source[i].replace('(','(self,',1).lstrip()
                                break

                                return re.sub(r'(?<!w)%s.'%cls_name,'self.',''.join(source))

                                def class_remove_indentation(cls):
                                source = inspect.getsourcelines(cls)[0]
                                for i in range(len(source)):
                                if ' class ' in source[i]:
                                source[i] = source[i].lstrip()
                                break
                                return ''.join(source)

                                def regular_var(x):
                                return (not inspect.ismethod(x) and
                                not inspect.isbuiltin(x) and
                                not inspect.ismethoddescriptor(x) and
                                not inspect.isclass(x) and
                                not inspect.isfunction(x))

                                #MAIN FUNCTION
                                def class_remove_static(cls,init = None,context = {}):
                                class newCls:
                                if init is not None:
                                __init__ = init

                                #Inner classes
                                for name,incls in inspect.getmembers(cls,predicate=lambda x: inspect.isclass(x)):
                                if name == "__class__": continue
                                exec(class_remove_indentation(incls),context)
                                setattr(newCls,name,context[name])

                                __init__ = init
                                #static methods are listed as functions
                                for name,method in inspect.getmembers(cls,predicate=inspect.isfunction):
                                if name == "__init__": continue
                                exec(method_remove_static(method,cls.__name__),context)
                                setattr(newCls,name,context[name])

                                #Class variables defined at time of call (almost)
                                for name,var in inspect.getmembers(cls,predicate=regular_var):
                                if (name == '__doc__' or name == '__module__' or
                                name == '__weakref__' or name =='__dict__'): continue
                                setattr(newCls,name,var)

                                return newCls


                                This literally re-compiles the source code. I am sure the regular expression sub can break some use-cases, but it worked for me. Provide your locals() as context if your class is based on variables in the module you are using this, and an optional init function that must accept at least one parameter (colloquially named self).



                                The is a simple search and replace, with the very un-loved exec. Use at your own discretion if you really need it.







                                share|improve this answer












                                share|improve this answer



                                share|improve this answer










                                answered Jan 4 at 18:35









                                kabanuskabanus

                                12.7k31543




                                12.7k31543













                                • Note this solution is highly specialized. For one, I only have static methods, no regular ones, and the regular expression I am sure might break on some examples.

                                  – kabanus
                                  Jan 7 at 19:44



















                                • Note this solution is highly specialized. For one, I only have static methods, no regular ones, and the regular expression I am sure might break on some examples.

                                  – kabanus
                                  Jan 7 at 19:44

















                                Note this solution is highly specialized. For one, I only have static methods, no regular ones, and the regular expression I am sure might break on some examples.

                                – kabanus
                                Jan 7 at 19:44





                                Note this solution is highly specialized. For one, I only have static methods, no regular ones, and the regular expression I am sure might break on some examples.

                                – kabanus
                                Jan 7 at 19:44


















                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54041039%2fcreate-a-normal-class-from-class-with-all-static-methods%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                Angular Downloading a file using contenturl with Basic Authentication

                                Olmecas

                                Can't read property showImagePicker of undefined in react native iOS