Включение целочисленного переполнения в Python - PullRequest
1 голос
/ 26 мая 2019

Я хотел бы создать 2D-среду, в которой верхний и нижний, левый и правый соединены (аналогично торусу или пончику). Однако вместо того, чтобы проверять координаты x / y объекта в каждом кадре, я хотел бы смоделировать его, используя целочисленное переполнение.
Хотя обычную итерацию (как показано в примере кода ниже) можно выполнить, может быть несколько более эффективным (хотя и опасным) просто включить переполнение некоторых переменных, особенно при работе с сотнями или тысячами объектов в каждом кадре / итерации.

Я могу найти несколько примеров, которые также симулируют целочисленное переполнение в Python, например this . Однако я ищу что-то, что может переполниться, просто включив переполнение в некоторых переменных и пропуская проверки в общем.

# With normal checking of every instance
import random

width = 100
height = 100

class item():
    global width, height

    def __init__(self):
        self.x = random.randint(0, width)
        self.y = random.randint(0, height)

items = [item for _ in range(10)] # create 10 instances

while True:
    for obj in items:
        obj.x += 10
        obj.y += 20
        while obj.x > width:
            obj.x -= width
        while obj.y > height:
            obj.y -= height
        while obj.x < width:
            obj.x += width
        while obj.y < height:
            obj.y += height

Я бы хотел смоделировать целочисленное переполнение только для некоторых определенных классов / объектов. Есть ли способ, чтобы некоторые переменные автоматически переполнялись и возвращались к своим минимальным / максимальным значениям?

Ответы [ 2 ]

1 голос
/ 26 мая 2019

Вы можете использовать свойства для реализации методов получения / установки с настраиваемым поведением. Например, как это:

import random

WIDTH = 100
HEIGHT = 100


class item():

    def __init__(self):
        self._x = random.randint(0, WIDTH - 1)
        self._y = random.randint(0, HEIGHT - 1)

    def __str__(self):
        return '(%r, %r)' % (self._x, self._y)

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, new_value):
        self._x = new_value % WIDTH

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, new_value):
        self._y = new_value % HEIGHT


items = [item() for _ in range(10)]

while True:
    for pos in items:
        pos.x += 10
        pos.y += 20
        print(pos)  # to show the results
0 голосов
/ 26 мая 2019

С помощью дескриптора вы можете определить желаемое поведение атрибутов вашего объекта. Читая между строк, звучит так, будто вы хотите, чтобы ваши атрибуты демонстрировали поведение value = value % maximum.

from weakref import WeakKeyDictionary

class MaxValue:
    '''A descriptor whose value will be: value modulo maximum.'''
    def __init__(self, maximum, default=0):
        self.maximum = maximum
        self.default = default
        self.data = WeakKeyDictionary()

    def __get__(self, instance, owner):
        return self.data.get(instance, self.default)

    def __set__(self, instance, value):
        self.data[instance] = value % self.maximum

Дескрипторы должны быть атрибутами класса. Для вашего примера класса:

import random
width = 100
height = 100

class Item:
##    global width, height
    x = MaxValue(width)
    y = MaxValue(height)

    def __init__(self):
        self.x = random.randint(0, width)
        self.y = random.randint(0, height)
    def __str__(self):
        return f'({self.x:>3},{self.y:>3})'

Пример:

items = [Item() for _ in range(5)]
print(','.join(f'{item}' for item in items))
for n in range(15):
    for item in items:
        item.x += 10
        item.y += 20
    print(','.join(f'{item}' for item in items))

>>>
( 74,  6),( 49, 19),( 56, 10),( 72, 16),( 83, 16)
( 84, 26),( 59, 39),( 66, 30),( 82, 36),( 93, 36)
( 94, 46),( 69, 59),( 76, 50),( 92, 56),(  3, 56)
(  4, 66),( 79, 79),( 86, 70),(  2, 76),( 13, 76)
( 14, 86),( 89, 99),( 96, 90),( 12, 96),( 23, 96)
( 24,  6),( 99, 19),(  6, 10),( 22, 16),( 33, 16)
( 34, 26),(  9, 39),( 16, 30),( 32, 36),( 43, 36)
( 44, 46),( 19, 59),( 26, 50),( 42, 56),( 53, 56)
( 54, 66),( 29, 79),( 36, 70),( 52, 76),( 63, 76)
( 64, 86),( 39, 99),( 46, 90),( 62, 96),( 73, 96)
( 74,  6),( 49, 19),( 56, 10),( 72, 16),( 83, 16)
( 84, 26),( 59, 39),( 66, 30),( 82, 36),( 93, 36)
( 94, 46),( 69, 59),( 76, 50),( 92, 56),(  3, 56)
(  4, 66),( 79, 79),( 86, 70),(  2, 76),( 13, 76)
( 14, 86),( 89, 99),( 96, 90),( 12, 96),( 23, 96)
( 24,  6),( 99, 19),(  6, 10),( 22, 16),( 33, 16)
>>>

Не моя идея - поднял это на Дескрипторы Python Демистифицированы


Каждый экземпляр MaxValue должен отслеживать (или знать ), значение для каждого экземпляра Item - Item.x должно знать значение x для Item экземпляров a, b, c, .... Для этого удобен словарь, и используется WeakKeyDictionary, так что если словарь является единственной ссылкой на экземпляр Item, то этот экземпляр может быть подвергнут сборке мусора.

Это решение избавляет от необходимости писать getter / setter для каждого атрибута, который разделяет поведение.

...