What's the difference between dict() and {}? - python

So let's say I wanna make a dictionary. We'll call it d. But there are multiple ways to initialize a dictionary in Python! For example, I could do this:
d = {'hash': 'bang', 'slash': 'dot'}
Or I could do this:
d = dict(hash='bang', slash='dot')
Or this, curiously:
d = dict({'hash': 'bang', 'slash': 'dot'})
Or this:
d = dict([['hash', 'bang'], ['slash', 'dot']])
And a whole other multitude of ways with the dict() function. So obviously one of the things dict() provides is flexibility in syntax and initialization. But that's not what I'm asking about.
Say I were to make d just an empty dictionary. What goes on behind the scenes of the Python interpreter when I do d = {} versus d = dict()? Is it simply two ways to do the same thing? Does using {} have the additional call of dict()? Does one have (even negligible) more overhead than the other? While the question is really completely unimportant, it's a curiosity I would love to have answered.

>>> def f():
... return {'a' : 1, 'b' : 2}
...
>>> def g():
... return dict(a=1, b=2)
...
>>> g()
{'a': 1, 'b': 2}
>>> f()
{'a': 1, 'b': 2}
>>> import dis
>>> dis.dis(f)
2 0 BUILD_MAP 0
3 DUP_TOP
4 LOAD_CONST 1 ('a')
7 LOAD_CONST 2 (1)
10 ROT_THREE
11 STORE_SUBSCR
12 DUP_TOP
13 LOAD_CONST 3 ('b')
16 LOAD_CONST 4 (2)
19 ROT_THREE
20 STORE_SUBSCR
21 RETURN_VALUE
>>> dis.dis(g)
2 0 LOAD_GLOBAL 0 (dict)
3 LOAD_CONST 1 ('a')
6 LOAD_CONST 2 (1)
9 LOAD_CONST 3 ('b')
12 LOAD_CONST 4 (2)
15 CALL_FUNCTION 512
18 RETURN_VALUE
dict() is apparently some C built-in. A really smart or dedicated person (not me) could look at the interpreter source and tell you more. I just wanted to show off dis.dis. :)

As far as performance goes:
>>> from timeit import timeit
>>> timeit("a = {'a': 1, 'b': 2}")
0.424...
>>> timeit("a = dict(a = 1, b = 2)")
0.889...

#Jacob: There is a difference in how the objects are allocated, but they are not copy-on-write. Python allocates a fixed-size "free list" where it can quickly allocate dictionary objects (until it fills). Dictionaries allocated via the {} syntax (or a C call to PyDict_New) can come from this free list. When the dictionary is no longer referenced it gets returned to the free list and that memory block can be reused (though the fields are reset first).
This first dictionary gets immediately returned to the free list, and the next will reuse its memory space:
>>> id({})
340160
>>> id({1: 2})
340160
If you keep a reference, the next dictionary will come from the next free slot:
>>> x = {}
>>> id(x)
340160
>>> id({})
340016
But we can delete the reference to that dictionary and free its slot again:
>>> del x
>>> id({})
340160
Since the {} syntax is handled in byte-code it can use this optimization mentioned above. On the other hand dict() is handled like a regular class constructor and Python uses the generic memory allocator, which does not follow an easily predictable pattern like the free list above.
Also, looking at compile.c from Python 2.6, with the {} syntax it seems to pre-size the hashtable based on the number of items it's storing which is known at parse time.

Basically, {} is syntax and is handled on a language and bytecode level. dict() is just another builtin with a more flexible initialization syntax. Note that dict() was only added in the middle of 2.x series.

Update: thanks for the responses. Removed speculation about copy-on-write.
One other difference between {} and dict is that dict always allocates a new dictionary (even if the contents are static) whereas {} doesn't always do so (see mgood's answer for when and why):
def dict1():
return {'a':'b'}
def dict2():
return dict(a='b')
print id(dict1()), id(dict1())
print id(dict2()), id(dict2())
produces:
$ ./mumble.py
11642752 11642752
11867168 11867456
I'm not suggesting you try to take advantage of this or not, it depends on the particular situation, just pointing it out. (It's also probably evident from the disassembly if you understand the opcodes).

