development/script

415 지원되지 않는 미디어 유형, Spring 3 mvc로 POST JSON이 실패 함

big-blog 2020. 5. 30. 09:52
반응형

Vim : 시작할 때와 같은 다른 [이름 없음] 버퍼를 어떻게 열 수 있습니까?


내 Vimscript 프로그램에서 파일과 즉시 연결되지는 않지만 추가 된 Vim 버퍼를 열어야하지만 사용자는라는 초기 버퍼와 같이 선택한 파일에 저장할 수 있습니다 [No Name]. 어떻게해야합니까?


이름없이 새 버퍼를 여는 방법에는 여러 가지가 있으며 가장 간단한 방법은입니다 :new.

:new 명명되지 않은 버퍼로 분할 창을 만듭니다.

:enew 현재 창에서 하나를 엽니 다.

:vnew 세로로 분할 된 창에서 하나를 엽니 다.

:tabnew 새 탭에서 열립니다.


일반 모드에서을 입력하십시오 :new<CR>.


당신은 또한 조사 할 수 있습니다 :sp filename

나는 항상 분할 창을 사용합니다. 매우 훌륭합니다. 화면과 함께 많은 즐거움이 있습니다.

참고 URL : https://stackoverflow.com/questions/4478111/vim-how-do-you-open-another-no-name-buffer-like-the-one-on-startup

파이썬에서 불변의 객체를 만드는 법?


필자는 이것이 필요하지 않았지만 파이썬에서 불변의 객체를 만드는 것이 약간 까다로울 수 있다는 사실에 놀랐습니다. 을 (를) 재정의 __setattr__할 수 없습니다 __init__.에 속성을 설정할 수도 없기 때문 입니다. 튜플 서브 클래 싱은 작동하는 트릭입니다.

class Immutable(tuple):

    def __new__(cls, a, b):
        return tuple.__new__(cls, (a, b))

    @property
    def a(self):
        return self[0]

    @property
    def b(self):
        return self[1]

    def __str__(self):
        return "<Immutable {0}, {1}>".format(self.a, self.b)

    def __setattr__(self, *ignored):
        raise NotImplementedError

    def __delattr__(self, *ignored):
        raise NotImplementedError

그러나 당신은 aand를 b통해 self[0]and 변수에 액세스 할 수 있습니다 self[1].

Pure Python에서 가능합니까? 그렇지 않은 경우 C 확장으로 어떻게합니까?

(Python 3에서만 작동하는 답변이 허용됩니다).

최신 정보:

그래서 서브 클래스 튜플 잘하여 데이터를 액세스하는 추가 가능성을 제외하고 작동 순수 파이썬, 그것을 할 수있는 방법이다 [0], [1]등등 그래서이 누락되는 모든 C에 "제대로"그것을 할 HOWTO이다이 질문을 완료하는 나는 단지 geititem또는 setattribute등을 구현하지 않음으로써 매우 간단하다고 생각합니다 . 그러나 나 자신을 대신하는 대신 게으 르기 때문에 그에 대한 현상금을 제공합니다. :)


방금 생각한 또 다른 솔루션 : 원래 코드와 동일한 동작을 얻는 가장 간단한 방법은

Immutable = collections.namedtuple("Immutable", ["a", "b"])

이 속성을 통해 액세스 할 수 있는지 문제가 해결되지 않는 [0]등,하지만 적어도 그것은 상당히 짧다과 호환되는 부가적인 장점 제공 picklecopy.

namedtuple내가 설명 것과 유사한 유형의 생성 이 답변 에서 파생하여 예 tuple및 사용 __slots__. Python 2.6 이상에서 사용할 수 있습니다.


가장 쉬운 방법은 다음을 사용하는 것입니다 __slots__.

class A(object):
    __slots__ = []

A속성을 설정할 수 없으므로 인스턴스 는 변경할 수 없습니다.

클래스 인스턴스에 데이터가 포함되도록하려면 다음에서 파생 된 것과 결합 할 수 있습니다 tuple.

from operator import itemgetter
class Point(tuple):
    __slots__ = []
    def __new__(cls, x, y):
        return tuple.__new__(cls, (x, y))
    x = property(itemgetter(0))
    y = property(itemgetter(1))

p = Point(2, 3)
p.x
# 2
p.y
# 3

편집 : 인덱싱을 제거하려면 다음을 무시하십시오 __getitem__().

