Why do set operations work with iterables only when using methods? - python

Why do set operations work with arbitrary iterables when using set methods, but not operators? To show what I mean:
>>> {0, 1, 2, 3}.intersection([0, 1])
{0, 1}
>>> {0, 1, 2, 3} & [0, 1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for &: 'set' and 'list'
>>>
>>> {0, 1, 2, 3}.union([4, 5])
{0, 1, 2, 3, 4, 5}
>>> {0, 1, 2, 3} | [4, 5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for |: 'set' and 'list'

From the docs:
Note, the non-operator versions of union(), intersection(), difference(), and symmetric_difference(), issubset(), and issuperset() methods will accept any iterable as an argument. In contrast, their operator based counterparts require their arguments to be sets. This precludes error-prone constructions like set('abc') & 'cbs' in favor of the more readable set('abc').intersection('cbs').
It was considered less error-prone this way.

Related

assertEqual vs assertSetEqulal in unittest

Is there a difference between assertEquals and assertSetEqual in the python unittest.TestCase for assertion of sets or frozensets?
And if there is not, why are there assertSetEqual?
also for this situation we can use assertCountEqual and assertSequenceEqual!
.
.
.
self.assertEqual({1, 2, 3}, {1, 2, 3})
self.assertSetEqual({1, 2, 3}, {1, 2, 3})
.
.
.
The type-specific calls give type-specific error messages when they fail. For instance, for a set it will list the elements found in each set but not found in the other.
The docs note that assertEqual will call the type-specific test if both args are of the exact same type and if there is a type-specific test - thus, for two sets assertEqual will call assertSetEqual and therefore show the more helpful error message. However, it doesn't do this if both one arg is a set and the other is a frozenset. This may not come up often, but it's one case in which you might call assertSetEqual directly.
>>> TestCase().assertEqual({1, 2, 3}, frozenset((2, 1)))
Traceback (most recent call last):
...
AssertionError: {1, 2, 3} != frozenset({1, 2})
>>> TestCase().assertSetEqual({1, 2, 3}, frozenset((2, 1)))
Traceback (most recent call last):
...
AssertionError: Items in the first set but not the second:
3

What does "TypeError: unsupported operand type(s) for +: 'int' and 'tuple'" mean when using built-in sum function?

I'm struggling to understand TypeError when using built-in sum function.
First, I would appreciate if you could check following function.
def mysum(*args):
print(sum(args))
Second, I implemented following code.
mysum((1, 2, 3, 4, 5))
So, following error was outputted.
TypeError: unsupported operand type(s) for +: 'int' and 'tuple'
Thank you for reading this far.
It would be awesome if you could teach me this TypeError meaning.
When you define def mysum(*args):, python packs the function arguments into the single iterable "args" parameter. From the help text of sum
sum(iterable, /, start=0)
Return the sum of a 'start' value (default: 0) plus an iterable of numbers
Sum adds the values from the iterable to a start value that defaults to 0 (an integer). When you called mysum, args iterated a single tuple (1, 2, 3, 4, 5) and python attempted to do 0 + (1, 2, 3, 4, 5). You can add a print to the funciton to get a better idea of what's going on
>>> def mysum(*args):
... print(repr(args))
... print(sum(args))
...
>>> mysum((1, 2, 3, 4, 5))
((1, 2, 3, 4, 5),)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in mysum
TypeError: unsupported operand type(s) for +: 'int' and 'tuple'
You could try a list to get a different view of the same problem
>>> mysum([1, 2, 3, 4, 5])
([1, 2, 3, 4, 5],)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in mysum
TypeError: unsupported operand type(s) for +: 'int' and 'list'
You could unpack the tuple in the call. The function will repack it into the args parameter
>>> mysum(*(1, 2, 3, 4, 5))
(1, 2, 3, 4, 5)
15
And you can even redefine the start value and turn this into concatenation
>>> def mysum(*args):
... print(repr(args))
... print(sum(args, start=('a', 'b')))
...
>>> mysum((1,2,3,4,5))
((1, 2, 3, 4, 5),)
('a', 'b', 1, 2, 3, 4, 5)
>>>
>>> mysum((1,2,3,4,5),(6, 7, 8, 9, 10))
((1, 2, 3, 4, 5), (6, 7, 8, 9, 10))
('a', 'b', 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
You don't need to expand the argument with *, sum() itself expects list/tuple:
def mysum(args):
print(sum(args))
mysum((1, 2, 3, 4, 5))
If you need to specify arguments without the tuple (like mysum(1,2...)):
def mysum(*args):
print(sum(args))
mysum(1, 2, 3, 4, 5)
A star with a name in the argument list groups positional arguments into a tuple. That means that calling mysum((1, 2, 3, 4, 5)) creates a tuple for args with a single element, which is the tuple you're passing in. It's equivalent to doing the following within the function:
args = ((1, 2, 3, 4, 5),)
The error occurs because the default initial value for sum is the integer 0. You can't add a tuple to it.
Two simple solutions present themselves. The easiest is probably to call the function with individual arguments:
mysum(1, 2, 3, 4, 5)
If you must pass in a tuple, drop the asterisk in the function definition:
def mysum(args):

unsupported operand type(s) for +: 'numpy.ndarray' and 'str'

I want to get the result array(['0th', '1th', '2th', '3th', '4th']) by operating on the whole array given by np.array(range(5)).astype(str). I tried this:
>>> np.array(range(5))
array([0, 1, 2, 3, 4])
>>> np.array(range(5))*2
array([0, 2, 4, 6, 8])
>>> np.array(range(5)).astype(str)
array(['0', '1', '2', '3', '4'],
dtype='<U24')
>>> np.array(range(5)).astype(str)+"th"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'numpy.ndarray' and 'str'
I know I can do this using a list comprehension:
[ x+"th" for x in np.array(range(5)).astype(str) ] # can get the result,
but I would prefer a vectorized way to do the same thing, such as:
pandas.date_range("20150105",periods=16*7,freq="D").format(formatter=lambda x:x.strftime("%Y%m%d"))
Is this possible?
You can do something like this:
>>> np.core.defchararray.add(np.arange(5).astype(str), 'th')
array(['0th', '1th', '2th', '3th', '4th'],
dtype='|S26')
Possible solution:
>>> np.array([str(a) + 'th' for a in range(5)])
array(['0th', '1th', '2th', '3th', '4th'],
dtype='|S3')
I currently don't have the Numpy package in my computer, so I can't really test but here is my first thought.
np.array(range(5)).astype(str) seems to return a ndarray element of the form ndarray(list, str)
Does this works?:
print [ x+"th" for x in np.array(range(5)).astype(str)[0] ]

Why does building a set fail when using set(int)?

I can do
>>> s = {1}
>>> type(s)
<class 'set'>
but
>>> s = set(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'int' object is not iterable
What is the difference?
The difference is that the set() constructor takes an iterable. A single number is not an iterable.
s = set((1,))

Theano: Why does indexing fail in this case?

I'm trying to get the max of a vector given a boolean value.
With Numpy:
>>> this = np.arange(10)
>>> this[~(this>=5)].max()
4
But with Theano:
>>> that = T.arange(10, dtype='int32')
>>> that[~(that>=5)].max().eval()
9
>>> that[~(that>=5).nonzero()].max().eval()
Traceback (most recent call last):
File "<pyshell#146>", line 1, in <module>
that[~(that>=5).nonzero()].max().eval()
AttributeError: 'TensorVariable' object has no attribute 'nonzero'
Why does this happen? Is this a subtle nuance that i'm missing?
You are using a version of Theano that is too old. In fact, tensor_var.nonzero() isn't in any released version. You need to update to the development version.
With the development version I have this:
>>> that[~(that>=5).nonzero()].max().eval()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bad operand type for unary ~: 'tuple'
This is because you are missing parenthesis in your line. Here is the good line:
>>> that[(~(that>=5)).nonzero()].max().eval()
array(9, dtype=int32)
But we still have unexpected result! The problem is that Theano do not support bool. Doing ~ on int8, is doing the bitwise invert on 8 bits, not 1 bit. It give this result:
>>> (that>=5).eval()
array([0, 0, 0, 0, 0, 1, 1, 1, 1, 1], dtype=int8)
>>> (~(that>=5)).eval()
array([-1, -1, -1, -1, -1, -2, -2, -2, -2, -2], dtype=int8)
You can remove the ~ with this:
>>> that[(that<5).nonzero()].max().eval()
array(4, dtype=int32)

Categories

Resources