1

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.

3
  • 2
    Your alternate conductor isn't creating an instance, but modifying the class. Commented Jul 25, 2014 at 0:12
  • But then I should be able to do cls.init_others() right? Commented Jul 25, 2014 at 0:13
  • No, because Image.init_others is an instance method, not a class method. You have decorated the Image.from_data method as a class method; this means that the function can be called on both instances of Image and the class Image itself, but the first argument will always be the class. Commented Jul 25, 2014 at 0:14

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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.

Comments

1

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

1 Comment

Sorry that was a type. I do pass self. Edited it now.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.