class Point(tuple):
    __slots__ = []
    def __new__(cls, x, y):
        return tuple.__new__(cls, (x, y))
    @property
    def x(self):
        return tuple.__getitem__(self, 0)
    @property
    def y(self):
        return tuple.__getitem__(self, 1)
    def __getitem__(self, item):
        raise TypeError

operator.itemgetter이 경우 속성 Point.__getitem__()대신에 사용할 수 있으므로 속성에 사용할 수 없습니다 tuple.__getitem__(). 또한 이것으로의 사용을 막을 tuple.__getitem__(p, 0)수는 없지만 이것이 어떻게 문제를 구성 해야하는지 상상할 수는 없습니다.

나는 불변의 객체를 만드는 "올바른"방법이 C 확장을 작성한다고 생각하지 않습니다. 파이썬은 일반적으로 성인동의하는 라이브러리 구현 자 및 라이브러리 사용자에 의존하며 실제로 인터페이스를 시행하는 대신 설명서에 인터페이스를 명확하게 명시해야합니다. 이것이 내가 문제 __setattr__()를 부름 으로써 재정의를 피할 가능성을 고려하지 않는 이유 object.__setattr__()입니다. 누군가이 일을하면 위험을 감수해야합니다.


C.에서 "올바로"수행하는 방법

Cython 을 사용하여 Python의 확장 유형을 작성할 수 있습니다 .

cdef class Immutable:
    cdef readonly object a, b
    cdef object __weakref__ # enable weak referencing support

    def __init__(self, a, b):
        self.a, self.b = a, b

Python 2.x와 3 모두에서 작동합니다.

테스트

# compile on-the-fly
import pyximport; pyximport.install() # $ pip install cython
from immutable import Immutable

o = Immutable(1, 2)
assert o.a == 1, str(o.a)
assert o.b == 2

try: o.a = 3
except AttributeError:
    pass
else:
    assert 0, 'attribute must be readonly'

try: o[1]
except TypeError:
    pass
else:
    assert 0, 'indexing must not be supported'

try: o.c = 1
except AttributeError:
    pass
else:
    assert 0, 'no new attributes are allowed'

o = Immutable('a', [])
assert o.a == 'a'
assert o.b == []

o.b.append(3) # attribute may contain mutable object
assert o.b == [3]

try: o.c
except AttributeError:
    pass
else:
    assert 0, 'no c attribute'

o = Immutable(b=3,a=1)
assert o.a == 1 and o.b == 3

try: del o.b
except AttributeError:
    pass
else:
    assert 0, "can't delete attribute"

d = dict(b=3, a=1)
o = Immutable(**d)
assert o.a == d['a'] and o.b == d['b']

o = Immutable(1,b=3)
assert o.a == 1 and o.b == 3

try: object.__setattr__(o, 'a', 1)
except AttributeError:
    pass
else:
    assert 0, 'attributes are readonly'

try: object.__setattr__(o, 'c', 1)
except AttributeError:
    pass
else:
    assert 0, 'no new attributes'

try: Immutable(1,c=3)
except TypeError:
    pass
else:
    assert 0, 'accept only a,b keywords'

for kwd in [dict(a=1), dict(b=2)]:
    try: Immutable(**kwd)
    except TypeError:
        pass
    else:
        assert 0, 'Immutable requires exactly 2 arguments'

인덱싱 지원이 마음에 들지 않으면 @Sven Marnachcollections.namedtuple제안하는 것이 좋습니다 .

Immutable = collections.namedtuple("Immutable", "a b")

또 다른 아이디어는 생성자에서 완전히 허용하지 __setattr__않고 사용하는 것 object.__setattr__입니다.

class Point(object):
    def __init__(self, x, y):
        object.__setattr__(self, "x", x)
        object.__setattr__(self, "y", y)
    def __setattr__(self, *args):
        raise TypeError
    def __delattr__(self, *args):
        raise TypeError

물론 당신은 사용할 수 object.__setattr__(p, "x", 3)수정 Point인스턴스를 p,하지만 같은 문제에서 원래 구현 겪고있다가 (시도 tuple.__setattr__(i, "x", 42)Immutable경우).

원래 구현에서 동일한 트릭을 적용 할 수 있습니다.를 제거 __getitem__()하고 tuple.__getitem__()속성 함수에서 사용 하십시오.


당신은 만들 수 @immutable중 하나는보다 우선 장식을 __setattr__ 하고 을 변경 __slots__빈 목록에 다음 장식 __init__함께 방법을.

