prosource

파이썬에 불변 리스트가 있습니까?

probook 2023. 10. 25. 23:23
반응형

파이썬에 불변 리스트가 있습니까?

파이썬은 불변의 목록을 가지고 있습니까?

주문된 요소 집합의 기능을 사용하고 싶지만 변경되지 않을 것이라고 보장합니다. 어떻게 구현할 수 있습니까?목록은 순서대로 나열되지만 변형될 수 있습니다.

네. A라고 합니다.tuple.

그래서 대신에[1,2]어느것이list돌연변이가 될 수도 있고,(1,2)tuple할 수 없습니다.


자세한 정보:

원-엘리먼트tuple글로는 예를 들 수 없습니다.(1), 대신에, 당신은 글을 써야 합니다.(1,). 그 이유는 인터프리터가 괄호 안에 사용할 수 있는 다른 용도가 다양하기 때문입니다.

괄호를 모두 제거할 수도 있습니다.1,2와 같음(1,2)

튜플은 정확히 불변의 목록이 아닙니다.목록과 튜플의 차이점에 대해 자세히 알아보려면 여기를 클릭하십시오.

여기 있습니다.ImmutableList실행.기본 목록은 어떤 직접 데이터 멤버에도 노출되지 않습니다.그래도 회원기능의 폐쇄성을 이용하여 접근할 수 있습니다.위 재산을 이용하여 폐업의 내용을 변경하지 않는 관례에 따른다면 본 시행이 그 목적에 부합할 것입니다.이것의 예ImmutableListclass는 일반 파이썬 목록이 예상되는 곳이라면 어디든지 사용할 수 있습니다.

from functools import reduce

__author__ = 'hareesh'


class ImmutableList:
    """
    An unmodifiable List class which uses a closure to wrap the original list.
    Since nothing is truly private in python, even closures can be accessed and
    modified using the __closure__ member of a function. As, long as this is
    not done by the client, this can be considered as an unmodifiable list.

    This is a wrapper around the python list class
    which is passed in the constructor while creating an instance of this class.
    The second optional argument to the constructor 'copy_input_list' specifies
    whether to make a copy of the input list and use it to create the immutable
    list. To make the list truly immutable, this has to be set to True. The
    default value is False, which makes this a mere wrapper around the input
    list. In scenarios where the input list handle is not available to other
    pieces of code, for modification, this approach is fine. (E.g., scenarios
    where the input list is created as a local variable within a function OR
    it is a part of a library for which there is no public API to get a handle
    to the list).

    The instance of this class can be used in almost all scenarios where a
    normal python list can be used. For eg:
    01. It can be used in a for loop
    02. It can be used to access elements by index i.e. immList[i]
    03. It can be clubbed with other python lists and immutable lists. If
        lst is a python list and imm is an immutable list, the following can be
        performed to get a clubbed list:
        ret_list = lst + imm
        ret_list = imm + lst
        ret_list = imm + imm
    04. It can be multiplied by an integer to increase the size
        (imm * 4 or 4 * imm)
    05. It can be used in the slicing operator to extract sub lists (imm[3:4] or
        imm[:3] or imm[4:])
    06. The len method can be used to get the length of the immutable list.
    07. It can be compared with other immutable and python lists using the
        >, <, ==, <=, >= and != operators.
    08. Existence of an element can be checked with 'in' clause as in the case
        of normal python lists. (e.g. '2' in imm)
    09. The copy, count and index methods behave in the same manner as python
        lists.
    10. The str() method can be used to print a string representation of the
        list similar to the python list.
    """

    @staticmethod
    def _list_append(lst, val):
        """
        Private utility method used to append a value to an existing list and
        return the list itself (so that it can be used in funcutils.reduce
        method for chained invocations.

        @param lst: List to which value is to be appended
        @param val: The value to append to the list
        @return: The input list with an extra element added at the end.

        """
        lst.append(val)
        return lst

    @staticmethod
    def _methods_impl(lst, func_id, *args):
        """
        This static private method is where all the delegate methods are
        implemented. This function should be invoked with reference to the
        input list, the function id and other arguments required to
        invoke the function

        @param list: The list that the Immutable list wraps.

        @param func_id: should be the key of one of the functions listed in the
            'functions' dictionary, within the method.
        @param args: Arguments required to execute the function. Can be empty

        @return: The execution result of the function specified by the func_id
        """

        # returns iterator of the wrapped list, so that for loop and other
        # functions relying on the iterable interface can work.
        _il_iter = lambda: lst.__iter__()
        _il_get_item = lambda: lst[args[0]]  # index access method.
        _il_len = lambda: len(lst)  # length of the list
        _il_str = lambda: lst.__str__()  # string function
        # Following represent the >, < , >=, <=, ==, != operators.
        _il_gt = lambda: lst.__gt__(args[0])
        _il_lt = lambda: lst.__lt__(args[0])
        _il_ge = lambda: lst.__ge__(args[0])
        _il_le = lambda: lst.__le__(args[0])
        _il_eq = lambda: lst.__eq__(args[0])
        _il_ne = lambda: lst.__ne__(args[0])
        # The following is to check for existence of an element with the
        # in clause.
        _il_contains = lambda: lst.__contains__(args[0])
        # * operator with an integer to multiply the list size.
        _il_mul = lambda: lst.__mul__(args[0])
        # + operator to merge with another list and return a new merged
        # python list.
        _il_add = lambda: reduce(
            lambda x, y: ImmutableList._list_append(x, y), args[0], list(lst))
        # Reverse + operator, to have python list as the first operand of the
        # + operator.
        _il_radd = lambda: reduce(
            lambda x, y: ImmutableList._list_append(x, y), lst, list(args[0]))
        # Reverse * operator. (same as the * operator)
        _il_rmul = lambda: lst.__mul__(args[0])
        # Copy, count and index methods.
        _il_copy = lambda: lst.copy()
        _il_count = lambda: lst.count(args[0])
        _il_index = lambda: lst.index(
            args[0], args[1], args[2] if args[2] else len(lst))

        functions = {0: _il_iter, 1: _il_get_item, 2: _il_len, 3: _il_str,
                     4: _il_gt, 5: _il_lt, 6: _il_ge, 7: _il_le, 8: _il_eq,
                     9: _il_ne, 10: _il_contains, 11: _il_add, 12: _il_mul,
                     13: _il_radd, 14: _il_rmul, 15: _il_copy, 16: _il_count,
                     17: _il_index}

        return functions[func_id]()

    def __init__(self, input_lst, copy_input_list=False):
        """
        Constructor of the Immutable list. Creates a dynamic function/closure
        that wraps the input list, which can be later passed to the
        _methods_impl static method defined above. This is
        required to avoid maintaining the input list as a data member, to
        prevent the caller from accessing and modifying it.

        @param input_lst: The input list to be wrapped by the Immutable list.
        @param copy_input_list: specifies whether to clone the input list and
            use the clone in the instance. See class documentation for more
            details.
        @return:
        """

        assert(isinstance(input_lst, list))
        lst = list(input_lst) if copy_input_list else input_lst
        self._delegate_fn = lambda func_id, *args: \
            ImmutableList._methods_impl(lst, func_id, *args)

    # All overridden methods.
    def __iter__(self): return self._delegate_fn(0)

    def __getitem__(self, index): return self._delegate_fn(1, index)

    def __len__(self): return self._delegate_fn(2)

    def __str__(self): return self._delegate_fn(3)

    def __gt__(self, other): return self._delegate_fn(4, other)

    def __lt__(self, other): return self._delegate_fn(5, other)

    def __ge__(self, other): return self._delegate_fn(6, other)

    def __le__(self, other): return self._delegate_fn(7, other)

    def __eq__(self, other): return self._delegate_fn(8, other)

    def __ne__(self, other): return self._delegate_fn(9, other)

    def __contains__(self, item): return self._delegate_fn(10, item)

    def __add__(self, other): return self._delegate_fn(11, other)

    def __mul__(self, other): return self._delegate_fn(12, other)

    def __radd__(self, other): return self._delegate_fn(13, other)

    def __rmul__(self, other): return self._delegate_fn(14, other)

    def copy(self): return self._delegate_fn(15)

    def count(self, value): return self._delegate_fn(16, value)

    def index(self, value, start=0, stop=0):
        return self._delegate_fn(17, value, start, stop)


