파이썬 API 둘러보기

exttuple(custom)

앞의 토픽에 이어서... 정말 쓸 데 없을 거 같은 모듈을 만들어 보았다.

그나마 2차원 배열로 보드게임 만들거나 미로찾기 할 때 쓸만하다-_-;;

 

2차원 맵에서 한 점을 기준으로 5칸짜리 십자를 그린다고 생각해 보자.

import numpy as np


def set_cross(arr, x, y):
    for dx, dy in [(0,0), (-1,0), (1,0), (0,-1), (0,1)]:
        xx, yy = x + dx, y + dy
        if 0 <= xx < arr.shape[0] and 0 <= yy < arr.shape[1]:
            arr[xx, yy] = 1


arr = np.zeros((5, 5))
set_cross(arr, 1, 4)
print(arr)

 

실행결과:

[[0. 0. 0. 0. 1.]
 [0. 0. 0. 1. 1.]
 [0. 0. 0. 0. 1.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]

 

이걸 이렇게

from exttuple import ArrayIndex as A


def set_cross(arr, index: A):
    for d in [(0,0), (-1,0), (1,0), (0,-1), (0,1)]:
        if A(0,0) <= index + d < arr.shape:
            arr[index + d] = 1

 

아니면  이렇게 쓰고 싶어서(차이가 보이는지?)

from exttuple import ArrayIndex as A


def set_cross(arr, index: A):
    for d in [(0,0), (-1,0), (1,0), (0,-1), (0,1)]:
        if index + d in A(*arr.shape):
            arr[index + d] = 1

클래스를 몇 개 만들었다.

 

앞 토픽에서 namedtuple을 찾게 된 건 의미 없는 [0]과 [1] 대신 이름을 주고 싶어서였고,

새로 클래스를 만든 건

(1,2) + (3,4) == (1,2,3,4)

이것보다는

(1,2) + (3,4) == (4, 6)

이렇게 벡터합을 구해주고 싶어서였다.

 

AddableTuple은 2-튜플이고, 또 attribute로 'x'와 'y'를 갖는 namedtuple이지만,

'+', '<', '<=' 등 연산자의 의미가 튜플과 다르다.

Point는 2차원 좌표로서, AddableTuple의 다른 이름이다.

ArrayIndex 는 2차원 배열 인덱스의 유효성 검사를 조금 간단히 해 준다.

"""
exttuple.py
programmed by jhjang

exttuple only supports (int, int) tuple
operators have different semantics compared to those of tuple

Usage:
    from exttuple import Addable2Tuple as T

    T(1,2).x == 1
    T(1,2).y == 2
    T(1,2) + T(3,4) == T(1,2) + (3,4) == T(4,6) != (1,2) + T(3,4) 
    T(1,2) < T(3,4) == T(1,2) < (3,4) == 1 < 3 and 2 < 4 != (1,2) < T(3,4)
"""


import typing


class AddableTuple(typing.NamedTuple):
    x: int
    y: int

    @classmethod
    def from_tuple(cls, tup):
        return cls(*tup)

    def __add__(self, other):
        return self.__class__(self[0] + other[0], self[1] + other[1])

    def __sub__(self, other):
        return self.__class__(self[0] - other[0], self[1] - other[1])

    def __lt__(self, other):
        return self[0] < other[0] and self[1] < other[1]

    def __le__(self, other):
        return self[0] <= other[0] and self[1] <= other[1]

    def __gt__(self, other):
        return self[0] > other[0] and self[1] > other[1]

    def __ge__(self, other):
        return self[0] >= other[0] and self[1] >= other[1]

    def __repr__(self):
        return f"'{self.__class__.__name__}({self[0]}, {self[1]})'"

    def __str__(self):
        return str(tuple(self))


# alias
class Point(AddableTuple):
    pass


"""
validates X*Y 2D array index using

   ArrayIndex(x, y) in ArrayIndex(X, Y)

   or

   (x, y) in ArrayIndex(X, Y)
"""
class ArrayIndex(AddableTuple):
    def __contains__(self, item):
        return 0 <= item[0] < self[0] and 0 <= item[1] < self[1]


# test code
if __name__ == '__main__':
    print(repr(AddableTuple(1, 2)))
    print(repr(AddableTuple.from_tuple((1, 2))))
    print(AddableTuple(1, 2))
    print(AddableTuple(1,2).x, AddableTuple(1,2).y)

    print(AddableTuple(1, 2) + AddableTuple(3, 4))
    print(AddableTuple(1, 2) - AddableTuple(3, 4))
    print(AddableTuple(1, 2) + (3, 4))
    print((1, 2) + AddableTuple(3, 4)) # in this case, treated as a tuple

    print(AddableTuple(1, 2) < AddableTuple(1, 3))
    print(AddableTuple(1, 2) <= AddableTuple(1, 3))
    print(AddableTuple(2, 2) > AddableTuple(1, 2))
    print(AddableTuple(2, 2) >= AddableTuple(1, 2))

    print(ArrayIndex(1, 2) in ArrayIndex(2, 3))
    print(ArrayIndex(1, 2) in ArrayIndex(2, 2))

 

댓글

댓글 본문
작성자
비밀번호
버전 관리
장과장02
현재 버전
선택 버전
graphittie 자세히 보기