편집 : OP가 언급했듯이 __slots__속성을 변경 하면 수정이 아닌 새 속성을 만들 수 없습니다.

Edit2 : 구현은 다음과 같습니다.

Edit3 :를 사용 __slots__하면 객체의 생성이 중지 되므로이 코드가 중단됩니다 __dict__. 대안을 찾고 있습니다.

Edit4 : 글쎄. 그것은 hackish이지만 운동으로 작동합니다 :-)

class immutable(object):
    def __init__(self, immutable_params):
        self.immutable_params = immutable_params

    def __call__(self, new):
        params = self.immutable_params

        def __set_if_unset__(self, name, value):
            if name in self.__dict__:
                raise Exception("Attribute %s has already been set" % name)

            if not name in params:
                raise Exception("Cannot create atribute %s" % name)

            self.__dict__[name] = value;

        def __new__(cls, *args, **kws):
            cls.__setattr__ = __set_if_unset__

            return super(cls.__class__, cls).__new__(cls, *args, **kws)

        return __new__

class Point(object):
    @immutable(['x', 'y'])
    def __new__(): pass

    def __init__(self, x, y):
        self.x = x
        self.y = y

p = Point(1, 2) 
p.x = 3 # Exception: Attribute x has already been set
p.z = 4 # Exception: Cannot create atribute z

나는 튜플이나 명명 된 튜플을 사용하는 것을 제외하고는 완전히 가능하다고 생각하지 않습니다. 어쨌든 __setattr__()사용자 를 재정의 하는 경우 항상 object.__setattr__()직접 호출하여 사용자 를 무시할 있습니다. 의존하는 솔루션은 __setattr__작동하지 않습니다.

다음은 일종의 튜플을 사용하지 않고 얻을 수있는 가장 가까운 것입니다.

class Immutable:
    __slots__ = ['a', 'b']
    def __init__(self, a, b):
        object.__setattr__(self, 'a', a)
        object.__setattr__(self, 'b', b)
    def __setattr__(self, *ignored):
        raise NotImplementedError
    __delattr__ = __setattr__

그러나 충분히 노력하면 깨집니다.

>>> t = Immutable(1, 2)
>>> t.a
1
>>> object.__setattr__(t, 'a', 2)
>>> t.a
2

그러나 Sven의 사용 namedtuple은 진정으로 불변입니다.

최신 정보

C에서 올바르게 수행하는 방법을 묻는 질문이 업데이트되었으므로 Cython에서 올바르게 수행하는 방법에 대한 내 대답은 다음과 같습니다.

먼저 immutable.pyx:

cdef class Immutable:
    cdef object _a, _b

    def __init__(self, a, b):
        self._a = a
        self._b = b

    property a:
        def __get__(self):
            return self._a

    property b:
        def __get__(self):
            return self._b

    def __repr__(self):
        return "<Immutable {0}, {1}>".format(self.a, self.b)