def main():
    lst1 = ['a', 'b', 'c']
    lst2 = ['p', 'q', 'r', 's']

    imm1 = ImmutableList(lst1)
    imm2 = ImmutableList(lst2)

    print('Imm1 = ' + str(imm1))
    print('Imm2 = ' + str(imm2))

    add_lst1 = lst1 + imm1
    print('Liist + Immutable List: ' + str(add_lst1))
    add_lst2 = imm1 + lst2
    print('Immutable List + List: ' + str(add_lst2))
    add_lst3 = imm1 + imm2
    print('Immutable Liist + Immutable List: ' + str(add_lst3))

    is_in_list = 'a' in lst1
    print("Is 'a' in lst1 ? " + str(is_in_list))

    slice1 = imm1[2:]
    slice2 = imm2[2:4]
    slice3 = imm2[:3]
    print('Slice 1: ' + str(slice1))
    print('Slice 2: ' + str(slice2))
    print('Slice 3: ' + str(slice3))

    imm1_times_3 = imm1 * 3
    print('Imm1 Times 3 = ' + str(imm1_times_3))
    three_times_imm2 = 3 * imm2
    print('3 Times Imm2 = ' + str(three_times_imm2))

    # For loop
    print('Imm1 in For Loop: ', end=' ')
    for x in imm1:
        print(x, end=' ')
    print()

    print("3rd Element in Imm1: '" + imm1[2] + "'")

    # Compare lst1 and imm1
    lst1_eq_imm1 = lst1 == imm1
    print("Are lst1 and imm1 equal? " + str(lst1_eq_imm1))

    imm2_eq_lst1 = imm2 == lst1
    print("Are imm2 and lst1 equal? " + str(imm2_eq_lst1))

    imm2_not_eq_lst1 = imm2 != lst1
    print("Are imm2 and lst1 different? " + str(imm2_not_eq_lst1))

    # Finally print the immutable lists again.
    print("Imm1 = " + str(imm1))
    print("Imm2 = " + str(imm2))

    # The following statemetns will give errors.
    # imm1[3] = 'h'
    # print(imm1)
    # imm1.append('d')
    # print(imm1)

