web-dev-qa-db-fra.com

Créer une liste de dictionnaire Python

Je veux obtenir tous les iframe d'une page Web.

Code:

site = "http://" + url
f = urllib2.urlopen(site)
web_content =  f.read()

soup = BeautifulSoup(web_content)
info = {}
content = []
for iframe in soup.find_all('iframe'):
    info['src'] = iframe.get('src')
    info['height'] = iframe.get('height')
    info['width'] = iframe.get('width')
    content.append(info)
    print(info)       

pprint(content)

résultat de print(info):

{'src': u'abc.com', 'width': u'0', 'height': u'0'}
{'src': u'xyz.com', 'width': u'0', 'height': u'0'}
{'src': u'http://www.detik.com', 'width': u'1000', 'height': u'600'}

résultat de pprint(content):

[{'height': u'600', 'src': u'http://www.detik.com', 'width': u'1000'},
{'height': u'600', 'src': u'http://www.detik.com', 'width': u'1000'},
{'height': u'600', 'src': u'http://www.detik.com', 'width': u'1000'}]

Pourquoi la valeur du contenu n'est-elle pas correcte? C'est supposé être identique à la valeur quand I print(info).

27
l1th1um

Vous ne créez pas de dictionnaire distinct pour chaque iframe, vous ne faites que modifier le même dictionnaire, et vous continuez à ajouter des références supplémentaires à ce dictionnaire dans votre liste.

Rappelez-vous que lorsque vous faites quelque chose comme content.append(info), vous ne faites pas de copie des données, vous ajoutez simplement une référence aux données.

Vous devez créer un nouveau dictionnaire pour chaque iframe.

for iframe in soup.find_all('iframe'):
   info = {}
    ...

Mieux encore, vous n'avez pas besoin de créer un dictionnaire vide au préalable. Il suffit de créer le tout à la fois:

for iframe in soup.find_all('iframe'):
    info = {
        "src":    iframe.get('src'),
        "height": iframe.get('height'),
        "width":  iframe.get('width'),
    }
    content.append(info)

Il existe d'autres moyens d'y parvenir, tels que parcourir une liste d'attributs ou d'utiliser des listes de compréhension ou des dictionnaires, mais il est difficile d'améliorer la clarté du code ci-dessus.

54
Bryan Oakley

Vous avez mal compris l'objet Python list. Il ressemble à un C pointer-array. Il ne "copie" pas réellement l'objet que vous lui ajoutez. Au lieu de cela, il stocke simplement un "pointeur" sur cet objet.

Essayez le code suivant:

>>> d={}
>>> dlist=[]
>>> for i in xrange(0,3):
    d['data']=i
    dlist.append(d)
    print(d)

{'data': 0}
{'data': 1}
{'data': 2}
>>> print(dlist)
[{'data': 2}, {'data': 2}, {'data': 2}]

Alors, pourquoi print(dlist) n'est-il pas identique à print(d)?

Le code suivant vous montre la raison:

>>> for i in dlist:
    print "the list item point to object:", id(i)

the list item point to object: 47472232
the list item point to object: 47472232
the list item point to object: 47472232

Ainsi, vous pouvez voir que tous les éléments du dlist pointe en fait sur le même objet dict.

La vraie réponse à cette question sera d’ajouter la "copie" de l’élément cible, en utilisant d.copy().

>>> dlist=[]
>>> for i in xrange(0,3):
    d['data']=i
    dlist.append(d.copy())
    print(d)

{'data': 0}
{'data': 1}
{'data': 2}
>>> print dlist
[{'data': 0}, {'data': 1}, {'data': 2}]

Essayez l’astuce id(), vous pouvez voir que les éléments de la liste indiquent des objets complètement différents.

>>> for i in dlist:
    print "the list item points to object:", id(i)

the list item points to object: 33861576
the list item points to object: 47472520
the list item points to object: 47458120
33
Wang

info est un pointeur sur un dictionnaire - vous continuez à ajouter le même pointeur à votre liste contact.

Insérer info = {} dans la boucle et cela devrait résoudre le problème:

...
content = []
for iframe in soup.find_all('iframe'):
    info = {}
    info['src'] = iframe.get('src')
    info['height'] = iframe.get('height')
    info['width'] = iframe.get('width')
...
3
zenpoy

Si vous voulez une ligne:

list_of_dict = [{} for i in range(list_len)]
3
XU Bin