Можно ли принудительно устанавливать уникальные идентификаторы для переменных, содержащих целые числа от -5 до 256 в python? - PullRequest
0 голосов
/ 01 февраля 2020

У меня есть класс с несколькими именованными атрибутами. Я хотел бы иметь возможность передавать один из атрибутов классов самому себе и иметь возможность конкретно определить, какой атрибут был передан.

Ниже приведен тривиальный пример того, как я это делал (используя оператор "is" до тех пор, пока я не обнаружил, что специальные целые идентификаторы кэшированных переменных используются для целочисленных значений от -5 до 256.

class AClass:
    def __init__(self, one, two, three):
        self.one = one
        self.two = two
        self.three = three

    def getIndex(self, attribute):
        if attribute is self.one:
            return 1
        elif attribute is self.two:
            return 2
        elif attribute is self.three:
            return 3

    def setByIndex(self, i, value):
        if i == 1:
            self.one = value
        elif i == 2:
            self.two = value
        elif i == 3:
            self.three = value

    def setByAttrib(self, attribute, value):
        i = self.getIndex(attribute)
        self.setByIndex(i, value)


object = AClass(0, 0, 0)

object.setByAttrib(object.three, 10)

В вышеприведенном примере предполагается установить object.three до 10 . Однако, поскольку все атрибуты указывают на кэшированное местоположение целого числа 0 , функция getIndex будет оценивать значение true для любого из них, а object.one (который появляется первым) будет установлен на 10 . Если бы объект был инициализирован со значениями 257, 257, 257 , функциональность предположительно была бы такой, как предполагалось.

Так что вопрос в том, есть ли способ:

a) заставить систему назначать не кэшированные, уникальные ячейки памяти для этих атрибутов (даже если они установлены в диапазоне от -5 до 256), или

b) использовать какой-либо другой метод для проверить, является ли атрибут, переданный в качестве аргумента, уникальным сам по себе?

РЕДАКТИРОВАТЬ:

Поскольку его спросили пару раз, одна из причин, по которой я использую эту парадигму связано с отсутствием указателей в python. В приведенном выше примере функция setByIndex может выполнять некоторую сложную работу с атрибутом. Вместо того, чтобы писать несколько идентичных функций для каждой переменной (например, setOne, setTwo, setThree ), я могу написать одну функцию generi c, которая получает и устанавливает по индексу (индекс в основном действует как указатель ). Да, я мог бы передать значение атрибута в качестве аргумента и вернуть новое установленное значение и выполнить присваивание в области, где известен атрибут speci c, но я уже возвращаю значение. Да, я мог бы вернуть список, но это добавляет больше сложности.

Я понимаю, что есть лучшие способы реализовать то, что мне нужно (например, пары ключ-значение для атрибутов и номеров индексов), но это будет много работы для реализации (тысячи изменений). Если бы был способ использовать varaible ID в качестве моего уникального идентификатора и продолжать использовать оператор «is» (или аналогичный), мне не пришлось бы менять слишком много. Хотя это не представляется возможным. Ценю комментарии / ответы.

1 Ответ

1 голос
/ 01 февраля 2020

Я бы не беспокоился о местах памяти, они здесь просто детали реализации. Это действительно дизайн функций, поэтому, если вы хотите установить object.three, то сделайте именно это, в противном случае вы можете создать отображение на индекс, если хотите:

class MyClass:
    def __init__(self, *args):
        self.one, self.two, self.three, *_ = args

    # get an object by it's index
    def get_by_index(self, index):
        # here's how you could create such a mapping
        opts = dict(zip((1, 2, 3), ('one', 'two', 'three')))

        try:
            return getattr(self, opts[index])
        except KeyError as e:
            raise ValueError(f"Improper alias for attribute, select one of {', '.join(opts)}") from e

    # if you want to set by an index, then do that this way
    def set_by_index(self, index, val):
        opts = dict(zip((1, 2, 3), ('one', 'two', 'three')))

        try:
            setattr(self, opts[index], val)
        except KeyError as e:
            raise ValueError(f"Improper alias for attribute, select one of {', '.join(opts)}") from e



# otherwise, just set the attribute by the name
a = MyClass(0, 0, 0)
a.three = 55


Дело в том, что вы Вы правы, is будет смотреть на три 0 одинаково, потому что он никогда не копировал эти данные. one, two, three указывают на одни и те же данные, поскольку им были назначены одни и те же данные. После того, как вы снова назначите атрибут, вы фактически повторно связали этот атрибут с новым значением, вместо того, чтобы обновить существующее.

Суть в том, не беспокойтесь о где память для этой реализации, просто явно установите для атрибута

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