Πώς μπορώ να ξεφορτώσω (επαναφορτώσω) μια ενότητα;

Έχω έναν διακομιστή Python που λειτουργεί για μεγάλο χρονικό διάστημα και θα ήθελα να μπορώ να αναβαθμίσω μια υπηρεσία χωρίς να επανεκκινήσω τον διακομιστή. Ποιος είναι ο καλύτερος τρόπος για να το κάνω αυτό;

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()
Λύση

Μπορείτε να επαναφορτώσετε μια ενότητα όταν έχει ήδη εισαχθεί χρησιμοποιώντας την ενσωματωμένη συνάρτηση reload:

from importlib import reload  # Python 3.4+ only.
import foo

while True:
    # Do some things.
    if is_changed(foo):
        foo = reload(foo)

Στην Python 3, η reload μεταφέρθηκε στην ενότητα imp. Στην έκδοση 3.4, το imp καταργήθηκε για χάρη του importlib, και το reload προστέθηκε στο τελευταίο. Όταν στοχεύετε στο 3 ή μεταγενέστερο, είτε αναφερθείτε στο κατάλληλο module όταν καλείτε το reload είτε εισάγετε το.

Νομίζω ότι αυτό είναι που θέλετε. Οι διακομιστές ιστού όπως ο διακομιστής ανάπτυξης του Django'το χρησιμοποιούν αυτό, ώστε να μπορείτε να δείτε τα αποτελέσματα των αλλαγών στον κώδικά σας χωρίς να επανεκκινήσετε την ίδια τη διαδικασία του διακομιστή.

Για να παραθέσω ένα απόσπασμα από τα έγγραφα:

Ο κώδικας των ενοτήτων Python μεταγλωττίζεται εκ νέου και

ο κώδικας σε επίπεδο ενότητας εκτελείται εκ νέου, ορίζοντας ένα νέο σύνολο αντικειμένων που συνδέονται με ονόματα στο αρχείο της ενότητας. λεξικό της μονάδας. Η συνάρτηση init της των ενοτήτων επέκτασης δεν καλείται δεύτερη φορά. Όπως και με όλα τα άλλα αντικείμενα στην Python τα παλιά αντικείμενα είναι μόνο ανακτώνται μόνο μετά τον αριθμό των αναφορών τους πέσουν στο μηδέν. Τα ονόματα στην ενότητα ενημερώνονται ώστε να δείχνουν σε οποιοδήποτε νέα ή αλλαγμένα αντικείμενα. Άλλα αναφορές στα παλιά αντικείμενα (όπως τα ονόματα εκτός της ενότητας) δεν αναπήδηση για να αναφέρονται στα νέα αντικείμενα και πρέπει να ενημερώνονται σε κάθε χώρο ονομάτων όπου εμφανίζονται, εάν αυτό είναι επιθυμητό.

Όπως σημειώσατε στην ερώτησή σας, θα πρέπει να ανακατασκευάσετε τα αντικείμενα Foo αν η κλάση Foo βρίσκεται στην ενότητα foo.

Σχόλια (17)

Μπορεί να είναι ιδιαίτερα δύσκολο να διαγράψετε μια ενότητα αν δεν είναι καθαρή Python.

Εδώ είναι μερικές πληροφορίες από το: Πώς μπορώ πραγματικά να διαγράψω μια εισαγόμενη ενότητα;

Μπορείτε να χρησιμοποιήσετε τη sys.getrefcount() για να μάθετε τον πραγματικό αριθμό των αναφορών. &gt,

>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3

&gt,

Αριθμοί μεγαλύτεροι του 3 υποδεικνύουν ότι ότι θα είναι δύσκολο να απαλλαγούμε από το... ενότητα. Η εγχώρια "κενή&quot, (που δεν περιέχει τίποτα) ενότητα θα πρέπει να είναι να συλλέγεται από τα σκουπίδια μετά &gt,

>>> del sys.modules["empty"]
>>> del empty

&gt,

καθώς η τρίτη αναφορά είναι ένα τεχνούργημα της συνάρτησης getrefcount().

Σχόλια (2)

reload(module), αλλά μόνο αν είναι εντελώς αυτόνομο. Αν οτιδήποτε άλλο έχει αναφορά στο module (ή σε οποιοδήποτε αντικείμενο που ανήκει στο module), τότε θα λάβετε λεπτά και περίεργα σφάλματα που προκαλούνται από τον παλιό κώδικα που παραμένει εκεί περισσότερο από όσο περιμένατε, και πράγματα όπως το isinstance που δεν λειτουργεί σε διαφορετικές εκδόσεις του ίδιου κώδικα.

Αν έχετε μονόδρομες εξαρτήσεις, πρέπει επίσης να επαναφορτώσετε όλες τις ενότητες που εξαρτώνται από την επαναφορτωμένη ενότητα για να απαλλαγείτε από όλες τις αναφορές στον παλιό κώδικα. Και στη συνέχεια να επαναφορτώσετε αναδρομικά τα modules που εξαρτώνται από τα επαναφορτωμένα modules.

Αν έχετε κυκλικές εξαρτήσεις, κάτι που είναι πολύ συνηθισμένο για παράδειγμα όταν έχετε να κάνετε με την επαναφόρτωση ενός πακέτου, πρέπει να ξεφορτώσετε όλα τα modules της ομάδας με μία κίνηση. Δεν μπορείτε να το κάνετε αυτό με την reload() επειδή θα επαναφέρει κάθε ενότητα πριν ανανεωθούν οι εξαρτήσεις της, επιτρέποντας σε παλιές αναφορές να εισχωρήσουν σε νέες ενότητες.

Ο μόνος τρόπος για να το κάνετε σε αυτή την περίπτωση είναι να χακάρετε το sys.modules, το οποίο είναι κάπως μη υποστηριζόμενο. Θα πρέπει να ψάξετε και να διαγράψετε κάθε καταχώρηση του sys.modules που θέλετε να επαναφορτωθεί στην επόμενη εισαγωγή, και επίσης να διαγράψετε καταχωρήσεις των οποίων οι τιμές είναι None για να αντιμετωπίσετε ένα θέμα υλοποίησης που έχει να κάνει με την προσωρινή αποθήκευση αποτυχημένων σχετικών εισαγωγών. Δεν είναι και τόσο ωραίο, αλλά εφόσον έχετε ένα πλήρως αυτοτελές σύνολο εξαρτήσεων που δεν αφήνει αναφορές εκτός της βάσης κωδικών του, είναι λειτουργικό.

Πιθανότατα είναι καλύτερο να επανεκκινήσετε τον διακομιστή :-)

Σχόλια (7)