Как создать свойство статического класса, которое возвращает экземпляр самого класса? - PullRequest
0 голосов
/ 04 февраля 2019

Я написал класс, который может обрабатывать целые числа с произвольной точностью (только для учебных целей).Класс принимает строковое представление целого числа и преобразует его в экземпляр BigInt для дальнейших вычислений.

Часто вам нужны числа Ноль и Один Я подумал, что было бы полезно, если бы класс мог вернуть их.Я попробовал следующее:

class BigInt():
    zero = BigInt("0")

    def __init__(self, value):
        ####yada-yada####

Это не работает.Ошибка: "имя 'BigInt' не определено"

Затем я попробовал следующее:

class BigInt():

    __zero = None

    @staticmethod
    def zero():
        if BigInt.__zero is None:
            BigInt.__zero = BigInt('0')
        return BigInt.__zero


    def __init__(self, value):
        ####yada-yada####

Это на самом деле работает очень хорошо.Что мне не нравится, так это то, что zero - это метод (и, следовательно, должен вызываться с помощью BigInt.zero()), который является нелогичным, поскольку он должен просто ссылаться на фиксированное значение.

Поэтому я попытался изменить zero, чтобы стать свойством, но затем запись BigInt.zero возвращает экземпляр класса property вместо BigInt из-за используемого декоратора.Этот экземпляр нельзя использовать для вычислений из-за неправильного типа.

Есть ли способ обойти эту проблему?

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

Вопрос противоречив: static и property не идут вместе таким образом.Статические атрибуты в Python - это просто атрибуты, которые назначаются только один раз, и сам язык включает в себя очень большое их количество.( Большинство строк являются interred, все целые числа <определенное значение предварительно построены и т. Д. Например, <a href="https://docs.python.org/3/library/string.html" rel="nofollow noreferrer"> модуль string .).Самый простой подход - статически назначать атрибуты после построения, как показывает wim:

class Foo:
    ...

Foo.first = Foo()
...

Или, как он далее предложил, использовать декоратор класса для выполнения назначений, что функционально аналогично приведенному выше.Декоратор - это, по сути, функция, которой в качестве аргумента передается «оформленная» функция, и она должна возвращать функцию, чтобы эффективно заменить исходную.Это может быть исходная функция, скажем, измененная с некоторыми аннотациями, или может быть совершенно другая функция.Исходная (оформленная) функция может вызываться или не вызываться соответствующим образом для декоратора.

def preload(**values):
    def inner(cls):
        for k, v in values.items():
            setattr(cls, k, cls(v))

        return cls

    return inner

Затем ее можно использовать динамически:

@preload(zero=0, one=1)
class Foo:
    ...

Если целью является сохранение некоторыхвремя на общих целочисленных значениях, defaultdict отображение целых чисел на сконструированные BigInt с может быть полезно в качестве формы кэширования и упрощенного построения / одноэлементного хранения.(Например, BigInt.numbers[27])

Однако проблема использования @property на уровне класса заинтриговала меня, поэтому я немного покопался.Вполне возможно использовать " объекты протокола дескриптора " (которые возвращает декоратор @property) на уровне класса, если вы добавите атрибут вверх по иерархии объектной модели в метакласс.

class Foo(type):
    @property
    def bar(cls):
        print("I'm a", cls)
        return 27

class Bar(metaclass=Foo):
    ...

>>> Bar.bar
I'm a <class '__main__.Bar'>
<<< 27

Примечательно, что этот атрибут недоступен из экземпляров:

>>> Bar().bar
AttributeError: 'Bar' object has no attribute 'bar'

Надеюсь, это поможет!

0 голосов
/ 04 февраля 2019

Статическое свойство ...?Мы называем статическое свойство «атрибутом».Не Javaбыть полностью инкапсулированным в блоке класса, делайте это, используя декоратор класса (но учтите, что это просто более изящный способ написать то же самое).

def add_zero(cls):
    cls.zero = cls("0")
    return cls

@add_zero
class BigInt:
    ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...