简体   繁体   中英

Calling other class methods from __new__() in python

I have created a class foo as below:

class foo():

    def __new__(cls, a, b, c, add=True):
        return cls.sum(a, b, c) if add else cls.subtract(a, b, c)

    def sum(a, b, c):
        return a + b + c

    def subtract(a, b, c):
        return c - b - a

print(foo(1, 2, 3, True))

This program returns the required result as 6 . However, I needed to get the clarity of a few concepts:

  1. Is using this methodology or design of OOP correct or is there a better way to do it? I want the class to return a value or any other object(not it's own class instance)
  2. Regardless of the structure above, if sum and subtract are instance methods, how can they be called without instantiating an object as in the above example ie, print(...) ?

I have observed many python APIs and frameworks returning an object or a value through class instantiation.

I am trying to understand the core concepts of OOPs in python please help.

The way you have it now, sum and subtract are indeed instance methods.

>>> foo_obj = object.__new__(foo)  # This will actually create a foo object to demonstrate
>>> foo_obj.sum
<bound method foo.sum of <__main__.foo object at 0x0000000000000000>>
>>> type(foo_obj.sum)
<class 'method'>

But that's just because when you access them through an instance, Python dynamically creates a method (Basically just binds the first argument to the object, usually self )

But, you can access the wrapped function through the class:

>>> foo_obj.sum.__func__
<function foo.sum at 0x0000000000000001>
>>> foo.sum
<function foo.sum at 0x0000000000000001>
>>> foo_obj.sum.__func__ is foo.sum
True

So in your __new__ function, it won't bind the first argument, and they call the underlying function instead of making them an instance method.

To fix the warnings, you can make them classmethod s or staticmethod s. But it is generally bad practice to not return an object that is an instance of the class from the __new__ . If you really wanted to use OOP, either subclass int or make a wrapper, so you can have:

>>> class Foo:
    __slots__ = 'value',
    def __init__(self, a, b, c, add=True):
        self.value = self.sum(a, b, c) if add else self.subtract(a, b, c)
    @staticmethod
    def sum(a, b, c):
        return a + b + c
    @staticmethod
    def subtract(a, b, c):
        return c - b - a
>>> foo = Foo(1, 2, 3, True)
>>> foo
<__main__.foo object at 0x0000000000000002>
>>> foo.value
6

or

>>> class Foo(int):
    __slots__ = ()
    def __new__(cls, a, b, c, add=True):
        value = cls.sum(a, b, c) if add else cls.subtract(a, b, c)
        return super().__new__(cls, value)
    @staticmethod
    def sum(a, b, c):
        return a + b + c
    @staticmethod
    def subtract(a, b, c):
        return c - b - a
>>> foo = Foo(1, 2, 3, True)
>>> foo
6
>>> type(foo)
<class '__main__.Foo'>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM