In PyCharm, when I write:
return set([(sy + ady, sx + adx)])
it says "Function call can be replaced with set literal" so it replaces it with:
return {(sy + ady, sx + adx)}
Why is that? A set() in Python is not the same as a dictionary {}?
And if it wants to optimize this, why is this more effective?
Python sets and dictionaries can both be constructed using curly braces:
my_dict = {'a': 1, 'b': 2}
my_set = {1, 2, 3}
The interpreter (and human readers) can distinguish between them based on their contents. However it isn't possible to distinguish between an empty set and an empty dict, so this case you need to use set() for empty sets to disambiguate.
A very simple test suggests that the literal construction is faster (python3.5):
>>> timeit.timeit('a = set([1, 2, 3])')
0.5449375328607857
>>> timeit.timeit('a = {1, 2, 3}')
0.20525191631168127
This question covers some issues of performance of literal constructions over builtin functions, albeit for lists and dicts. The summary seems to be that literal constructions require less work from the interpreter.
It is an alternative syntax for set()
>>> a = {1, 2}
>>> b = set()
>>> b.add(1)
>>> b.add(2)
>>> b
set([1, 2])
>>> a
set([1, 2])
>>> a == b
True
>>> type(a) == type(b)
True
dict syntax is different. It consists of key-value pairs. For example:
my_obj = {1:None, 2:None}
Another example how set and {} are not interchangeable (as jonrsharpe mentioned):
In: f = 'FH'
In: set(f)
Out: {'F', 'H'}
In: {f}
Out: {'FH'}
set([iterable]) is the constructor to create a set from the optional iterable iterable. And {} is to create set / dict object literals. So what is created depends on how you use it.
In [414]: x = {}
In [415]: type(x)
Out[415]: dict
In [416]: x = {1}
In [417]: type(x)
Out[417]: set
In [418]: x = {1: "hello"}
In [419]: type(x)
Out[419]: dict
Related
I'm solving a Python challenge which I answered it like this:
def areEquallyStrong(yourLeft, yourRight, friendsLeft, friendsRight):
return (yourLeft == friendsLeft or yourLeft == friendsRight)
and (yourRight == friendsLeft or yourRight == friendsRight)
I wonder if its equivalent to
def areEquallyStrong(yourLeft, yourRight, friendsLeft, friendsRight):
return {yourLeft, yourRight} == {friendsLeft, friendsRight}
I don't precisely know what the {} == {} is doing under the hood and how it's being compared.
Using the builtin type function is useful here:
>>> type({})
<class 'dict'>
>>> type({1, 2})
<class 'set'>
We can conclude that {} in your case is not a dictionary, but a set. A set is an unordered sequence of values, in which each element is unique (if you do print({2, 2}) the output will be {2}). {1, 2} == {1, 2} does a set comparison. Basically, it checks if the two sets were the same if they were ordered.
But, the two code snippets won't give the same result, because, in the first you are checking if both yourLeft and yourRight equal one of friendsLeft and friendsRight, and in the second you aren't. You would be better off with putting friendsLeft and friendsRight in a list and checking if both yourLeft and yourRight are present in that list:
def areEquallyStrong(yourLeft, yourRight, friendsLeft, friendsRight):
return yourLeft in [friendsLeft, friendsRight] and yourRight in [friendsLeft, friendsRight]
In python, {item1, item2} creates a set. A set object is an unordered collection of distinct objects. Duplicated items will be removed when creating a set or adding items to a set.
Equivalence comparison between two sets yields True if they contains exactly the same elements.
You can try it like:
>>> s1 = {1, 2, 3, 1}
>>> s2 = {3, 2, 1}
>>> s1
{1, 2, 3}
>>> s2
{1, 2, 3}
>>> s1 == s2
True
Notes:
To be precise, the objects in a set must be hashable.
While s = {item1, item2} creates a set, s = {} does not create an empty set. Instead, it creates an empty dict. To create an empty set, use s = set().
{} == {} is a set comparison. Python’s built-in set type are unordered and unique. Two sets are equal if and only if every element of each set is contained in the other
you can use max and min to check these
def areEquallyStrong(yourLeft, yourRight, friendsLeft, friendsRight):
if max(yourLeft,yourRight) == max(friendsLeft,friendsRight) and
min(yourLeft,yourRight) == min(friendsLeft,friendsRight):
return True
else:
return False
Why can't I do the below thing :
a = (1,2,3)
dict[a] = 'hi'
TypeError: 'type' object does not support item assignment
It can be. The problem is you're trying to access an item in the dict type itself.
>>> a = (1,2,3)
>>> d = {}
>>> d[a] = "hi"
>>> d
{(1, 2, 3): 'hi'}
As #mgilson put it in a comment: "Tuples can be hashed as long as all of their elements can be hashed."
(Note that you should never name your dictionaries dict, or lists list, etc. This shadows the built-in name, and they're often handy to have around, e.g. dict(zip(keys, values)).)
You can use a tuple as a key (as long as all of its items are hashable):
>>> a = (1,2,3)
>>> b = {a:'hi'}
>>> b[(1,2,3)]
'hi'
>>>
Your problem is that you are trying to index the built-in function dict:
>>> dict
<type 'dict'>
>>>
dict is a type. You want to make an instance of that type.
d = {}
a = (1, 2, 3)
d[a] = 'hi'
Instead of this:
a = {"foo": None, "bar": None}
Is there a way to write this?
b = {"foo", "bar"}
And still let b have constant time access (i.e. not a Python set, which cannot be keyed into)?
Actually, in Python 2.7 and 3.2+, this really does work:
>>> b = {"foo", "bar"}
>>> b
set(['foo', 'bar'])
You can't use [] access on a set ("key into"), but you can test for inclusion:
>>> 'x' in b
False
>>> 'foo' in b
True
Sets are as close to value-less dictionaries as it gets. They have average-case constant-time access, require hashable objects (i.e. no storing lists or dicts in sets), and even support their own comprehension syntax:
{x**2 for x in xrange(100)}
Yes, sets:
set() -> new empty set object
set(iterable) -> new set object
Build an unordered collection of unique elements.
Related: How is set() implemented?
Time complexity : https://wiki.python.org/moin/TimeComplexity#set
In order to "key" into a set in constant time use in:
>>> s = set(['foo', 'bar', 'baz'])
>>> 'foo' in s
True
>>> 'fork' in s
False
This may be a simple question, but I'm having trouble making a unique search for it.
I have a class that defines a static dictionary, then attempts to define a subset of that dictionary, also statically.
So, as a toy example:
class example(object):
first_d = {1:1,2:2,3:3,4:4}
second_d = dict((k,first_d[k]) for k in (2,3))
This produces NameError: global name 'first_d' is not defined
How should I be making this reference? It seems this pattern works in other cases, eg:
class example2(object):
first = 1
second = first + 1
A basic list comprehension has the following syntax
[expression for var in iterable]
When a list comprehension occurs inside a class, the attributes of the class
can be used in iterable. This is true in Python2 and Python3.
However, the attributes of the class can be used (i.e. accessed) in expression in Python2 but not in Python3.
The story is a bit different for generator expressions:
(expression for var in iterable)
While the class attributes can still be accessed from iterable, the class attributes are not accessible from expression. (This is true for Python2 and Python3).
This can all be summarized as follows:
Python2 Python3
Can access class attributes
--------------------------------------------------
list comp. iterable Y Y
list comp. expression Y N
gen expr. iterable Y Y
gen expr. expression N N
dict comp. iterable Y Y
dict comp. expression N N
(Dict comprehensions behave the same as generator expressions in this respect.)
Now how does this relate to your question:
In your example,
second_d = dict((k,first_d[k]) for k in (2,3))
a NameError occurs because first_d is not accessible from the expression part of a generator expression.
A workaround for Python2 would be to change the generator expression to a list comprehension:
second_d = dict([(k,first_d[k]) for k in (2,3)])
However, I don't find this a very comfortable solution since this code will fail in Python3.
You could do as Joel Cornett suggests:
second_d = {k: v for k, v in first_d.items() if k in (2, 3)}
since this uses first_d in the iterable rather than the expression part of the dict comprehension. But this may loop through many more items than necessary if first_d contains many items. Neverthess, this solution might be just fine if first_d is small.
In general, you can avoid this problem by defining a helper function which can be defined inside or outside the class:
def partial_dict(dct, keys):
return {k:dct[k] for k in keys}
class Example(object):
first_d = {1:1,2:2,3:3,4:4}
second_d = partial_dict(first_d, (2,3))
class Example2(object):
a = [1,2,3,4,5]
b = [2,4]
def myfunc(A, B):
return [x for x in A if x not in B]
c = myfunc(a, b)
print(Example().second_d)
# {2: 2, 3: 3}
print(Example2().c)
# [1, 3, 5]
Functions work because they define a local scope and
variables in this local scope can be accessed from within the dict comprehension.
This was explained here, but I am not entirely comfortable with this since it does not explain why the expression part behaves differently than the iterable part of a list comprehension, generator expression or dict comprehension.
Thus I can not explain (completely) why Python behaves this way, only that this is the way it appears to behave.
It's a bit kludgy, but you could try this:
class test(object):
pass
test.first = {1:1, 2:2, 3:3, 4:4}
test.second = dict((k, test.first[k]) for k in (2,3))
...and then:
>>> test.first
{1: 1, 2: 2, 3: 3, 4: 4}
>>> test.second
{2: 2, 3: 3}
>>> t = test()
>>> t.first
{1: 1, 2: 2, 3: 3, 4: 4}
>>> t.second
{2: 2, 3: 3}
>>> test.first[5] = 5
>>> t.first
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5}
I don't think the class exists until you get to the end of its definition.
To define a singleton in python use singleton = ('singleton'),
A Python dictionary can use a tuple as a key, as in
[('one', 'two'): 5]
But is it possible to do
[('singleton'),: 5]
Somehow?
Yes, you can do this — but not with ('Singleton'). You've got to use ('Singleton',).
The reason for this is that Python will interpret single parentheses around a single item as merely the item itself. Adding a comma enforces the tuple interpretation.
>>> d = {}
>>> d[('Thing')] = "one"
>>> d.keys()
['Thing']
>>> d[('Thing',)] = "another"
>>> d
{'Thing': 'one', ('Thing',): 'another'}
Signify to python that 'singleton' is a tuple to make it work:
>>> a = {}
>>> a[('singleton',)] = 5
>>> a
{('singleton',): 5}