if __name__ == '__main__':
    main()

이 질문은 현대적인 답을 얻을 자격이 있습니다. 이제는 주석을 입력하고 다음을 통해 유형을 확인합니다.mypy점점 인기가 많아지고 있습니다.

교체List[T]유형 주석을 사용할 때 튜플에 의한 해결책이 최적이 아닐 수 있습니다.개념적으로 리스트는 1의 일반성을 갖습니다. 즉, 그들은 하나의 일반적인 인수를 갖습니다.T(물론, 이 논쟁은 다음과 같을 수 있습니다.Union[A, B, C, ...]이질적으로 입력된 목록을 설명합니다.)이와 대조적으로 튜플은 본질적으로 가변적인 제네릭입니다.Tuple[A, B, C, ...]. 이로 인해 튜플이 어색한 목록 대체가 됩니다.

실제로 유형 확인은 다음과 같은 또 다른 가능성을 제공합니다.다음을 사용하여 변수를 불변 목록으로 주석을 달 수 있습니다.typing.Sequence, 이것은 불변 인터페이스의 유형에 해당합니다.예를 들어,

from typing import Sequence


def f(immutable_list: Sequence[str]) -> None:
    # We want to prevent mutations like:
    immutable_list.append("something")


mutable_list = ["a", "b", "c"]
f(mutable_list)
print(mutable_list)

물론 런타임 동작의 측면에서 이것은 불변하지 않습니다. 즉, 파이썬 인터프리터는 기꺼이 변형될 것입니다.immutable_list, 그리고 그 결과는["a", "b", "c", "something"].

그러나 프로젝트에서 다음과 같은 유형의 검사기를 사용하는 경우mypy, 다음과 같은 코드를 거부합니다.

immutable_lists_1.py:6: error: "Sequence[str]" has no attribute "append"
Found 1 error in 1 file (checked 1 source file)

따라서 후드 아래에서는 일반 목록을 계속 사용할 수 있지만, 형식 검사기는 형식 검사 시간에 어떠한 변형도 효과적으로 방지할 수 있습니다.

마찬가지로 목록 구성원의 수정을 방지할 수 있습니다. 예를 들어, 불변 데이터 클래스에서 필드 할당을 방지할 수 있습니다.frozen데이터 클래스는 실제로 런타임에 방지됩니다.):

@dataclass(frozen=True)
class ImmutableData:
    immutable_list: Sequence[str]


def f(immutable_data: ImmutableData) -> None:
    # mypy will prevent mutations here as well:
    immutable_data.immutable_list.append("something")

같은 원리를 사용하여 명령을 수행할 수 있습니다.typing.Mapping.

두 요소 튜플을 사용하여 리스프 스타일의 불변 단일 연결 목록을 시뮬레이션할 수 있습니다(참고: 이것은 유연성이 훨씬 떨어지는 튜플을 생성하는 임의 요소 튜플 응답과는 다릅니다).

nil = ()
cons = lambda ele, l: (ele, l)

예를 들어 일람표를 위하여[1, 2, 3], 당신은 다음과 같은 것을 갖게 될 것입니다.

l = cons(1, cons(2, cons(3, nil))) # (1, (2, (3, ())))

너의 기준car그리고.cdr함수는 간단합니다.

car = lambda l: l[0]
cdr = lambda l: l[1]

이 리스트는 단독으로 링크되어 있기 때문에, 앞에 붙는 것은 O(1)입니다.이 목록은 불변이므로 목록의 기본 요소도 불변인 경우 다른 목록에서 재사용할 하위 목록을 안전하게 공유할 수 있습니다.

그러나 배열과 튜플의 튜플이 있다면 튜플 내부의 배열은 수정될 수 있습니다.

>>> a
([1, 2, 3], (4, 5, 6))

>>> a[0][0] = 'one'

>>> a
(['one', 2, 3], (4, 5, 6))

List와 Tuple은 작업 스타일에 차이가 있습니다.

LIST에서는 작성 후 변경이 가능하지만 추후 변경이 적용될 수 없는 순서대로 진행하기를 원한다면 TUPLE을 사용할 수 있습니다.

추가 정보:

 1) the LIST is mutable that means you can make changes in it after its creation
 2) In Tuple, we can not make changes once it created
 3) the List syntax is
           abcd=[1,'avn',3,2.0]
 4) the syntax for Tuple is 
           abcd=(1,'avn',3,2.0) 
      or   abcd= 1,'avn',3,2.0 it is also correct

튜플 대신 프로즌셋을 사용할 수 있습니다.frozenset은 불변의 집합을 만듭니다.목록을 frozenset의 멤버로 사용할 수 있으며, single for loop을 사용하여 frozenset 내부의 목록의 모든 요소에 접근할 수 있습니다.

언급URL : https://stackoverflow.com/questions/11142397/does-python-have-an-immutable-list

반응형