그리고 setup.py그것을 컴파일하기 위해 (명령을 사용하여 setup.py build_ext --inplace:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

ext_modules = [Extension("immutable", ["immutable.pyx"])]

setup(
  name = 'Immutable object',
  cmdclass = {'build_ext': build_ext},
  ext_modules = ext_modules
)

그런 다음 사용해보십시오.

>>> from immutable import Immutable
>>> p = Immutable(2, 3)
>>> p
<Immutable 2, 3>
>>> p.a = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: attribute 'a' of 'immutable.Immutable' objects is not writable
>>> object.__setattr__(p, 'a', 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: attribute 'a' of 'immutable.Immutable' objects is not writable
>>> p.a, p.b
(2, 3)
>>>      

우아한 해결책 은 다음과 같습니다 .

class Immutable(object):
    def __setattr__(self, key, value):
        if not hasattr(self, key):
            super().__setattr__(key, value)
        else:
            raise RuntimeError("Can't modify immutable object's attribute: {}".format(key))

이 클래스에서 상속하여 생성자에서 필드를 초기화하면 모든 설정이 완료됩니다.


훌륭한 다른 답변 외에도 파이썬 3.4 (또는 3.3)에 대한 메소드를 추가하고 싶습니다. 이 답변은이 질문에 대한 몇 가지 이전 답변을 바탕으로합니다.

Python 3.4에서는 setter없이 속성 사용 하여 수정할 수없는 클래스 멤버를 만들 수 있습니다. (이전 버전에서는 세터없이 속성에 할당 할 수있었습니다.)

class A:
    __slots__=['_A__a']
    def __init__(self, aValue):
      self.__a=aValue
    @property
    def a(self):
        return self.__a

다음과 같이 사용할 수 있습니다.

instance=A("constant")
print (instance.a)

인쇄됩니다 "constant"

그러나 전화 instance.a=10하면

AttributeError: can't set attribute

설명 : setter가없는 속성은 python 3.4의 최신 기능입니다 (그리고 3.3이라고 생각합니다). 이러한 속성에 할당하려고하면 오류가 발생합니다. 슬롯을 사용하여 멤버 변수를 __A_a()로 제한합니다 __a.

문제 :에 할당 할 _A__a수 있습니다 ( instance._A__a=2). 그러나 개인 변수에 할당하면 자신의 잘못입니다 ...

그러나이 답변 은의 사용을 권장하지 않습니다 __slots__. 속성 생성을 방지하기 위해 다른 방법을 사용하는 것이 좋습니다.


을 재정의 __setattr__하고 호출자가 __init__다음과 같은 경우 집합을 허용하여 불변 클래스를 만들었습니다 .

import inspect
class Immutable(object):
    def __setattr__(self, name, value):
        if inspect.stack()[2][3] != "__init__":
            raise Exception("Can't mutate an Immutable: self.%s = %r" % (name, value))
        object.__setattr__(self, name, value)

이것은 사람 ___init__이 객체를 변경할 수 있기 때문에 아직 충분하지 않지만 아이디어를 얻습니다.


동작이있는 객체에 관심이 있다면 namedtuple이 거의 해결책입니다.

namedtuple 문서 의 맨 아래에 설명 된 것처럼 namedtuple 에서 자신의 클래스를 파생시킬 수 있습니다. 그런 다음 원하는 동작을 추가 할 수 있습니다.

예를 들어 ( 문서 에서 직접 가져온 코드 ) :

class Point(namedtuple('Point', 'x y')):
    __slots__ = ()
    @property
    def hypot(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5
    def __str__(self):
        return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

for p in Point(3, 4), Point(14, 5/7):
    print(p)

결과는 다음과 같습니다.

Point: x= 3.000  y= 4.000  hypot= 5.000
Point: x=14.000  y= 0.714  hypot=14.018

이 접근법은 Python 3과 Python 2.7 모두에서 작동합니다 (IronPython에서도 테스트 됨).
유일한 단점은 상속 트리가 약간 이상하다는 것입니다. 그러나 이것은 당신이 보통 가지고 노는 것이 아닙니다.


나는 조금 전에 이것을 필요로했고 그것을 위해 파이썬 패키지를 만들기로 결정했다. 초기 버전은 현재 PyPI에 있습니다.

$ pip install immutable

쓰다:

>>> from immutable import ImmutableFactory
>>> MyImmutable = ImmitableFactory.create(prop1=1, prop2=2, prop3=3)
>>> MyImmutable.prop1
1

전체 문서 : https://github.com/theengineear/immutable

그것이 도움이되기를 바랍니다. 그것은 논의 된 것처럼 명명 된 튜플을 감싸지 만 인스턴스화를 훨씬 간단하게 만듭니다.


이 방법은 object.__setattr__작동을 멈추지 않지만 여전히 유용하다는 것을 알았습니다.

class A(object):

    def __new__(cls, children, *args, **kwargs):
        self = super(A, cls).__new__(cls)
        self._frozen = False  # allow mutation from here to end of  __init__
        # other stuff you need to do in __new__ goes here
        return self

    def __init__(self, *args, **kwargs):
        super(A, self).__init__()
        self._frozen = True  # prevent future mutation

    def __setattr__(self, name, value):
        # need to special case setting _frozen.
        if name != '_frozen' and self._frozen:
            raise TypeError('Instances are immutable.')
        else:
            super(A, self).__setattr__(name, value)

    def __delattr__(self, name):
        if self._frozen:
            raise TypeError('Instances are immutable.')
        else:
            super(A, self).__delattr__(name)

__setitem__사용 사례에 따라 더 많은 것들 (예 :)을 재정의해야 할 수도 있습니다 .


다음 Immutable클래스 에서 상속 된 클래스는 __init__메서드 실행이 완료된 후 인스턴스와 마찬가지로 변경할 수 없습니다 . 순수한 파이썬이기 때문에 다른 사람들이 지적 밖으로을 가지고, 거기에베이스에서 돌연변이 특별한 방법을 사용하여 누군가 중지 아무것도 object하고는 type, 그러나 이것은 실수로 클래스 / 인스턴스를 돌연변이에서 정지 누군가에 충분하다.

메타 클래스로 클래스 생성 프로세스를 가로채는 방식으로 작동합니다.

"""Subclasses of class Immutable are immutable after their __init__ has run, in
the sense that all special methods with mutation semantics (in-place operators,
setattr, etc.) are forbidden.

"""  

# Enumerate the mutating special methods
mutation_methods = set()
# Arithmetic methods with in-place operations
iarithmetic = '''add sub mul div mod divmod pow neg pos abs bool invert lshift
                 rshift and xor or floordiv truediv matmul'''.split()
for op in iarithmetic:
    mutation_methods.add('__i%s__' % op)
# Operations on instance components (attributes, items, slices)
for verb in ['set', 'del']:
    for component in '''attr item slice'''.split():
        mutation_methods.add('__%s%s__' % (verb, component))
# Operations on properties
mutation_methods.update(['__set__', '__delete__'])


def checked_call(_self, name, method, *args, **kwargs):
    """Calls special method method(*args, **kw) on self if mutable."""
    self = args[0] if isinstance(_self, object) else _self
    if not getattr(self, '__mutable__', True):
        # self told us it's immutable, so raise an error
        cname= (self if isinstance(self, type) else self.__class__).__name__
        raise TypeError('%s is immutable, %s disallowed' % (cname, name))
    return method(*args, **kwargs)


def method_wrapper(_self, name):
    "Wrap a special method to check for mutability."
    method = getattr(_self, name)
    def wrapper(*args, **kwargs):
        return checked_call(_self, name, method, *args, **kwargs)
    wrapper.__name__ = name
    wrapper.__doc__ = method.__doc__
    return wrapper


def wrap_mutating_methods(_self):
    "Place the wrapper methods on mutative special methods of _self"
    for name in mutation_methods:
        if hasattr(_self, name):
            method = method_wrapper(_self, name)
            type.__setattr__(_self, name, method)


def set_mutability(self, ismutable):
    "Set __mutable__ by using the unprotected __setattr__"
    b = _MetaImmutable if isinstance(self, type) else Immutable
    super(b, self).__setattr__('__mutable__', ismutable)


class _MetaImmutable(type):

    '''The metaclass of Immutable. Wraps __init__ methods via __call__.'''

    def __init__(cls, *args, **kwargs):
        # Make class mutable for wrapping special methods
        set_mutability(cls, True)
        wrap_mutating_methods(cls)
        # Disable mutability
        set_mutability(cls, False)

    def __call__(cls, *args, **kwargs):
        '''Make an immutable instance of cls'''
        self = cls.__new__(cls)
        # Make the instance mutable for initialization
        set_mutability(self, True)
        # Execute cls's custom initialization on this instance
        self.__init__(*args, **kwargs)
        # Disable mutability
        set_mutability(self, False)
        return self

    # Given a class T(metaclass=_MetaImmutable), mutative special methods which
    # already exist on _MetaImmutable (a basic type) cannot be over-ridden
    # programmatically during _MetaImmutable's instantiation of T, because the
    # first place python looks for a method on an object is on the object's
    # __class__, and T.__class__ is _MetaImmutable. The two extant special
    # methods on a basic type are __setattr__ and __delattr__, so those have to
    # be explicitly overridden here.

    def __setattr__(cls, name, value):
        checked_call(cls, '__setattr__', type.__setattr__, cls, name, value)

    def __delattr__(cls, name, value):
        checked_call(cls, '__delattr__', type.__delattr__, cls, name, value)


class Immutable(object):

    """Inherit from this class to make an immutable object.

    __init__ methods of subclasses are executed by _MetaImmutable.__call__,
    which enables mutability for the duration.

    """

    __metaclass__ = _MetaImmutable


class T(int, Immutable):  # Checks it works with multiple inheritance, too.

    "Class for testing immutability semantics"

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

    @classmethod
    def class_mutation(cls):
        cls.a = 5

    def instance_mutation(self):
        self.c = 1

    def __iadd__(self, o):
        pass

    def not_so_special_mutation(self):
        self +=1

def immutabilityTest(f, name):
    "Call f, which should try to mutate class T or T instance."
    try:
        f()
    except TypeError, e:
        assert 'T is immutable, %s disallowed' % name in e.args
    else:
        raise RuntimeError('Immutability failed!')

immutabilityTest(T.class_mutation, '__setattr__')
immutabilityTest(T(6).instance_mutation, '__setattr__')
immutabilityTest(T(6).not_so_special_mutation, '__iadd__')

Python 3.7부터 클래스 에서 @dataclass데코레이터사용할 수 있으며 구조체처럼 변경할 수 없습니다! 그러나 __hash__()클래스에 메소드를 추가하거나 추가하지 않을 수 있습니다 . 인용문:

hash ()는 내장 hash ()에서 사용되며 사전 및 세트와 같은 해시 콜렉션에 오브젝트가 추가 될 때 사용됩니다. 해시 ()가 있으면 클래스의 인스턴스는 변경할 수 없습니다. 변경 가능성은 프로그래머의 의도, eq () 의 존재 및 동작 , dataclass () 데코레이터의 eq 및 고정 플래그 값에 따라 달라지는 복잡한 속성입니다 .

기본적으로 dataclass () 는 안전하지 않은 경우 암시 적으로 해시 () 메서드를 추가하지 않습니다 . 기존의 명시 적으로 정의 된 해시 () 메소드를 추가하거나 변경하지도 않습니다 . 클래스 속성 hash = None 설정은 해시 () 문서에 설명 된대로 Python에 특정한 의미를 갖습니다 .

경우 해시 () 정의 명시가 아니거나 없음으로 설정되어있는 경우, 다음 dataclass () 암시 추가 할 수 있습니다 해시 () 메소드를. 권장되지는 않지만, unsafe_hash = True 를 사용하여 dataclass ()가 해시 () 메소드 를 작성하도록 할 수 있습니다 . 클래스가 논리적으로 변경 불가능하지만 변경 될 수있는 경우에 해당 될 수 있습니다. 이것은 특수한 사용 사례이므로 신중하게 고려해야합니다.

다음은 위의 문서에서 가져온 예제입니다.

@dataclass
class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

타사 attr모듈은 이 기능을 제공 합니다 .

편집 : python 3.7은이 아이디어를 stdlib에 채택했습니다 @dataclass.

$ pip install attrs
$ python
>>> @attr.s(frozen=True)
... class C(object):
...     x = attr.ib()
>>> i = C(1)
>>> i.x = 2
Traceback (most recent call last):
   ...
attr.exceptions.FrozenInstanceError: can't set attribute

attr__setattr__설명서에 따라 재정 의하여 고정 클래스를 구현 하고 각 인스턴스화 시간에 약간의 성능 영향을 미칩니다.

클래스를 데이터 유형으로 사용하는 습관이 있다면 attr, 상용구를 처리 할 때 특히 유용 할 수 있습니다 (그러나 마술은하지 않습니다). 특히, repr, init, hash 및 모든 비교 함수를 포함하여 9 개의 dunder (__ X__) 메소드를 작성합니다 (해당 메소드를 끄지 않는 한).

attr에 대한 도우미__slots__ 도 제공합니다 .


setattr 을 재정의 하고 init 를 사용하여 변수를 설정할 수 있습니다. 수퍼 클래스 setattr을 사용 합니다. 여기 코드가 있습니다.

불변의 클래스 :
    __slots__ = ( 'a', 'b')
    데프 __init __ (자체, a, b) :
        super () .__ setattr __ ( 'a', a)
        super () .__ setattr __ ( 'b', b)

    데프 __str__ (자체) :
        "".format (self.a, self.b) 반환

    데프 __setattr __ (자기, * 무시) :
        NotImplementedError 발생

    데프 __delattr __ (자기, * 무시) :
        NotImplementedError 발생

다른 방법은 인스턴스를 변경할 수없는 래퍼를 만드는 것입니다.

class Immutable(object):

    def __init__(self, wrapped):
        super(Immutable, self).__init__()
        object.__setattr__(self, '_wrapped', wrapped)

    def __getattribute__(self, item):
        return object.__getattribute__(self, '_wrapped').__getattribute__(item)

    def __setattr__(self, key, value):
        raise ImmutableError('Object {0} is immutable.'.format(self._wrapped))

    __delattr__ = __setattr__

    def __iter__(self):
        return object.__getattribute__(self, '_wrapped').__iter__()

    def next(self):
        return object.__getattribute__(self, '_wrapped').next()

    def __getitem__(self, item):
        return object.__getattribute__(self, '_wrapped').__getitem__(item)

immutable_instance = Immutable(my_instance)

이것은 함수 호출의 기본 인수와 같이 일부 인스턴스 만 변경할 수없는 상황에서 유용합니다.

다음과 같은 불변 공장에서 사용할 수도 있습니다 :

@classmethod
def immutable_factory(cls, *args, **kwargs):
    return Immutable(cls.__init__(*args, **kwargs))

또한 object.__setattr__파이썬의 동적 특성으로 인해 다른 트릭에 빠지지는 않지만 보호합니다 .


Alex와 같은 아이디어를 사용했습니다 : 메타 클래스와 "초기 마커", 덮어 쓰기 __setattr__과 함께 :

>>> from abc import ABCMeta
>>> _INIT_MARKER = '_@_in_init_@_'
>>> class _ImmutableMeta(ABCMeta):
... 
...     """Meta class to construct Immutable."""
... 
...     def __call__(cls, *args, **kwds):
...         obj = cls.__new__(cls, *args, **kwds)
...         object.__setattr__(obj, _INIT_MARKER, True)
...         cls.__init__(obj, *args, **kwds)
...         object.__delattr__(obj, _INIT_MARKER)
...         return obj
...
>>> def _setattr(self, name, value):
...     if hasattr(self, _INIT_MARKER):
...         object.__setattr__(self, name, value)
...     else:
...         raise AttributeError("Instance of '%s' is immutable."
...                              % self.__class__.__name__)
...
>>> def _delattr(self, name):
...     raise AttributeError("Instance of '%s' is immutable."
...                          % self.__class__.__name__)
...
>>> _im_dict = {
...     '__doc__': "Mix-in class for immutable objects.",
...     '__copy__': lambda self: self,   # self is immutable, so just return it
...     '__setattr__': _setattr,
...     '__delattr__': _delattr}
...
>>> Immutable = _ImmutableMeta('Immutable', (), _im_dict)

참고 : Python 2.x 및 3.x 모두에서 작동하도록 메타 클래스를 직접 호출하고 있습니다.

>>> class T1(Immutable):
... 
...     def __init__(self, x=1, y=2):
...         self.x = x
...         self.y = y
...
>>> t1 = T1(y=8)
>>> t1.x, t1.y
(1, 8)
>>> t1.x = 7
AttributeError: Instance of 'T1' is immutable.

슬롯에서도 작동합니다 ... :

>>> class T2(Immutable):
... 
...     __slots__ = 's1', 's2'
... 
...     def __init__(self, s1, s2):
...         self.s1 = s1
...         self.s2 = s2
...
>>> t2 = T2('abc', 'xyz')
>>> t2.s1, t2.s2
('abc', 'xyz')
>>> t2.s1 += 'd'
AttributeError: Instance of 'T2' is immutable.

... 그리고 다중 상속 :

>>> class T3(T1, T2):
... 
...     def __init__(self, x, y, s1, s2):
...         T1.__init__(self, x, y)
...         T2.__init__(self, s1, s2)
...
>>> t3 = T3(12, 4, 'a', 'b')
>>> t3.x, t3.y, t3.s1, t3.s2
(12, 4, 'a', 'b')
>>> t3.y -= 3
AttributeError: Instance of 'T3' is immutable.

그러나 변경 가능한 속성은 변경 가능한 상태로 유지됩니다.

>>> t3 = T3(12, [4, 7], 'a', 'b')
>>> t3.y.append(5)
>>> t3.y
[4, 7, 5]

여기에 실제로 포함되지 않은 한 가지는 전체 불변성입니다. 부모 개체뿐만 아니라 모든 자식도 마찬가지입니다. 예를 들어 튜플 / 냉동 세트는 변경할 수 없지만 그 일부가 아닐 수도 있습니다. 다음은 불변성을 강제하는 적절한 작업을 수행하는 작은 (불완전한) 버전입니다.

# Initialize lists
a = [1,2,3]
b = [4,5,6]
c = [7,8,9]

l = [a,b]

# We can reassign in a list 
l[0] = c

# But not a tuple
t = (a,b)
#t[0] = c -> Throws exception
# But elements can be modified
t[0][1] = 4
t
([1, 4, 3], [4, 5, 6])
# Fix it back
t[0][1] = 2

li = ImmutableObject(l)
li
[[1, 2, 3], [4, 5, 6]]
# Can't assign
#li[0] = c will fail
# Can reference
li[0]
[1, 2, 3]
# But immutability conferred on returned object too
#li[0][1] = 4 will throw an exception

# Full solution should wrap all the comparison e.g. decorators.
# Also, you'd usually want to add a hash function, i didn't put
# an interface for that.

class ImmutableObject(object):
    def __init__(self, inobj):
        self._inited = False
        self._inobj = inobj
        self._inited = True

    def __repr__(self):
        return self._inobj.__repr__()

    def __str__(self):
        return self._inobj.__str__()

    def __getitem__(self, key):
        return ImmutableObject(self._inobj.__getitem__(key))

    def __iter__(self):
        return self._inobj.__iter__()

    def __setitem__(self, key, value):
        raise AttributeError, 'Object is read-only'

    def __getattr__(self, key):
        x = getattr(self._inobj, key)
        if callable(x):
              return x
        else:
              return ImmutableObject(x)

    def __hash__(self):
        return self._inobj.__hash__()

    def __eq__(self, second):
        return self._inobj.__eq__(second)

    def __setattr__(self, attr, value):
        if attr not in  ['_inobj', '_inited'] and self._inited == True:
            raise AttributeError, 'Object is read-only'
        object.__setattr__(self, attr, value)

최종 init 명령문에서 setAttr을 대체 할 수 있습니다. 구성 할 수는 있지만 변경할 수는 없습니다. 분명히 usint 객체로 재정의 할 수 있습니다. setAttr 그러나 실제로 대부분의 언어에는 어떤 형태의 반성이 있기 때문에 불변성은 항상 누출되는 추상화입니다. 불변성은 클라이언트가 실수로 객체의 계약을 위반하는 것을 방지하는 것입니다. 나는 사용한다:

===============================

제공된 원래 솔루션이 잘못되었습니다. 여기 에서 솔루션을 사용한 의견을 기반으로 업데이트되었습니다.

원래 솔루션은 흥미로운 방식으로 잘못되었으므로 하단에 포함되어 있습니다.

================================

class ImmutablePair(object):

    __initialised = False # a class level variable that should always stay false.
    def __init__(self, a, b):
        try :
            self.a = a
            self.b = b
        finally:
            self.__initialised = True #an instance level variable

    def __setattr__(self, key, value):
        if self.__initialised:
            self._raise_error()
        else :
            super(ImmutablePair, self).__setattr__(key, value)

    def _raise_error(self, *args, **kw):
        raise NotImplementedError("Attempted To Modify Immutable Object")

if __name__ == "__main__":

    immutable_object = ImmutablePair(1,2)

    print immutable_object.a
    print immutable_object.b

    try :
        immutable_object.a = 3
    except Exception as e:
        print e

    print immutable_object.a
    print immutable_object.b

출력 :

1
2
Attempted To Modify Immutable Object
1
2

========================================

원래 구현 :

주석에서 클래스 setattr 메소드를 오버라이드 할 때 둘 이상의 객체가 생성되는 것을 막기 때문에 실제로 작동하지 않는다는 점이 올바르게 지적되었습니다. 두 번째 초기화에서 실패합니다.

class ImmutablePair(object):

    def __init__(self, a, b):
        self.a = a
        self.b = b
        ImmutablePair.__setattr__ = self._raise_error

    def _raise_error(self, *args, **kw):
        raise NotImplementedError("Attempted To Modify Immutable Object")

아래의 기본 솔루션은 다음 시나리오를 해결합니다.

  • __init__() 평소처럼 속성에 액세스하여 쓸 수 있습니다.
  • 속성 변경에 대해서만 OBJECT가 고정 된 후 :

아이디어는 __setattr__객체 고정 상태가 변경 될 때마다 메서드 를 재정의 하고 구현을 대체하는 것입니다.

따라서 우리 _freeze는 두 구현을 저장하고 요청시 그들 사이를 전환하는 메소드 ( ) 가 필요합니다 .

이 메커니즘은 사용자 클래스 내부에서 구현되거나 Freezer아래와 같이 특수 클래스 에서 상속 될 수 있습니다.

class Freezer:
    def _freeze(self, do_freeze=True):
        def raise_sa(*args):            
            raise AttributeError("Attributes are frozen and can not be changed!")
        super().__setattr__('_active_setattr', (super().__setattr__, raise_sa)[do_freeze])

    def __setattr__(self, key, value):        
        return self._active_setattr(key, value)

class A(Freezer):    
    def __init__(self):
        self._freeze(False)
        self.x = 10
        self._freeze()

참고 URL : https://stackoverflow.com/questions/4828080/how-to-make-an-immutable-object-in-python

반응형