Έχω έναν διακομιστή 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
.
Μπορεί να είναι ιδιαίτερα δύσκολο να διαγράψετε μια ενότητα αν δεν είναι καθαρή Python.
Εδώ είναι μερικές πληροφορίες από το: Πώς μπορώ πραγματικά να διαγράψω μια εισαγόμενη ενότητα;
Μπορείτε να χρησιμοποιήσετε τη sys.getrefcount() για να μάθετε τον πραγματικό αριθμό των αναφορών. >,
>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3
>,
Αριθμοί μεγαλύτεροι του 3 υποδεικνύουν ότι ότι θα είναι δύσκολο να απαλλαγούμε από το... ενότητα. Η εγχώρια "κενή", (που δεν περιέχει τίποτα) ενότητα θα πρέπει να είναι να συλλέγεται από τα σκουπίδια μετά >,
>>> del sys.modules["empty"]
>>> del empty
>,
καθώς η τρίτη αναφορά είναι ένα τεχνούργημα της συνάρτησης getrefcount().
reload(module)
, αλλά μόνο αν είναι εντελώς αυτόνομο. Αν οτιδήποτε άλλο έχει αναφορά στο module (ή σε οποιοδήποτε αντικείμενο που ανήκει στο module), τότε θα λάβετε λεπτά και περίεργα σφάλματα που προκαλούνται από τον παλιό κώδικα που παραμένει εκεί περισσότερο από όσο περιμένατε, και πράγματα όπως το isinstance
που δεν λειτουργεί σε διαφορετικές εκδόσεις του ίδιου κώδικα.
Αν έχετε μονόδρομες εξαρτήσεις, πρέπει επίσης να επαναφορτώσετε όλες τις ενότητες που εξαρτώνται από την επαναφορτωμένη ενότητα για να απαλλαγείτε από όλες τις αναφορές στον παλιό κώδικα. Και στη συνέχεια να επαναφορτώσετε αναδρομικά τα modules που εξαρτώνται από τα επαναφορτωμένα modules.
Αν έχετε κυκλικές εξαρτήσεις, κάτι που είναι πολύ συνηθισμένο για παράδειγμα όταν έχετε να κάνετε με την επαναφόρτωση ενός πακέτου, πρέπει να ξεφορτώσετε όλα τα modules της ομάδας με μία κίνηση. Δεν μπορείτε να το κάνετε αυτό με την reload()
επειδή θα επαναφέρει κάθε ενότητα πριν ανανεωθούν οι εξαρτήσεις της, επιτρέποντας σε παλιές αναφορές να εισχωρήσουν σε νέες ενότητες.
Ο μόνος τρόπος για να το κάνετε σε αυτή την περίπτωση είναι να χακάρετε το sys.modules
, το οποίο είναι κάπως μη υποστηριζόμενο. Θα πρέπει να ψάξετε και να διαγράψετε κάθε καταχώρηση του sys.modules
που θέλετε να επαναφορτωθεί στην επόμενη εισαγωγή, και επίσης να διαγράψετε καταχωρήσεις των οποίων οι τιμές είναι None
για να αντιμετωπίσετε ένα θέμα υλοποίησης που έχει να κάνει με την προσωρινή αποθήκευση αποτυχημένων σχετικών εισαγωγών. Δεν είναι και τόσο ωραίο, αλλά εφόσον έχετε ένα πλήρως αυτοτελές σύνολο εξαρτήσεων που δεν αφήνει αναφορές εκτός της βάσης κωδικών του, είναι λειτουργικό.
Πιθανότατα είναι καλύτερο να επανεκκινήσετε τον διακομιστή :-)