


Méthode d'ajustement de la longueur de la liste Python (avec code)
Ce que cet article vous apporte concerne la méthode d'ajustement de la longueur des listes Python (avec code). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
La liste de Python est un tableau très flexible et la longueur peut être ajustée à volonté. C'est précisément à cause de cette commodité que nous ne pouvons nous empêcher de modifier le tableau pour répondre à nos besoins. Par rapport à l'insertion, au pop, etc., l'utilisation de l'ajout est plus courante.
Certains sont utilisés comme ceci :
>>> test = [] >>> test.append(1) >>> test.append({2}) >>> test.append([3]) >>> print test # 输出 [1, set([2]), [3]]
Il y en a aussi certains utilisés comme ceci :
test = [] for i in range(4): test.append(i) print test # 输出 [0, 1, 2, 3]
L'utiliser de cette façon est très heureux et satisfaisant.
Mais en fait, chaque fois que nous rencontrons un scénario où la longueur des données peut être modifiée dynamiquement, nous devons immédiatement réagir, c'est-à-dire le problème de la gestion de la mémoire.
Si l'efficacité opérationnelle et la commodité sont réunies en même temps, ce sera une excellente nouvelle.
Cependant, lorsque Dieu vous ouvre une fenêtre, il doit aussi avoir fermé une porte !
Initialisation avare
Nous sommes profondément influencés par la connaissance de la pré-allocation. Nous pensons également que la liste se voit attribuer une certaine longueur lors de l'initialisation, sinon elle serait "faible" à demander. mémoire à chaque fois ah.
En fait, la liste est vraiment si « basse » :
import sys test = [] test_1 = [1] print sys.getsizeof(test) print sys.getsizeof(test_1) - sys.getsizeof(test) # 输出 72 # 空列表内存大小,也是 list 对象的总大小 8 # 代表增加一个成员,list 增加的大小
Nous pensons qu'une fois la liste définie, un pool d'une certaine taille sera pré-alloué pour le remplissage data , pour éviter de demander de la mémoire à chaque tour.
Mais l'expérience ci-dessus montre que la longueur d'une liste de membres n'est que de 8 octets plus grande qu'une liste vide. S'il existe réellement un tel pool pré-alloué, alors le nombre de membres pré-alloués lors de l'ajout de membres, la taille de la mémoire des deux doit rester inchangée.
On peut donc deviner que cette liste ne dispose pas d'un tel pool de mémoire pré-alloué. Ici, nous avons besoin d'un vrai marteau
PyObject * PyList_New(Py_ssize_t size) { PyListObject *op; size_t nbytes; if (size < 0) { PyErr_BadInternalCall(); return NULL; } /* Check for overflow without an actual overflow, * which can cause compiler to optimise out */ if ((size_t)size > PY_SIZE_MAX / sizeof(PyObject *)) return PyErr_NoMemory(); // list对象指针的缓存 if (numfree) { numfree--; op = free_list[numfree]; _Py_NewReference((PyObject *)op); } else { op = PyObject_GC_New(PyListObject, &PyList_Type); if (op == NULL) return NULL; } // list 成员的内存申请 nbytes = size * sizeof(PyObject *); if (size <= 0) op->ob_item = NULL; else { op->ob_item = (PyObject **) PyMem_MALLOC(nbytes); if (op->ob_item == NULL) { Py_DECREF(op); return PyErr_NoMemory(); } memset(op->ob_item, 0, nbytes); } Py_SIZE(op) = size; op->allocated = size; _PyObject_GC_TRACK(op); return (PyObject *) op; }
Lorsque nous exécutons test = [1], nous ne faisons en fait que deux choses :
Selon le nombre de membres, construire une longueur correspondante Liste vide ; (au-dessus du code)
Mettez ces membres un par un
Certains enfants peuvent penser qu'à l'étape de branchement des membres, un mécanisme peut être déclenché pour le faire devenir grand ?
C'est dommage, car la méthode d'initialisation est PyList_SET_ITEM, donc il n'y a pas de mécanisme de déclenchement ici, c'est juste une simple affectation des membres du tableau :
#define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v))
Donc la liste entière est initialisé, il n'y a vraiment pas de pool de mémoire pré-alloué. Vous pouvez en faire la demande directement sur demande. Chaque carotte est une fosse, ce qui est vraiment cruel
La clé de la longueur variable
Initialisation Il est compréhensible que le processus soit ainsi, mais s'il est toujours ainsi pendant le fonctionnement, ce serait un peu déraisonnable. Imaginez simplement, dans l'exemple d'utilisation de append au début de l'article, si la mémoire est appliquée à chaque fois qu'un élément est ajouté, alors la liste peut être critiquée au point de douter de la vie, c'est donc Il est évident que lors d'une demande de mémoire, il a toujours sa propre routine. Dans la liste, que ce soit par insertion, pop ou ajout, vous rencontrerez list_resize. Comme son nom l'indique, cette fonction est utilisée pour ajuster l'utilisation de la mémoire des objets de liste.static int list_resize(PyListObject *self, Py_ssize_t newsize) { PyObject **items; size_t new_allocated; Py_ssize_t allocated = self->allocated; /* Bypass realloc() when a previous overallocation is large enough to accommodate the newsize. If the newsize falls lower than half the allocated size, then proceed with the realloc() to shrink the list. */ if (allocated >= newsize && newsize >= (allocated >> 1)) { assert(self->ob_item != NULL || newsize == 0); Py_SIZE(self) = newsize; return 0; } /* This over-allocates proportional to the list size, making room * for additional growth. The over-allocation is mild, but is * enough to give linear-time amortized behavior over a long * sequence of appends() in the presence of a poorly-performing * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ # 确定新扩展之后的占坑数 new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6); /* check for integer overflow */ if (new_allocated > PY_SIZE_MAX - newsize) { PyErr_NoMemory(); return -1; } else { new_allocated += newsize; } if (newsize == 0) new_allocated = 0; # 申请内存 items = self->ob_item; if (new_allocated <= (PY_SIZE_MAX / sizeof(PyObject *))) PyMem_RESIZE(items, PyObject *, new_allocated); else items = NULL; if (items == NULL) { PyErr_NoMemory(); return -1; } self->ob_item = items; Py_SIZE(self) = newsize; self->allocated = new_allocated; return 0; }
a = [1, 2, 3] a.append(1)
0 <= ob_size <= allocated len(list) == ob_size
#coding: utf8 import sys test = [] raw_size = sys.getsizeof(test) test.append(1) print "1 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "2 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "3 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "4 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "5 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size) test.append(1) print "6 次 append 减去空列表的内存大小:%s " % (sys.getsizeof(test) - raw_size)
# 输出结果 1 次 append 减去空列表的内存大小:32 2 次 append 减去空列表的内存大小:32 3 次 append 减去空列表的内存大小:32 4 次 append 减去空列表的内存大小:32 5 次 append 减去空列表的内存大小:64 6 次 append 减去空列表的内存大小:64
第 n 次 append | 列表原长度 | 新增成员数 | 原 allocated | newsize | new_allocated |
---|---|---|---|---|---|
1 | 0 | 1 | 0 | 0 + 1 = 1 | 3 + 1 = 4 |
2 | 1 | 1 | 4 | 1 + 1 = 2 | 无需改变 |
3 | 2 | 1 | 4 | 2 + 1 = 3 | 无需改变 |
4 | 3 | 1 | 4 | 3 + 1 = 4 | 无需改变 |
5 | 4 | 1 | 4 | 4 + 1 = 5 | 3 + 5 = 8 |
6 | 5 | 1 | 8 | 5 + 1 = 6 | 无需改变 |
通过上面的表格,应该比较清楚看到什么时候会触发改变 allocated,并且当触发时它们是如何计算的。为什么我们需要这样关注 allocated?理由很简单,因为这个值决定了整个 list 的动态内存的占用大小;
扩容是这样,缩容也是照猫画虎。反正都是算出新的 allocated, 然后由 PyMem_RESIZE 来处理。
总结
综上所述,在一些明确列表成员或者简单处理再塞入列表的情况下,我们不应该再用下面的方式:
test = [] for i in range(4): test.append(i) print test
而是应该用更加 pythonic 和 更加高效的列表推导式:test = [i for i in range(4)]。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

PHP et Python ont chacun leurs propres avantages et choisissent en fonction des exigences du projet. 1.Php convient au développement Web, en particulier pour le développement rapide et la maintenance des sites Web. 2. Python convient à la science des données, à l'apprentissage automatique et à l'intelligence artificielle, avec syntaxe concise et adaptée aux débutants.

La fonction ReadDir dans le système Debian est un appel système utilisé pour lire le contenu des répertoires et est souvent utilisé dans la programmation C. Cet article expliquera comment intégrer ReadDir avec d'autres outils pour améliorer sa fonctionnalité. Méthode 1: combinant d'abord le programme de langue C et le pipeline, écrivez un programme C pour appeler la fonction readdir et sortir le résultat: # include # include # include # includeIntmain (intargc, char * argv []) {dir * dir; structDirent * entrée; if (argc! = 2) {

Pour maximiser l'efficacité de l'apprentissage de Python dans un temps limité, vous pouvez utiliser les modules DateTime, Time et Schedule de Python. 1. Le module DateTime est utilisé pour enregistrer et planifier le temps d'apprentissage. 2. Le module de temps aide à définir l'étude et le temps de repos. 3. Le module de planification organise automatiquement des tâches d'apprentissage hebdomadaires.

La configuration d'un serveur HTTPS sur un système Debian implique plusieurs étapes, notamment l'installation du logiciel nécessaire, la génération d'un certificat SSL et la configuration d'un serveur Web (tel qu'Apache ou Nginx) pour utiliser un certificat SSL. Voici un guide de base, en supposant que vous utilisez un serveur Apacheweb. 1. Installez d'abord le logiciel nécessaire, assurez-vous que votre système est à jour et installez Apache et OpenSSL: SudoaptupDaSuDoaptupgradeSudoaptinsta

Développer un plugin Gitlab sur Debian nécessite des étapes et des connaissances spécifiques. Voici un guide de base pour vous aider à démarrer avec ce processus. Installation de GitLab Tout d'abord, vous devez installer GitLab sur votre système Debian. Vous pouvez vous référer au manuel d'installation officiel de Gitlab. Obtenez un jeton d'accès API avant d'effectuer l'intégration de l'API, vous devez d'abord obtenir le jeton d'accès API de GitLab. Ouvrez le tableau de bord GitLab, recherchez l'option "AccessTokens" dans les paramètres utilisateur et générez un nouveau jeton d'accès. Sera généré

Apache est le héros derrière Internet. Ce n'est pas seulement un serveur Web, mais aussi une plate-forme puissante qui prend en charge un trafic énorme et fournit un contenu dynamique. Il offre une flexibilité extrêmement élevée grâce à une conception modulaire, permettant l'expansion de diverses fonctions au besoin. Cependant, la modularité présente également des défis de configuration et de performance qui nécessitent une gestion minutieuse. Apache convient aux scénarios de serveur qui nécessitent des besoins complexes hautement personnalisables.

Apache est écrit en C. La langue offre la vitesse, la stabilité, la portabilité et l'accès direct au matériel, ce qui le rend idéal pour le développement du serveur Web.

PHP et Python ont leurs propres avantages et inconvénients, et le choix dépend des besoins du projet et des préférences personnelles. 1.Php convient au développement rapide et à la maintenance des applications Web à grande échelle. 2. Python domine le domaine de la science des données et de l'apprentissage automatique.
