Вызов других методов класса из __new __ () в python - PullRequest
0 голосов
/ 27 октября 2018

Я создал класс foo, как показано ниже:

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))

Эта программа возвращает требуемый результат как 6. Однако мне нужно было получить ясность по нескольким понятиям:

  1. Правильно ли используется эта методология или дизайн ООП или есть лучший способ сделать это? Я хочу, чтобы класс возвращал значение или любой другой объект (не его собственный экземпляр класса)
  2. Независимо от приведенной выше структуры, если sum и subtract являются методами экземпляра, как их можно вызывать без создания экземпляра объекта, как в примере выше, то есть print(...)?

Я наблюдал, как многие Python API и фреймворки возвращали объект или значение через создание экземпляров класса.

Я пытаюсь понять основные концепции ООП в python, пожалуйста, помогите.

1 Ответ

0 голосов
/ 27 октября 2018

Как у вас сейчас, sum и subtract действительно методы экземпляра.

>>> 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'>

Но это только потому, что когда вы обращаетесь к ним через экземпляр, Python динамически создает метод (в основном просто привязывает первый аргумент к объекту, обычно self)

Но вы можете получить доступ к упакованной функции через класс:

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

Так что в вашей функции __new__ она не будет привязывать первый аргумент, и они вызывают базовую функцию вместо того, чтобы делать их методом экземпляра.

Чтобы исправить предупреждения, вы можете сделать их classmethod с или staticmethod с. Но, как правило, плохая практика - не возвращать объект, который является экземпляром класса из __new__. Если вы действительно хотите использовать ООП, подкласс int или создайте оболочку, чтобы вы могли иметь:

>>> 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

или

>>> 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'>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...