Qual é a diferença entre dict () e {}?
-
21-08-2019 - |
Pergunta
Então, digamos que eu quero fazer um dicionário. Vamos chamá-lo d
. Mas existem várias maneiras de inicializar um dicionário em Python! Por exemplo, eu poderia fazer isso:
d = {'hash': 'bang', 'slash': 'dot'}
Ou eu poderia fazer isso:
d = dict(hash='bang', slash='dot')
Ou este, curiosamente:
d = dict({'hash': 'bang', 'slash': 'dot'})
Ou este:
d = dict([['hash', 'bang'], ['slash', 'dot']])
E toda uma outra infinidade de maneiras com a função dict()
. Então, obviamente, uma das coisas dict()
fornece flexibilidade na sintaxe e de inicialização. Mas isso não é o que eu estou perguntando.
Say eu fosse fazer d
apenas um dicionário vazio. O que se passa nos bastidores do interpretador Python quando eu faço d = {}
contra d = dict()
? É simplesmente duas maneiras de fazer a mesma coisa? Será que usando {}
ter o adicional Chamada de dict()
? Um tem (mesmo insignificante) mais sobrecarga do que o outro? Enquanto a questão é realmente completamente sem importância, é uma curiosidade que eu gostaria de ter respondido.
Solução
>>> 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 () é, aparentemente, alguns C embutido. Uma pessoa realmente inteligente ou dedicado (não eu) poderia olhar para a fonte intérprete e lhe dizer mais. Eu só queria mostrar dis.dis. :)
Outras dicas
Tanto quanto o desempenho vai:
>>> from timeit import timeit
>>> timeit("a = {'a': 1, 'b': 2}")
0.424...
>>> timeit("a = dict(a = 1, b = 2)")
0.889...
@Jacob: Há uma diferença na forma como os objetos são alocados, mas eles não são copy-on-write. Python aloca um tamanho fixo "lista livre", onde ele pode rapidamente alocar dicionário objetos (até encher). Dicionários alocados via a sintaxe {}
(ou uma chamada C para PyDict_New
) pode vir a partir desta lista livre. Quando o dicionário não é referenciado ele é retornado para a lista livre e que um bloco de memória pode ser reutilizado (embora os campos são repostos em primeiro lugar).
Este primeiro dicionário é imediatamente voltou para a lista livre, e o próximo será reutilizar seu espaço de memória:
>>> id({})
340160
>>> id({1: 2})
340160
Se você manter uma referência, o próximo dicionário virá a partir do próximo slot livre:
>>> x = {}
>>> id(x)
340160
>>> id({})
340016
Mas podemos excluir a referência a esse dicionário e libertar seu slot novamente:
>>> del x
>>> id({})
340160
Uma vez que a sintaxe {}
é tratado em byte-code ele pode usar essa otimização mencionada acima. Por outro lado dict()
é tratado como um construtor de classe regular e Python usa o alocador de memória genérica, que não segue um padrão facilmente previsível como o livre lista acima.
Além disso, olhando para compile.c do Python 2.6, com a sintaxe {}
parece pré-size o hashtable com base no número de itens que ele está armazenando que é conhecido no momento da análise.
Basicamente, {} é sintaxe e é tratado em um nível de linguagem e bytecode. dict () é apenas mais um builtin com uma sintaxe de inicialização mais flexível. Note-se que dict () só foi adicionado no meio de 2.x série.
Atualização : obrigado pelas respostas. especulação removido cerca de copy-on-write.
Uma outra diferença entre {}
e dict
é que dict
sempre aloca um novo dicionário (mesmo se o conteúdo estático), enquanto {}
não sempre o fazer (ver mgood's para quando e porquê):
def dict1():
return {'a':'b'}
def dict2():
return dict(a='b')
print id(dict1()), id(dict1())
print id(dict2()), id(dict2())
produz:
$ ./mumble.py 11642752 11642752 11867168 11867456
Eu não estou sugerindo que você tentar tirar proveito disso ou não, depende da situação particular, apenas apontando para fora. (Também é provavelmente evidente a partir do desmontagem se você entender a opcodes).
dict () é usado quando você quer criar um dicionário de uma iterable, como:
dict( generator which yields (key,value) pairs )
dict( list of (key,value) pairs )
Uso engraçado:
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)
saída:
I want to be printed
a
A fim de criar um conjunto vazio, devemos usar a palavra-chave set antes que ele
ou seja set()
isso cria um conjunto vazio onde, como em dicts apenas os suportes de flores pode criar um dict vazio
Lets Go com um exemplo
print isinstance({},dict)
True
print isinstance({},set)
False
print isinstance(set(),set)
True