-1

Description:

I am trying to return a value from a class when I call it.

I want the result of an object's method call upon creating the object.

I want to get the value of:

A().get_result() 

# by just calling"
A()

My Question:

Why does A.get_result() require the argument self?

Minimal Reproducible Example:

Using the following class definition:

class A():
    _arg_list = None
    
    def __new__(self, my_args):
        self._arg_list = my_args
        return self.get_result()
        
    def get_result(self):
        return self._args_list[0]

Current Result:

A(['arg1','arg2'])


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[6], line 1
----> 1 A(['arg1','arg2'])

Cell In[5], line 9, in A.__new__(self, my_args)
      5 def __new__(self, my_args):
      7     self._arg_list = my_args
----> 9     return self.get_result()

TypeError: A.get_result() missing 1 required positional argument: 'self'

Desired Result:

A(['arg1','arg2'])
>> 'arg1'
Alexander
  • 59,041
  • 12
  • 98
  • 151
Jesse Sealand
  • 302
  • 1
  • 11
  • 4
    Have you considered just making a function called `def A()`? – Alexander Aug 29 '23 at 20:30
  • "using __new__ , instead of __init__" why would you do that? – njzk2 Aug 29 '23 at 20:36
  • Now that I understand how it would work, it think it's a great resource. – Jesse Sealand Aug 29 '23 at 20:50
  • This [linked dupe](https://stackoverflow.com/questions/5738470/whats-an-example-use-case-for-a-python-classmethod) isn't correct. While class methods might be a better fit for OP's problem, his question is about customizing `__new__`. – Alexander Aug 29 '23 at 20:57

2 Answers2

4

Instance methods operate on, well... instances. In Python, that's made explicit by requiring self as the first parameter of all instance methods (though the exact name can be anything, by convention, it's always self for instance_methods and cls for class methods). Other OO languages make this implicit (where self or this is just a magical keyword), but nonetheless require it.

Even if you don't want an object to hang around, and you just want to call the instance method get_result() once, you still need the instance call the method on. You have 2 options:

  1. Change get_result() to not be an instance method (so it doesn't require an instance)
  2. Create an instance to call get_result() on.

Here's one possible way to achieve this:

class A():
    _arg_list = None
    
    def __new__(cls, my_args):
        new_instance = super().__new__(cls)
        new_instance._args_list = my_args
        
        return new_instance.get_result()
        
    def get_result(self):
        return self._args_list[0]

print(A(['arg1', 'arg2'])) # => 'arg1'

But really, this is all really weird. Unless you have a really good reason not to, I'd suggest:

  1. Circumvent all this headache by just making a function, and getting rid of the class all together:

    # You *could* call it A if you really wanted, but people would expect that to be a class, so don't do that.
    def a(my_args):
        return my_args[0]
    
  2. Just use A().get_result(), which is perfectly clear.

Alexander
  • 59,041
  • 12
  • 98
  • 151
  • You perfectly explained how that would work, and now I get it. My minimal example does not reflect the overall problem but just one concept that I was struggling with. I appreciate your explanation for that. – Jesse Sealand Aug 29 '23 at 20:45
  • 1
    @JesseSealand Glad I could help! If I could suggest, when asking a question, you should give more insight into your real underlying issue. Otherwise there's a risk that people end up on a wild goose change to solve a problem for a solution approach that might not be the best approach to being with (and I'll be honest, I think it's **likely** that it isn't, in this case). See https://xyproblem.info/ – Alexander Aug 29 '23 at 20:52
1

Because you defined it to require self, as is normal for methods!

Perhaps the part you are missing is that the first argument to __new__ is actually the class.

So

return self.get_result()

Is equivalent to:

return A.get_result()

And it is important to note, the implicit binding of the first argument only occurs when you call a method on an instance. You don't actually have an instance anywhere in your code!

But the question you really should be asking yourself here is why A is a class at all.

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • You're saying the argument and the methods are not bound to the class because the object is not yet created? That would make sense. – Jesse Sealand Aug 29 '23 at 20:40
  • 1
    @JesseSealand bound to the **instance**. And just define your class `A` with just the `get_value` method, and do `A.get_value()` and you get the exact same error, because in your code, that is *exactly* what you are doing, `self` in `__new__` is `A`, not an instance of `A`, the job of `__new__` is to *create the instance* – juanpa.arrivillaga Aug 29 '23 at 20:43