-3

I have defined a class

code.py

class test:
     def __init__(self.x,self.y):
       self.x = x
       self.y = y


    def sum(self):
      z = self.x + self.y
      return z

def main():
   x = test(1,2)
   valsum = x.sum()

I want the sum to be returned when the class is called not when the method id called?

How will I code it

user1050619
  • 19,822
  • 85
  • 237
  • 413
  • 1
    It's not possible. Returning anything from a constructor in python is an error. – Kenan Banks Oct 12 '12 at 17:14
  • Actually it's perfectly cromulent to return an object from a constructor; it's just that the constructor is named `__new__`. `__init__` is not a constructor. – kindall Oct 12 '12 at 17:34
  • @kindall That's misleading pedanticism. Java, C#, and I believe C++ as well also call this sort of code a constructor, even if it returns no value. The closest analogue of `__new__` is overloading the `new` operator in C++. (At least I think that's possible.) – millimoose Oct 12 '12 at 17:35
  • It's not pedanticism at all. `__new__` is the constructor. `__init__` is called after the object already exists, so cannot be a constructor. – kindall Oct 12 '12 at 17:39
  • @kindall: the documentation seems fine with calling `__init__` a constructor (see the last sentence [here in the data model](http://docs.python.org/reference/datamodel.html#object.__init__)). This subject has been hashed out here [before](http://stackoverflow.com/questions/6578487/init-as-a-constructor). – DSM Oct 12 '12 at 17:47
  • @kindall Except that in all languages that have constructors, the constructor is called after the object exists. (For certain values of "exists", specific to language. The definition is about as easy to pin down as defining when life starts.) – millimoose Oct 12 '12 at 18:06
  • Fairy nuff. I read something that referred to `__new__` as the constructor and `__init__` as the initializer, so I've been going by that definition. – kindall Oct 12 '12 at 18:08
  • @kindall Which is fine. My point was more that the terms "constructor" and "initialiser" are not really precisely and universally defined, and thus don't really have a specific meaning outside the context they appear in. Thus it also makes little sense to be pedantic about their definitions, as opposed to following convention and existing documentation. For what it's worth, when talking about Python, I prefer to just say `__init__` and `__new__` directly to avoid confusion. – millimoose Oct 12 '12 at 18:11
  • @user1050619: There. My answer now has no less than four various ways to make calling a class return something else than an instance of the class, in roughly increasing order of stupidity. Choice is always good! – millimoose Oct 12 '12 at 20:08

3 Answers3

3

Use a function for this:

def test(*args):
    return sum(args)

Or better, just use the builtin:

sum((1,2))

If you have good reason to want this, you can always wrap this stuff up in another function:

def testsum(a,b):
    t = test(a,b)
    return t.sum()

Or you can just do:

result = test(a,b).sum()

directly. This should be used sparingly though since it is inefficient ...


Finally (as pointed out in the comments, you can do this if you override __new__, DON'T DO THIS)

class test(object):
    def __new__(cls,*args):
       return sum(*args)

print (test(1,2,3,4)) #10
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 2
    @user1050619 -- There's no way to do it with a class. The reason there's no way to do it using a class is because (as far as I can figure), there is absolutely no *reason* to do it using a class. Classes are for grouping data with functions. You're asking to create a structure with data that you immediately throw away ... – mgilson Oct 12 '12 at 17:17
  • @mgilson You probably could do this with a class if you override `__new__`. (It's a terrible idea, but still.) – millimoose Oct 12 '12 at 17:21
  • @millimoose -- You're absolutely correct. It can be done with `__new__`. But ... ick. Definitely `__new__` abuse. – mgilson Oct 12 '12 at 17:23
3

You can override __new__():

class test(object):
    def __new__(cls, x, y):
        return x+y

z = test(1, 2)
print z # => 3

That said, I can not stress enough how incredibly pointless doing so is, more or less always.

While we're being pointless, you can also have sum() be a method:

class test(object):
    def __new__(cls, *args, **kwargs):
        test_obj = super(test, cls).__new__(cls)
        test_obj.__init__(*args, **kwargs)
        return test_obj.sum()

    def __init__(self, x, y):
        test.x = x
        test.y = y

    def sum(self):
        return self.x + self.y

z = test(1, 2)
print z

However, there's no way to access it outside the __new__ implementation. Or without creating a test instance "the hard way" by manually invoking object.__new__() and __init__, at which point any violence you'd suffer at the hands of your supervisor would be justified.

To maximise perversion, here's @kindall's suggested variant – needlessly overengineered of course:

With a metaclass

class meta_delegate(type):
    def __call__(cls, *args, **kwargs):
        obj = cls.__new__(cls)
        obj.__init__(*args, **kwargs)
        delegate = cls.__delegate
        if (isinstance(delegate, basestring)):
            delegate = getattr(obj, delegate)
            return delegate()
        else:
            return delegate(obj)

    @staticmethod
    def to(delegate):
        def __new__(*args, **kwargs):
            cls = meta_delegate(*args, **kwargs)
            cls.__delegate = delegate
            return cls
        return __new__

class test(object):
    def __init__(self, x, y):
        test.x = x
        test.y = y

    def sum(self):
        return self.x + self.y

    __metaclass__ = meta_delegate.to(sum)

I'm actually honestly surprised it works. It seems that invoking a metaclass doesn't use its __call__.

And a last one just to illustrate the sheer pointlessness of it all:

So pointless it's circular

class meta_delegate(type):
    def __call__(cls, *args, **kwargs):
        return cls.__delegate(*args, **kwargs)

    @staticmethod
    def to(delegate):
        def __new__(*args, **kwargs):
            cls = meta_delegate(*args, **kwargs)
            cls.__delegate = staticmethod(delegate)
            return cls
        return __new__

class test(object):
    __metaclass__ = meta_delegate.to(lambda x, y: x+y)

The delegate here can be any callable, and the API is much simpler! Now if you'll excuse me I'll go and have a drink.

Community
  • 1
  • 1
millimoose
  • 39,073
  • 9
  • 82
  • 134
1

While it's not possible to return any value from the constructor, you may make use of the __call__ magic method to make your object directly callable.

class Sum:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __call__(self):
        return self.x + self.y

x = Sum(4,7)
x() # = 11
Kenan Banks
  • 207,056
  • 34
  • 155
  • 173