dict() is used when you want to create a dictionary from an iterable, like :
dict( generator which yields (key,value) pairs )
dict( list of (key,value) pairs )

Funny usage:
def func(**kwargs):
for e in kwargs:
print(e)
a = 'I want to be printed'
kwargs={a:True}
func(**kwargs)
a = 'I dont want to be printed'
kwargs=dict(a=True)
func(**kwargs)
output:
I want to be printed
a

In order to create an empty set we should use the keyword set before it
i.e set() this creates an empty set where as in dicts only the flower brackets can create an empty dict
Lets go with an example
print isinstance({},dict)
True
print isinstance({},set)
False
print isinstance(set(),set)
True

Related

Checking if JSON object exists [duplicate]

This question's answers are a community effort. Edit existing answers to improve this post. It is not currently accepting new answers or interactions.
I wanted to test if a key exists in a dictionary before updating the value for the key.
I wrote the following code:
if 'key1' in dict.keys():
print "blah"
else:
print "boo"
I think this is not the best way to accomplish this task. Is there a better way to test for a key in the dictionary?
in tests for the existence of a key in a dict:
d = {"key1": 10, "key2": 23}
if "key1" in d:
print("this will execute")
if "nonexistent key" in d:
print("this will not")
Use dict.get() to provide a default value when the key does not exist:
d = {}
for i in range(10):
d[i] = d.get(i, 0) + 1
To provide a default value for every key, either use dict.setdefault() on each assignment:
d = {}
for i in range(10):
d[i] = d.setdefault(i, 0) + 1
or use defaultdict from the collections module:
from collections import defaultdict
d = defaultdict(int)
for i in range(10):
d[i] += 1
Use key in my_dict directly instead of key in my_dict.keys():
if 'key1' in my_dict:
print("blah")
else:
print("boo")
That will be much faster as it uses the dictionary's O(1) hashing as opposed to doing an O(n) linear search on a list of keys.
You can test for the presence of a key in a dictionary, using the in keyword:
d = {'a': 1, 'b': 2}
'a' in d # <== evaluates to True
'c' in d # <== evaluates to False
A common use for checking the existence of a key in a dictionary before mutating it is to default-initialize the value (e.g. if your values are lists, for example, and you want to ensure that there is an empty list to which you can append when inserting the first value for a key). In cases such as those, you may find the collections.defaultdict() type to be of interest.
In older code, you may also find some uses of has_key(), a deprecated method for checking the existence of keys in dictionaries (just use key_name in dict_name, instead).
You can shorten your code to this:
if 'key1' in my_dict:
...
However, this is at best a cosmetic improvement. Why do you believe this is not the best way?
For additional information on speed execution of the accepted answer's proposed methods (10 million loops):
'key' in mydict elapsed time 1.07 seconds
mydict.get('key') elapsed time 1.84 seconds
mydefaultdict['key'] elapsed time 1.07 seconds
Therefore using in or defaultdict are recommended against get.
I would recommend using the setdefault method instead. It sounds like it will do everything you want.
>>> d = {'foo':'bar'}
>>> q = d.setdefault('foo','baz') #Do not override the existing key
>>> print q #The value takes what was originally in the dictionary
bar
>>> print d
{'foo': 'bar'}
>>> r = d.setdefault('baz',18) #baz was never in the dictionary
>>> print r #Now r has the value supplied above
18
>>> print d #The dictionary's been updated
{'foo': 'bar', 'baz': 18}
A dictionary in Python has a get('key', default) method. So you can just set a default value in case there isn't any key.
values = {...}
myValue = values.get('Key', None)
Using the Python ternary operator:
message = "blah" if 'key1' in my_dict else "booh"
print(message)
Use EAFP (easier to ask forgiveness than permission):
try:
blah = dict["mykey"]
# key exists in dict
except KeyError:
# key doesn't exist in dict
See other Stack Overflow posts:
Using 'try' vs. 'if' in Python
Checking for member existence in Python
Check if a given key already exists in a dictionary
To get the idea how to do that we first inspect what methods we can call on dictionary.
Here are the methods:
d={'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}
Python Dictionary clear() Removes all Items
Python Dictionary copy() Returns Shallow Copy of a Dictionary
Python Dictionary fromkeys() Creates dictionary from given sequence
Python Dictionary get() Returns Value of The Key
Python Dictionary items() Returns view of dictionary (key, value) pair
Python Dictionary keys() Returns View Object of All Keys
Python Dictionary pop() Removes and returns element having given key
Python Dictionary popitem() Returns & Removes Element From Dictionary
Python Dictionary setdefault() Inserts Key With a Value if Key is not Present
Python Dictionary update() Updates the Dictionary
Python Dictionary values() Returns view of all values in dictionary
The brutal method to check if the key already exists may be the get() method:
d.get("key")
The other two interesting methods items() and keys() sounds like too much of work. So let's examine if get() is the right method for us. We have our dict d:
d= {'clear':0, 'copy':1, 'fromkeys':2, 'get':3, 'items':4, 'keys':5, 'pop':6, 'popitem':7, 'setdefault':8, 'update':9, 'values':10}
Printing shows the key we don't have will return None:
print(d.get('key')) #None
print(d.get('clear')) #0
print(d.get('copy')) #1
We use that to get the information if the key is present or no.
But consider this if we create a dict with a single key:None:
d= {'key':None}
print(d.get('key')) #None
print(d.get('key2')) #None
Leading that get() method is not reliable in case some values may be None.
This story should have a happier ending. If we use the in comparator:
print('key' in d) #True
print('key2' in d) #False
We get the correct results.
We may examine the Python byte code:
import dis
dis.dis("'key' in d")
# 1 0 LOAD_CONST 0 ('key')
# 2 LOAD_NAME 0 (d)
# 4 COMPARE_OP 6 (in)
# 6 RETURN_VALUE
dis.dis("d.get('key2')")
# 1 0 LOAD_NAME 0 (d)
# 2 LOAD_METHOD 1 (get)
# 4 LOAD_CONST 0 ('key2')
# 6 CALL_METHOD 1
# 8 RETURN_VALUE
This shows that in compare operator is not just more reliable, but even faster than get().
The ways in which you can get the results are:
if your_dict.has_key(key) Removed in Python 3
if key in your_dict
try/except block
Which is better is dependent on 3 things:
Does the dictionary 'normally has the key' or 'normally does not have the key'.
Do you intend to use conditions like if...else...elseif...else?
How big is dictionary?
Read More: http://paltman.com/try-except-performance-in-python-a-simple-test/
Use of try/block instead of 'in' or 'if':
try:
my_dict_of_items[key_i_want_to_check]
except KeyError:
# Do the operation you wanted to do for "key not present in dict".
else:
# Do the operation you wanted to do with "key present in dict."
Python 2 only: (and Python 2.7 supports `in` already)
You can use the has_key() method:
if dict.has_key('xyz')==1:
# Update the value for the key
else:
pass
Just an FYI adding to Chris. B's (best) answer:
d = defaultdict(int)
Works as well; the reason is that calling int() returns 0 which is what defaultdict does behind the scenes (when constructing a dictionary), hence the name "Factory Function" in the documentation.
A Python dictionary has the method called __contains__. This method will return True if the dictionary has the key, else it returns False.
>>> temp = {}
>>> help(temp.__contains__)
Help on built-in function __contains__:
__contains__(key, /) method of builtins.dict instance
True if D has a key k, else False.
Another way of checking if a key exists using Boolean operators:
d = {'a': 1, 'b':2}
keys = 'abcd'
for k in keys:
x = (k in d and 'blah') or 'boo'
print(x)
This returns
>>> blah
>>> blah
>>> boo
>>> boo
Explanation
First, you should know that in Python, 0, None, or objects with zero length evaluate to False. Everything else evaluates to True. Boolean operations are evaluated left to right and return the operand not True or False.
Let's see an example:
>>> 'Some string' or 1/0
'Some string'
>>>
Since 'Some string' evaluates to True, the rest of the or is not evaluated and there is no division by zero error raised.
But if we switch the order 1/0 is evaluated first and raises an exception:
>>> 1/0 or 'Some string'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>>
We can use this for pattern for checking if a key exists.
(k in d and 'blah')
does the same as
if k in d:
'blah'
else:
False
This already returns the correct result if the key exists, but we want it to print 'boo' when it doesn't. So, we take the result and or it with 'boo'
>>> False or 'boo'
'boo'
>>> 'blah' or 'boo'
'blah'
>>>
You can use a for loop to iterate over the dictionary and get the name of key you want to find in the dictionary. After that, check if it exist or not using if condition:
dic = {'first' : 12, 'second' : 123}
for each in dic:
if each == 'second':
print('the key exists and the corresponding value can be updated in the dictionary')

Python mutable and immutable [duplicate]

I'm a bit confused about modifying tuple members. The following doesn't work:
>>> thing = (['a'],)
>>> thing[0] = ['b']
TypeError: 'tuple' object does not support item assignment
>>> thing
(['a'],)
But this does work:
>>> thing[0][0] = 'b'
>>> thing
(['b'],)
Also works:
>>> thing[0].append('c')
>>> thing
(['b', 'c'],)
Doesn't work, and works (huh?!):
>>> thing[0] += 'd'
TypeError: 'tuple' object does not support item assignment
>>> thing
(['b', 'c', 'd'],)
Seemingly equivalent to previous, but works:
>>> e = thing[0]
>>> e += 'e'
>>> thing
(['b', 'c', 'd', 'e'],)
So what exactly are the rules of the game, when you can and can't modify something inside a tuple? It seems to be more like prohibition of using the assignment operator for tuple members, but the last two cases are confusing me.
You can always modify a mutable value inside a tuple. The puzzling behavior you see with
>>> thing[0] += 'd'
is caused by +=. The += operator does in-place addition but also an assignment — the in-place addition works just file, but the assignment fails since the tuple is immutable. Thinking of it like
>>> thing[0] = thing[0] + 'd'
explains this better. We can use the dis module from the standard library to look at the bytecode generated from both expressions. With += we get an INPLACE_ADD bytecode:
>>> def f(some_list):
... some_list += ["foo"]
...
>>> dis.dis(f)
2 0 LOAD_FAST 0 (some_list)
3 LOAD_CONST 1 ('foo')
6 BUILD_LIST 1
9 INPLACE_ADD
10 STORE_FAST 0 (some_list)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
With + we get a BINARY_ADD:
>>> def g(some_list):
... some_list = some_list + ["foo"]
>>> dis.dis(g)
2 0 LOAD_FAST 0 (some_list)
3 LOAD_CONST 1 ('foo')
6 BUILD_LIST 1
9 BINARY_ADD
10 STORE_FAST 0 (some_list)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
Notice that we get a STORE_FAST in both places. This is the bytecode that fails when you try to store back into a tuple — the INPLACE_ADD that comes just before works fine.
This explains why the "Doesn't work, and works" case leaves the modified list behind: the tuple already has a reference to the list:
>>> id(thing[0])
3074072428L
The list is then modified by the INPLACE_ADD and the STORE_FAST fails:
>>> thing[0] += 'd'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
So the tuple still has a reference to the same list, but the list has been modified in-place:
>>> id(thing[0])
3074072428L
>>> thing[0]
['b', 'c', 'd']
You can't modify the tuple, but you can modify the contents of things contained within the tuple. Lists (along with sets, dicts, and objects) are a reference type and thus the "thing" in the tuple is just a reference - the actual list is a mutable object which is pointed to by that reference and can be modified without changing the reference itself.
( + ,) <--- your tuple (this can't be changed)
|
|
v
['a'] <--- the list object your tuple references (this can be changed)
After thing[0][0] = 'b':
( + ,) <--- notice how the contents of this are still the same
|
|
v
['b'] <--- but the contents of this have changed
After thing[0].append('c'):
( + ,) <--- notice how this is still the same
|
|
v
['b','c'] <--- but this has changed again
The reason why += errors is that it's not completely equivalent to .append() - it actually does an addition and then an assignment (and the assignment fails), rather than merely appending in-place.
You cannot replace an element of a tuple, but you can replace the entire contents of the element. This will work:
thing[0][:] = ['b']

a mutable type inside an immutable container

I'm a bit confused about modifying tuple members. The following doesn't work:
>>> thing = (['a'],)
>>> thing[0] = ['b']
TypeError: 'tuple' object does not support item assignment
>>> thing
(['a'],)
But this does work:
>>> thing[0][0] = 'b'
>>> thing
(['b'],)
Also works:
>>> thing[0].append('c')
>>> thing
(['b', 'c'],)
Doesn't work, and works (huh?!):
>>> thing[0] += 'd'
TypeError: 'tuple' object does not support item assignment
>>> thing
(['b', 'c', 'd'],)
Seemingly equivalent to previous, but works:
>>> e = thing[0]
>>> e += 'e'
>>> thing
(['b', 'c', 'd', 'e'],)
So what exactly are the rules of the game, when you can and can't modify something inside a tuple? It seems to be more like prohibition of using the assignment operator for tuple members, but the last two cases are confusing me.
You can always modify a mutable value inside a tuple. The puzzling behavior you see with
>>> thing[0] += 'd'
is caused by +=. The += operator does in-place addition but also an assignment — the in-place addition works just file, but the assignment fails since the tuple is immutable. Thinking of it like
>>> thing[0] = thing[0] + 'd'
explains this better. We can use the dis module from the standard library to look at the bytecode generated from both expressions. With += we get an INPLACE_ADD bytecode:
>>> def f(some_list):
... some_list += ["foo"]
...
>>> dis.dis(f)
2 0 LOAD_FAST 0 (some_list)
3 LOAD_CONST 1 ('foo')
6 BUILD_LIST 1
9 INPLACE_ADD
10 STORE_FAST 0 (some_list)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
With + we get a BINARY_ADD:
>>> def g(some_list):
... some_list = some_list + ["foo"]
>>> dis.dis(g)
2 0 LOAD_FAST 0 (some_list)
3 LOAD_CONST 1 ('foo')
6 BUILD_LIST 1
9 BINARY_ADD
10 STORE_FAST 0 (some_list)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
Notice that we get a STORE_FAST in both places. This is the bytecode that fails when you try to store back into a tuple — the INPLACE_ADD that comes just before works fine.
This explains why the "Doesn't work, and works" case leaves the modified list behind: the tuple already has a reference to the list:
>>> id(thing[0])
3074072428L
The list is then modified by the INPLACE_ADD and the STORE_FAST fails:
>>> thing[0] += 'd'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
So the tuple still has a reference to the same list, but the list has been modified in-place:
>>> id(thing[0])
3074072428L
>>> thing[0]
['b', 'c', 'd']
You can't modify the tuple, but you can modify the contents of things contained within the tuple. Lists (along with sets, dicts, and objects) are a reference type and thus the "thing" in the tuple is just a reference - the actual list is a mutable object which is pointed to by that reference and can be modified without changing the reference itself.
( + ,) <--- your tuple (this can't be changed)
|
|
v
['a'] <--- the list object your tuple references (this can be changed)
After thing[0][0] = 'b':
( + ,) <--- notice how the contents of this are still the same
|
|
v
['b'] <--- but the contents of this have changed
After thing[0].append('c'):
( + ,) <--- notice how this is still the same
|
|
v
['b','c'] <--- but this has changed again
The reason why += errors is that it's not completely equivalent to .append() - it actually does an addition and then an assignment (and the assignment fails), rather than merely appending in-place.
You cannot replace an element of a tuple, but you can replace the entire contents of the element. This will work:
thing[0][:] = ['b']

Is there a difference between using a dict literal and a dict constructor?

Using PyCharm, I noticed it offers to convert a dict literal:
d = {
'one': '1',
'two': '2',
}
into a dict constructor:
d = dict(one='1', two='2')
Do these different approaches differ in some significant way?
(While writing this question I noticed that using dict() it seems impossible to specify a numeric key .. d = {1: 'one', 2: 'two'} is possible, but, obviously, dict(1='one' ...) is not. Anything else?)
I think you have pointed out the most obvious difference. Apart from that,
the first doesn't need to lookup dict which should make it a tiny bit faster
the second looks up dict in locals() and then globals() and the finds the builtin, so you can switch the behaviour by defining a local called dict for example although I can't think of anywhere this would be a good idea apart from maybe when debugging
Literal is much faster, since it uses optimized BUILD_MAP and STORE_MAP opcodes rather than generic CALL_FUNCTION:
> python2.7 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.958 usec per loop
> python2.7 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.479 usec per loop
> python3.2 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.975 usec per loop
> python3.2 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.409 usec per loop
They look pretty much the same on Python 3.2.
As gnibbler pointed out, the first doesn't need to lookup dict, which should make it a tiny bit faster.
>>> def literal():
... d = {'one': 1, 'two': 2}
...
>>> def constructor():
... d = dict(one='1', two='2')
...
>>> import dis
>>> dis.dis(literal)
2 0 BUILD_MAP 2
3 LOAD_CONST 1 (1)
6 LOAD_CONST 2 ('one')
9 STORE_MAP
10 LOAD_CONST 3 (2)
13 LOAD_CONST 4 ('two')
16 STORE_MAP
17 STORE_FAST 0 (d)
20 LOAD_CONST 0 (None)
23 RETURN_VALUE
>>> dis.dis(constructor)
2 0 LOAD_GLOBAL 0 (dict)
3 LOAD_CONST 1 ('one')
6 LOAD_CONST 2 ('1')
9 LOAD_CONST 3 ('two')
12 LOAD_CONST 4 ('2')
15 CALL_FUNCTION 512
18 STORE_FAST 0 (d)
21 LOAD_CONST 0 (None)
24 RETURN_VALUE
These two approaches produce identical dictionaries, except, as you've noted, where the lexical rules of Python interfere.
Dictionary literals are a little more obviously dictionaries, and you can create any kind of key, but you need to quote the key names. On the other hand, you can use variables for keys if you need to for some reason:
a = "hello"
d = {
a: 'hi'
}
The dict() constructor gives you more flexibility because of the variety of forms of input it takes. For example, you can provide it with an iterator of pairs, and it will treat them as key/value pairs.
I have no idea why PyCharm would offer to convert one form to the other.
One big difference with python 3.4 + pycharm is that the dict() constructor
produces a "syntax error" message if the number of keys exceeds 256.
I prefer using the dict literal now.
From python 2.7 tutorial:
A pair of braces creates an empty
dictionary: {}. Placing a
comma-separated list of key:value
pairs within the braces adds initial
key:value pairs to the dictionary;
this is also the way dictionaries are
written on output.
tel = {'jack': 4098, 'sape': 4139}
data = {k:v for k,v in zip(xrange(10), xrange(10,20))}
While:
The dict() constructor builds
dictionaries directly from lists of
key-value pairs stored as tuples. When
the pairs form a pattern, list
comprehensions can compactly specify
the key-value list.
tel = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) {'sape': 4139, 'jack': 4098, 'guido': 4127}
data = dict((k,v) for k,v in zip(xrange(10), xrange(10,20)))
When the keys are simple strings, it
is sometimes easier to specify pairs
using keyword arguments:
dict(sape=4139, guido=4127, jack=4098)
>>> {'sape': 4139, 'jack':4098, 'guido': 4127}
So both {} and dict() produce dictionary but provide a bit different ways of dictionary data initialization.
I find the dict literal d = {'one': '1'} to be much more readable, your defining data, rather than assigning things values and sending them to the dict() constructor.
On the other hand i have seen people mistype the dict literal as d = {'one', '1'} which in modern python 2.7+ will create a set.
Despite this i still prefer to all-ways use the set literal because i think its more readable, personal preference i suppose.
the dict() literal is nice when you are copy pasting values from something else (none python)
For example a list of environment variables.
if you had a bash file, say
FOO='bar'
CABBAGE='good'
you can easily paste then into a dict() literal and add comments. It also makes it easier to do the opposite, copy into something else. Whereas the {'FOO': 'bar'} syntax is pretty unique to python and json. So if you use json a lot, you might want to use {} literals with double quotes.
There is no dict literal to create dict-inherited classes, custom dict classes with additional methods. In such case custom dict class constructor should be used, for example:
class NestedDict(dict):
# ... skipped
state_type_map = NestedDict(**{
'owns': 'Another',
'uses': 'Another',
})
Super late to the party here, but if you have a kwargs function:
def foo(a=None, b=None):
...
And your splatting a dict like so:
d_1 = { 'a': 1, 'b': 2 }
d_2 = dict(a=1, b=2)
# This works
foo(**d_1)
# And this as well
foo(**d_2)
But d_2 may be better suited for refactoring argument names that may change in your foo signature. Since in d_1 they are strings.
Also, when it comes to reading code (which is a lot), I feel that the literal has less cognitive burden (because we associate literals to be something that is less "active" than say a dict() which looks like a function call which makes the brain wonder...at least for a micro second :)) compared to dict(), admittedly partly due to the syntax highlighting in the editor, but still very relevant on a daily basis (at least for me).
If I focus on the surrounding code around the dict statement represented as ..., a literal dict makes it a bit easier for me to understand the surrounding code :).
...
...
...
config = {
'key1':"value1",
'key2':"value2",
'key3':"value3",
'key4':"value4",
}
...
...
...
#****VS *****
...
...
...
config =dict(
key1 = 'value1',
key2 = 'value2',
key3 = 'value3',
key4 = 'value4',
)
...
...
...
Also consider the fact that tokens that match for operators can't be used in the constructor syntax, i.e. dasherized keys.
>>> dict(foo-bar=1)
File "<stdin>", line 1
SyntaxError: keyword can't be an expression
>>> {'foo-bar': 1}
{'foo-bar': 1}

