我有一个基本上是具有一些额外属性的 int 的对象。当它用作列表索引时,我可以将它强制转换为 int 吗?

I've got an object that is basically an int with some extra properties. Can I coerce it into an int when it's used as a list index?

上下文:我正在制作一款发生在方形方块迷宫中的游戏,从移动到攻击,几乎所有内容都涉及方向,这些方向主要用于索引列表。减去或添加方向是左转或右转的简单方法,但我总是必须检查它们是否仍在范围内,我想通过自定义 class.

来自动执行此操作

这是我目前的做法:

global UP
UP = 0
global RIGHT
RIGHT = 1
global DOWN
DOWN = 2
global LEFT
LEFT = 3

这是我想做的事情:

class Direction:
    number_of_directions=4

    def __init__(self,direction):
        self.direction = direction

    def __int__(self):
        return self.direction

    def __add__(self,other): #Here other is supposed to be an int
        return (self.direction + other)%number_of_directions

    def __sub__(self,other): #Here other is supposed to be an int
        return (self.direction - other)%number_of_directions

global UP
UP = Direction(0)
global LEFT
LEFT = Direction(1)
global DOWN
DOWN = Direction(2)
global RIGHT
RIGHT = Direction(3)

唯一的问题是我使用 UPRIGHT 等作为索引,就像我有一个 Tile 的列表,其中包含四个 [=15] =] 并且我经常调用 Tile.walls[direction],方向是我的四个常量之一,我不想每次都指定 Tile.walls[int(direction)]

有没有办法让 direction 在用于索引时自动强制转换为 int?

你可以使用 IntEnum:

from enum import IntEnum
from numbers import Integral

class Direction(IntEnum):
    UP = 0
    RIGHT = 1
    DOWN = 2
    LEFT = 3
    _NB_DIRECTIONS = 4

    def __add__(self, other):
        if isinstance(other, Integral):
            return Direction((self.value + other) % Direction._NB_DIRECTIONS)
        return NotImplemented

    def __sub__(self, other):
        if isinstance(other, Integral):
            return Direction((self.value - other) % Direction._NB_DIRECTIONS)
        return NotImplemented

那些是 int 的子类,可用于例如作为列表的索引:

lst = list(range(4))
print(lst[Direction.LEFT])  # -> 3

你举的例子是这样的:

print(Direction.UP)                            # Direction.UP
print(Direction.UP + 1)                        # Direction.RIGHT
print(Direction.UP - 1)                        # Direction.LEFT
print(Direction.UP + 10)                       # Direction.DOWN
a = Direction.UP
a += 1
print(a)                                       # Direction.RIGHT
print(Direction.UP)                            # Direction.UP
print(type(a))                                 # <enum 'Direction'>
b = 1
print(type(b))                                 # <class 'int'>
b += Direction.UP
print(b)                                       # 1
print(type(b))                                 # <class 'int'>
print(Direction.DOWN - 1 == Direction.UP + 1)  # True
lst = ["zero", "one", "two", "three"]
print(lst[Direction.DOWN])                     # 'two'
print(lst[Direction.UP + 3])                   # 'three'
print(lst[Direction.LEFT - 2])                 # 'one'

我通过将 Direction 设为 int 的子 class 来让我的代码工作。

这是我当前的代码:

global NB_DIRECTIONS
NB_DIRECTIONS = 4

(这部分有点多余,以防万一我以后想用六边形或三角形而不是正方形来改编游戏。真正的代码现在开始。)

class Direction(int):
    directions = NB_DIRECTIONS
    def __init__(self,direction):
        self.direction = direction

    def __add__(self,other):
        if isinstance(other,int):
            return Direction((self.direction+other)%self.directions)
        return NotImplemented

    def __radd__(self,other):
        if isinstance(other,int):
            return Direction((other+self.direction)%self.directions)
        return NotImplemented

    def __sub__(self,other):
        if isinstance(other,int):
            return Direction((self.direction-other)%self.directions)
        return NotImplemented

    def __rsub__(self,other):
        return NotImplemented

    def __eq__(self, other):
        if isinstance(other,Direction):
            return self.direction == other.direction
        return NotImplemented

global UP
UP=Direction(0)
global RIGHT
RIGHT=Direction(1)
global DOWN
DOWN=Direction(2)
global LEFT
LEFT=Direction(3)

(我在一个 Direction 对象和一个 int 对象之间做了添加,而不是在两个 Direction 对象之间添加,因为它对我正在做的事情更有意义,但是这与我试图解决的索引问题无关。)

让我们看看我的 Direction 的行为:

>>> UP
0
>>> UP+1
1
>>> UP-1
3
>>> UP+10
2
>>> a=UP
>>> a+=1
>>> a
1
>>> UP
0
>>> type(a)
<class '__main__.Direction'>
>>> b=1
>>> type(b)
<class 'int'>
>>> b+=UP
>>> b
1
>>> UP
0
>>> type(b)
<class '__main__.Direction'>
>>> DOWN-1==UP+1
True
>>> lst=["zero","one","two","three"]
>>> lst[DOWN]
'two'
>>> lst[UP+3]
'three'
>>> lst[LEFT-2]
'one'
>>> type(RIGHT)
<class '__main__.Direction'>

长话短说;博士: 我让我的 class 继承自 int,现在它可以用作索引。

是的,简单定义__index__()。例如:

class Direction:

    def __init__(self, direction):
        self.direction = direction

    def __index__(self):
        return self.direction

UP = Direction(0)
cardinals = ['north', 'east', 'south', 'west']
print(cardinals[UP])  # -> north

这也使得 __int__ 变得不必要,因为 __index__ 被用作后备。

print(int(UP))  # -> 0

P.S。对于这个答案,我忽略了任何设计考虑。使用 IntEnum 可能是更好的解决方案,我不确定。