Why does updating a set in a tuple cause an error?

I just tried the following in Python 2.6:

>>> foo = (set(),)
>>> foo[0] |= set(range(5))
TypeError: 'tuple' object does not support item assignment
>>> foo
(set([0, 1, 2, 3, 4]),)
>>> foo[0].update(set(range(10)))
>>> foo
(set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),)

I have a few questions:

  • Why foo[0] |= set(range(5))updates the set and throws an exception?
  • Why foo[0].update(set(range(10)))does it work without problems? Should it have the same result as the first statement?

Change . Many people have indicated that tuples are immutable. I know about it. They also noted that they |=would create a new object setand assign it to a tuple. It is not right. See this:

>>> foo = set()
>>> bar = foo
>>> foo is bar
True
>>> foo |= set(range(5))
>>> foo
set([0, 1, 2, 3, 4])
>>> bar
set([0, 1, 2, 3, 4])
>>> foo is bar
True

, , . . , TypeError, . , . TypeError, , , ?

+3
8
>>> def f():
...   x = (set(),)
...   y = set([0])
...   x[0] |= y
...   return   
... 
>>> import dis
>>> dis.dis(f)
  2           0 LOAD_GLOBAL              0 (set)
              3 CALL_FUNCTION            0
              6 BUILD_TUPLE              1
              9 STORE_FAST               0 (x)

  3          12 LOAD_GLOBAL              0 (set)
             15 LOAD_CONST               1 (0)
             18 BUILD_LIST               1
             21 CALL_FUNCTION            1
             24 STORE_FAST               1 (y)

  4          27 LOAD_FAST                0 (x)
             30 LOAD_CONST               1 (0)
             33 DUP_TOPX                 2
             36 BINARY_SUBSCR       
             37 LOAD_FAST                1 (y)
             40 INPLACE_OR          
             41 ROT_THREE           
             42 STORE_SUBSCR        

  5          43 LOAD_CONST               0 (None)
             46 RETURN_VALUE        

, x[0] |= y , x[0].__ior__(y), x[0].

set |=, set.__ior__ return self. x[0] . , , , ; , :

x = (set(),)
x[0] = x[0]

.

+11

foo . Tuples python inmutable, , tuple - foo[0] . :

>>> x = ('foo','bar')
>>> x[0]='foo2'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> 

list

>>> foo = [set(),None]
>>> foo
[set([]), None]
>>> foo[0] |= set(range(5))
>>> foo
[set([0, 1, 2, 3, 4]), None]
>>> 
+2
foo[0] |= set(range(5)) 

, :

foo[0] = foo[0] | set(range(5))

, . , :

x = (0, 1, 2)
x[0] = 3

, . :

x = set()
y = (x,)
x.update(set(range(5))

, , x ( y[0]) .

x |= y

x.update(y)

, update , x |= y (x | y) x.

+1

. foo[0], , ( ). update(), , . , .

0

, . , , . , u '| =' u, ( ), , . .

u r , . . http://docs.python.org/reference/datamodel.html

0

" TypeError, ?".

. .

,

foo [0] | = set (range (5))

. .

.

foo [0].update(set (range (10))) ?

. .

, ?

. - - .

, , , .

- , ? ? .

( ).

( ) .

0

- "":

foo[0] |= set(range(5))
foo[0] = set.__ior__(foo[0], set(range(5)))
tuple.__setitem__(foo, 0, set.__ior__(foo[0], set(range(5))))

foo[0].update(set(range(5)))
set.__ior__(foo[0], set(range(5)))

, update , foo[0] . __or__ . foo.

, , , (, foo[0] -> tuple.__getitem__(foo, 0)).

TypeError tuple.__setitem__. tuple . update foo (.. tuple.__setitem__).

0
  • a |= b a = operator.ior(a, b).
  • s[i] |= b s[i] = operator.ior(s[i], b).
  • .
  • set.__ior__ set.update .

, .

The main problem is that changing the cost of a tuple is a violation of the contract. You should not try to do this. Since you may have some kind of object in the tuple, there are loopholes that you can use, but then you get the kind of strange behavior that you observe.

Tuple elements should be frozensetinstead set. If you do this, you will get consistent behavior and will not have an unwanted side effect on error.

0
source

Source: https://habr.com/ru/post/1759855/


All Articles