Creating a list in Python- something sneaky going on?

Apologies if this doesn't make any sense, I'm very new to Python!
From testing in an interpreter, I can see that list() and [] both produce an empty list:
>>> list()
[]
>>> []
[]
From what I've learned so far, the only way to create an object is to call its constructor (__init__), but I don't see this happening when I just type []. So by executing [], is Python then mapping that to a call to list()?
Those two constructs are handled quite differently:
>>> import dis
>>> def f(): return []
...
>>> dis.dis(f)
1 0 BUILD_LIST 0
3 RETURN_VALUE
>>> def f(): return list()
...
>>> dis.dis(f)
1 0 LOAD_GLOBAL 0 (list)
3 CALL_FUNCTION 0
6 RETURN_VALUE
>>>
The [] form constructs a list using the opcode BUILD_LIST, whereas the list() form calls the list object's constructor.
No, Python does not call list(), or you could affect what type [] creates by assigning to list, which you cant:
>>> import __builtin__
>>> __builtin__.list = set
>>> list()
set([])
>>> []
[]
[] is syntax for creating a list. It's a builtin type and it has special syntax, just like dicts and strings and ints and floats and lots of other types.
Creating instances of types can also be done by calling the type, like list() -- which will in turn call the type's constructor and initializer for you. Calling the initializer (__init__) directly does not create a new instance of the type. Calling the constructor (__new__) does, but you should not be calling it directly.
I started learning python yesterday....
I guess you would have to say its internally mapped
>>> a = []
>>> type(a)
<type 'list'>
>>> a = list()
>>> type(a)
<type 'list'>
What are the key differences between using list() and []?
The most obvious and visible key difference between list() and [] is the syntax. Putting the syntax aside for a minute here, someone whose new or intermediately exposed to python might argue that they’re both lists or derive from the same class; that is true. Which furthermore increases the importance of understanding the key differences of both, most of which are outlined below.
list() is a function and [] is literal syntax.
Let’s take a look at what happens when we call list() and [] respectively through the disassembler.
>>> import dis
>>> print(dis.dis(lambda: list()))
1 0 LOAD_GLOBAL 0 (list)
3 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
6 RETURN_VALUE
None
>>> print(dis.dis(lambda: []))
1 0 BUILD_LIST 0
3 RETURN_VALUE
None
The output from the disassembler above shows that the literal syntax version doesn’t require a global lookup, denoted by the op code LOAD_GLOBAL or a function call, denoted by the op code CALL_FUNCTION.
As a result, literal syntax is faster than it’s counterpart. – Let’s take a second and look at the timings below.
import timeit
>>> timeit.timeit('[]', number=10**4)
0.0014592369552701712
>>> timeit.timeit('list()', number=10**4)
0.0033833282068371773
On another note it’s equally important and worth pointing out that literal syntax, [] does not unpack values. An example of unpacking is shown below.
>>> list('abc') # unpacks value
['a', 'b', 'c']
>>> ['abc'] # value remains packed
['abc']
What’s a literal in python?
Literals are notations or a way of writing constant or raw variable values which python recognises as built-in types.
Sourced from my post on PythonRight - what's the difference between list and [].
In addition to the other answers, from the Language Reference:
A list display is a possibly empty series of expressions enclosed in square brackets:
list_display ::= "[" [expression_list | list_comprehension] "]"
...
A list display yields a new list object.
It does not explicitly mention how "yielding a new list object" is implemented. It could well be a call to the list() constructor, like you mentioned. Or maybe lists, being so elementary, get special treatment, and list() is actually mapped to something different entirely.
Either way, [] is certainly not mapped to a call to the constructor of the type named __builtins__.list, because redefining that type still causes [] to return an actual list, as other answerers have shown.
Python, like most programming langauges, has something called literals, meaning that special syntax can be used to write out some of the most important types of values. Very little of this is necessary, but it makes it easier to use Python that we can write literals.
>>> 0
0
>>> int()
0
>>> 5
5
>>> int('5') # I'm using a string literal here though!
5
>>> 0.0
0.0
>>> float()
0.0
>>> ""
''
>>> str()
''
>>> u""
u''
>>> unicode()
u''
>>> ()
()
>>> tuple()
()
>>> {}
{}
>>> dict()
{}
When we make our own types (classes), we create instances of them using their constructors, like list for lists. When we use literals, it's sort of like syntactic sugar for calling list, but in reality it calls that same basic things behind the scene.
Since :
class list(object):
"""
list() -> new empty list
list(iterable) -> new list initialized from iterable's items
"""
If the element in your lists is an iterable (i.e. a str), the list() and [] don't work the same way.
So
>>> a = ['ab']
>>> b = list('ab')
>>> a[0]
'ab'
>>> b[0]
'a'

Categories

Resources