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;
}
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:
- I cannot forego the Singleton version. I used it too many times, so I cannot just rewrite it.
- The new class should access an object variable where the original accessed a class one
- All
staticmethod
decorators need to be removed - All methods need an additional
self
argument. - Need to define an
__init__
method - 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
|
show 1 more comment
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:
- I cannot forego the Singleton version. I used it too many times, so I cannot just rewrite it.
- The new class should access an object variable where the original accessed a class one
- All
staticmethod
decorators need to be removed - All methods need an additional
self
argument. - Need to define an
__init__
method - 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
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 withsuper()
, until you fix them
– Mstaino
Jan 4 at 15:03
@MstainoA
is hard-coded in the static methods; how do you plan on using those as instance methods?
– chepner
Jan 4 at 15:06
|
show 1 more comment
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:
- I cannot forego the Singleton version. I used it too many times, so I cannot just rewrite it.
- The new class should access an object variable where the original accessed a class one
- All
staticmethod
decorators need to be removed - All methods need an additional
self
argument. - Need to define an
__init__
method - 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
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:
- I cannot forego the Singleton version. I used it too many times, so I cannot just rewrite it.
- The new class should access an object variable where the original accessed a class one
- All
staticmethod
decorators need to be removed - All methods need an additional
self
argument. - Need to define an
__init__
method - 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
python python-3.x
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 withsuper()
, until you fix them
– Mstaino
Jan 4 at 15:03
@MstainoA
is hard-coded in the static methods; how do you plan on using those as instance methods?
– chepner
Jan 4 at 15:06
|
show 1 more comment
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 withsuper()
, until you fix them
– Mstaino
Jan 4 at 15:03
@MstainoA
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
|
show 1 more comment
4 Answers
4
active
oldest
votes
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:
- Strip the
staticmethod
decorator - Replace each method's argument list with
*args
- Manually identify if the first argument (if any) is an instance of A. If it is not, set
self = A
, otherwise,self = args[0]
. - 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.
add a comment |
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))
()
add a comment |
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)
add a comment |
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.
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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:
- Strip the
staticmethod
decorator - Replace each method's argument list with
*args
- Manually identify if the first argument (if any) is an instance of A. If it is not, set
self = A
, otherwise,self = args[0]
. - 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.
add a comment |
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:
- Strip the
staticmethod
decorator - Replace each method's argument list with
*args
- Manually identify if the first argument (if any) is an instance of A. If it is not, set
self = A
, otherwise,self = args[0]
. - 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.
add a comment |
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:
- Strip the
staticmethod
decorator - Replace each method's argument list with
*args
- Manually identify if the first argument (if any) is an instance of A. If it is not, set
self = A
, otherwise,self = args[0]
. - 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.
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:
- Strip the
staticmethod
decorator - Replace each method's argument list with
*args
- Manually identify if the first argument (if any) is an instance of A. If it is not, set
self = A
, otherwise,self = args[0]
. - 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.
answered Jan 4 at 15:26
chepnerchepner
263k36253345
263k36253345
add a comment |
add a comment |
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))
()
add a comment |
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))
()
add a comment |
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))
()
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))
()
answered Jan 4 at 17:12
Serge BallestaSerge Ballesta
82k963136
82k963136
add a comment |
add a comment |
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)
add a comment |
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)
add a comment |
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)
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)
answered Jan 4 at 17:19
quacodasquacodas
738
738
add a comment |
add a comment |
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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