I am trying to implement multiple constructors in python and one of the suggestions (through online searching) was to use the classmethod. However, using this, I am having issues with code reuse and modularity. Here is an example where I can create an object based on a supplied file or through some other means:
class Image:
def __init__(self, filename):
self.image = lib.load(filename)
self.init_others()
#classmethod
def from_data(cls, data, header):
cls.image = lib.from_data(data, header)
cls.init_others()
return cos
def init_others(self):
# initialise some other variables
self.something = numpy.matrix(4,4)
Now it seems that I cannot do that. The cls.init_others() call fails by saying that I have not provided the object to call it on. I guess I can initialise things in the from_data function itself but then I repeat the code in the init method and the other "constructors". Does anyone know how I can call these other initialiser methods from these #classmethod marked functions? Or perhaps someone knows a better way to initialise these variables.
I come from a C++ background. So still trying to find my way around the python constructs.
Your class method should create and return a new instance of the class, not assign class attributes and return the class itself. As an alternative to the keyword arguments, you could do something like:
class Image:
def __init__(self, image):
self.image = image
self.init_others()
#classmethod
def from_data(cls, data, header):
return cls(lib.from_data(data, header))
#classmethod
def from_filename(cls, filename):
return cls(lib.load(filename))
def init_others(self):
# initialise some other variables
self.something = numpy.matrix(4, 4)
This adds the ability to create an instance if you already have the image, too.
I would recommend not trying to create multiple constructors, and use keyword arguments instead:
class Image(object):
def __init__(self, filename=None, data=None, header=None):
if filename is not None:
self.image = lib.load(filename)
elif data is not None and header is not None:
self.image = lib.from_data(data, header)
else:
raise ValueError("You must provide filename or both data and header")
self.init_others()
def init_others(self):
# initialise some other variables
self.something = numpy.matrix(4,4)
This is a more Pythonic way to handle this scenario.
You should always pass in self as the first argument to any method that will act on a class instance. Python will not automatically determine the instance you're trying to call the method for unless you do that. So if you want to use a class function like
the_image = Image("file.txt")
the_image.interpolate(foo,bar)
You need to define the method within Image as
def interpolate(self,foo,bar):
# Your code
Related
I have a python file which can be resumed as follow :
from external_libs import save
class FakeClass1(MotherFakeClass1):
#property
def field(self):
if self.settings['save_parameter_booelan']:#settings come from the mother class but irelevant
import FakeClass2.save as save
# I want to override the save method by the one defined in the FakeClass2
return BehaviorModifierField(super(FakClass1, self).field) #The behavior Modifier decorate the new field but it's irelevant of what it does.
return super(FakClass1, self).field
def fakeMethod(self, boolean_val):
save('blabla')
class FakeClass2:
#staticmethod
def save(test):
#irrelevant core of the method
The idea is here but I struggle to find the right to do this.
I think I could do it more properly if I could move the FakeClass2 in another file but I don't want to.
Do you have a better idea ?
A staticmethod is not the right choice, as its invoked via Class.method. Your save is not used like that. And even if it were, it's on FakeClass, not FakeClass2.
If you want to invoke a different save depending on the class, just add a save METHOD (not function!) and use the function of choice. E.g.
from library import standard_save
class A:
def work(self):
self.save()
def save(self):
standard_save()
class B(A):
def save(self):
do_something_else()
Don't pass a boolean; pass the function to be used.
import external_libs
class FakeClass1:
def __init__(self, save_function=external_libs.save):
self.save = save_function
# Does this method do anything other than change the save function
# to use? If not, it can be eliminated.
def field(self):
# Use self.save as the function to save things
def fakeMethod(self, boolean_val):
self.save('blabla')
class FakeClass2:
#staticmethod
def save(test):
#irrelevant core of the method
instance1 = FakeClass1(FakeClass2.save)
instance2 = FakeClass1() # Default of external_libs.save
I think you are overcomplicating things.
Having a boolean value determining the behaviour of the save method means that the save method behaves differently depending on the instance of the class, according to the boolean value of the instance.
If this is what you want, this is the simplest way I can think.
class FakeClass1(MotherFakeClass1):
def __init__(self):
#your __init__ here
def save(self):
if self.settings['save_parameter_booelan']:
FakeClass2.save()
#or whatwever method you want to use in this case,
#even if is not this class method or another class method
else:
raise NotImplementedError
#or whatever code should be executed by save
#when save_parameter_boolean is false
I am trying to improve my python code and have started using classes to group related methods and variables.
What is the best practice when using a function that is able to access the variables that are initialized in the class? Should I just access the variable in the function? Or explicitly pass the variable to make it clear that I am relying on it?
I've created two examples to show what I mean by this question. Which method is preferred?
# method 1
class UploadForm(object):
def __init__(self, form_data):
self.file_name = form_data.get('file_name')
def validate(self):
agency_name = self.extract_agency_name(self.file_name)
#staticmethod
def extract_agency_name(file_name):
pattern = re.search('^[CFS]Y\d{4} (.+?)[.](?:xls|csv)$', file_name, re.I)
if pattern:
agency_name = pattern.group(1)
return agency_name
# method 2
class UploadForm(object):
def __init__(self, form_data):
self.file_name = form_data.get('file_name')
def validate(self):
agency_name = self.extract_agency_name()
def extract_agency_name(self):
pattern = re.search('^[CFS]Y\d{4} (.+?)[.](?:xls|csv)$', self.file_name, re.I)
if pattern:
agency_name = pattern.group(1)
return agency_name
For reasons below method 2 is preferred.
A member variable should be accessed via self.
By using self, you are making clear that you are referencing file_name variable of the same object.
Decorators can become overheads.
Decorators are wrappers around a method or a variable.
Passing more argument is more memory consuming.
Each argument takes up memory.
I have a class for making sprites flyweight and I am using a decorator to call this class. Here is some code:
class flyweight:
def __init__(self, cls):
self._cls = cls
self.__instances = dict()
def __call__(self, title):
return self.__instances.setdefault((title), self._cls(title))
In this question I'll just simplify the code to show what is relevant.
#flyweight
class Sprite:
def __init__(self, title, surf=None):
self.title = title
self.surf = surf if surf is not None else pygame.image.load('Images/Sprites/'+title+'.png').convert_alpha()
self.w, self.h = self.surf.get_size()
#staticmethod
def from_colour(colour, size=(40,40)):
surf = pygame.Surface(size).convert(); surf.fill(colour)
return Sprite(colour, surf)
red = Sprite.from_colour((125,0,0))
But this gives me the error:
AttributeError: 'flyweight' object has no attribute 'from_colour'
Should I remodel my flyweight implementation or is there some way around this?
Once decorated, the name of the wrapped object automatically points to the returned results of the decorator. In this case, Sprite now stores an instance of flyweight, which in turns contains an attribute storing an instance of the original wrapped class Sprite. For instance, printing Sprite after the declarations gives: <__main__.flyweight object at 0x102373080>. However, the staticmethod from_colour can be called from _cls:
red = Sprite._cls.from_colour((125,0,0))
A flyweight decorator really ought to pass through all constructors to the underlying class, including #classmethod and #staticmethod alternate constructors. In fact, more generally, a class decorator really ought to preserve the wrapped class's entire public interface.
And, while we could easily modify flyweight to specifically pass through the rest of the Sprite interface, which in this case is just that from_colour method, that would be a pain for a less trivial class, or for a class that ever changes. And really, what's the point of making a decorator that only works with a single class?
So, let's change it to:
Take any constructor signature. Ideally we'd want to make it configurable on what part of the signature counts as the key,1 but to keep things from getting too complicated, let's just fix it as the first argument.
Pass through the entire public interface of the class, not just its __call__ interface.
So:
class flyweight:
def __init__(self, cls):
self._cls = cls
self.__instances = dict()
def __call__(self, key, *args, **kw):
return self.__instances.setdefault(key, self._cls(key, *args, **kw))
def __getattr__(self, name):
if not name.startswith('_'):
return getattr(self._cls, name)
1. Some other library I've used has a nice design for this for function memo caches. Probably cachetools. And it ought to make just as much sense for class construction caches.
Is it good style to create a separate method, in which I preprocess data, before I pass it to the constructor (in case the preprocessing is cumbersome), like so:
class C():
def __init__(self, input, more_input):
self.value = self.prepare_value(input, more_input)
def prepare_value(self, input, more_input):
#here I actually do some nontrivial stuff, over many lines
#for brevity I'm illustrating just a short, one-line operation
value = (input + more_input)/2
return value
print(C(10, 33).value) # has value 21.5
If you wanted to do it like this, then I'd suggest two things.
Make the prepare_value() method a static method by decorating with the #staticmethod decorator. Since it's not making any changes to the instance of the class itself, just returning a value then you shouldn't be making it a method of the instance. Hence, #staticmethod.
Signify that the method should only be used internally by using the name _prepare_value(). This doesn't actually make it private, but it's a well recognized convention to say to other developers (i.e. future you) "this method isn't designed to be used externally".
Overall my suggestion would be:
class C():
def __init__(self, input, more_input):
self.value = self._prepare_value(input, more_input)
#staticmethod
def _prepare_value(input, more_input):
value = (input + more_input)/2
return value
here is a part of my code :
class projet(object):
def nameCouche(self):
valLissage = float(ui.valLissage.displayText())
return (valLissage)
valCouche = nameCouche() # asks for a positional argument but 'self' doesnt work
def choixTraitement(self):
ui.okLissage.clicked.connect(p.goLissage)
def goLissage(self, valCouche):
if ui.chkboxLissage.isChecked():
print(valCouche) # result is False
os.system(r'"C:\Program Files\FME\fme.exe" D:\Stelios\..... --MAX_NUM_POINTS {0}'.format(valCouche))
So I would like to use valCouche in goLissage method but it doesnt work.
I thought that valCouche would have the argument of valLissage but instead it gives False as a value.
I've tried different alternatives but still doesnt work.
You've got multiple problems here.
First, if you write this in the middle of a class definition:
valCouche = nameCouche()
... you're creating a class attribute, which is shared by all instances, not a normal instance attribute.
Also, you're running this at class definition time. That means there is no self yet--there aren't any instances yet to be self--so you can't call a method like nameCouche, because you don't have anything to call it on.
What you want to do is call the method at instance initialization time, on the instance being initialized, and store the return value in an instance attribute:
def __init__(self):
self.valCouche = self.nameCouche()
Then, when you want to access this value in another method later, you have to access it as self.valCouche.
If you make those changes, it will work. But your object model still doesn't make much sense. Why is nameCouche a method when it doesn't have anything to do with the object, and doesn't access any of its attributes? Maybe it makes sense as a #staticmethod, but really, I think it makes more sense just as a plain function outside the class. In fact, none of the code you've written seems to have anything to do with the class.
This kind of cram-everything-into-the-class design is often a sign that you're trying to write Java code in Python, and haven't yet really understood how Python does OO. You might want to read a good tutorial on Python classes. But briefly: if you're writing a class just to have somewhere to dump a bunch of vaguely-related functions, what you want is a module, not a class. If you have some reason to have instances of that class, and the functions all act on the data of each instance, then you want a class.
You have to declare variabile in the __init__ method (constructor) and then use it in your code
ex:
class projet(object):
def __init__(self):
self.valCouche = ''
def nameCouche(self):
valLissage = float(ui.valLissage.displayText())
return (valLissage)
def choixTraitement(self):
ui.okLissage.clicked.connect(p.goLissage)
def goLissage(self, valCouche):
if ui.chkboxLissage.isChecked():
self.valCouche = self.nameCouche()
print(self.valCouche) # result is False
os.system(r'"C:\Program Files\FME\fme.exe" D:\Stelios\..... --MAX_NUM_POINTS {0}'.format(self.valCouche))
you have to define an initialization function: def__init__(self)
defining valCouche as an instance attribute make it accessible on all the method so we have the following
class projet(object):
def __init__(self):
self.valCouche = ''
def nameCouche(self):
self.valCouche = float(ui.valLissage.displayText())
#staticmethod #here there is no need for self so it is a method of class
def choixTraitement():
ui.okLissage.clicked.connect(p.goLissage)
def goLissage(self):
if ui.chkboxLissage.isChecked():
print(self.valCouche) # result is False
os.system(r'"C:\Program Files\FME\fme.exe" D:\Stelios\..... --MAX_NUM_POINTS {0}'.format(self.valCouche))