A Python, hi ha un límit superior al nombre de recursions (el nombre màxim de recursions). Per executar una funció recursiva amb un gran nombre de trucades, cal canviar el límit. Utilitzeu les funcions del mòdul sys de la biblioteca estàndard.
El nombre de recursivitats també està limitat per la mida de la pila. En alguns entorns, el mòdul de recursos de la biblioteca estàndard es pot utilitzar per canviar la mida màxima de la pila (va funcionar a Ubuntu, però no a Windows o Mac).
Aquí es proporciona la informació següent.
- Obteniu el límit superior del nombre actual de recursivitats:
sys.getrecursionlimit()
- Canvieu el límit superior del nombre de recursivitats:
sys.setrecursionlimit()
- Canvia la mida màxima de la pila:
resource.setrlimit()
El codi de mostra s’està executant a Ubuntu.
Obteniu el límit de recursivitat actual: sys.getrecursionlimit()
El límit de recursivitat actual es pot obtenir amb sys.getrecursionlimit().
import sys
import resource
print(sys.getrecursionlimit())
# 1000
A l’exemple, el nombre màxim de recursivitats és 1000, que pot variar segons el vostre entorn. Tingueu en compte que el recurs que estem important aquí s’utilitzarà més endavant, però no a Windows.
Com a exemple, utilitzarem la següent funció recursiva senzilla. Si s’especifica un nombre enter positiu n com a argument, el nombre de trucades serà n vegades.
def recu_test(n):
if n == 1:
print('Finish')
return
recu_test(n - 1)
Es generarà un error (RecursionError) si intenteu fer recursivitat més del límit superior.
recu_test(950)
# Finish
# recu_test(1500)
# RecursionError: maximum recursion depth exceeded in comparison
Tingueu en compte que el valor obtingut per sys.getrecursionlimit() no és estrictament el nombre màxim de recursivitats, sinó la profunditat màxima de la pila de l’intèrpret de Python, de manera que encara que el nombre de recursions sigui lleugerament inferior a aquest valor, es produirà un error (RecursionError). ser aixecat.
再帰限界は、再帰の限界ではなく、pythonインタープリタのスタックの最夃クの最夀恮恧
python – Max recursion is not exactly what sys.getrecursionlimit() claims. How come? – Stack Overflow
# recu_test(995)
# RecursionError: maximum recursion depth exceeded while calling a Python object
Canvia el límit de recursivitat: sys.setrecursionlimit()
El límit superior del nombre de recursions es pot canviar mitjançant sys.setrecursionlimit(). El límit superior s’especifica com a argument.
Permet realitzar una recursivitat més profunda.
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit())
# 2000
recu_test(1500)
# Finish
Si el límit superior especificat és massa petit o massa gran, es produirà un error. Aquesta restricció (límits superior i inferior del propi límit) varia en funció de l’entorn.
El valor màxim del límit depèn de la plataforma. Si necessiteu una recursivitat profunda, podeu especificar un valor més gran dins de l’interval admès per la plataforma, però tingueu en compte que aquest valor provocarà un error si és massa gran.
If the new limit is too low at the current recursion depth, a RecursionError exception is raised.
sys.setrecursionlimit() — System-specific parameters and functions — Python 3.10.0 Documentation
sys.setrecursionlimit(4)
print(sys.getrecursionlimit())
# 4
# sys.setrecursionlimit(3)
# RecursionError: cannot set the recursion limit to 3 at the recursion depth 1: the limit is too low
sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
# sys.setrecursionlimit(10 ** 10)
# OverflowError: signed integer is greater than maximum
El nombre màxim de recursivitats també està limitat per la mida de la pila, com s’explica a continuació.
Canvia la mida màxima de la pila: resource.setrlimit()
Fins i tot si s’estableix un valor gran a sys.setrecursionlimit(), pot ser que no s’executi si el nombre de recursions és gran. Una falla de segmentació es produeix de la següent manera.
sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
recu_test(10 ** 4)
# Finish
# recu_test(10 ** 5)
# Segmentation fault
A Python, el mòdul de recursos de la biblioteca estàndard es pot utilitzar per canviar la mida màxima de la pila. Tanmateix, el mòdul de recursos és un mòdul específic d’Unix i no es pot utilitzar a Windows.
- Unix Specific Services — Python 3.10.0 Documentation
- resource — Resource usage information — Python 3.10.0 Documentation
Amb resource.getrlimit(), podeu obtenir el límit del recurs especificat a l’argument com una tupla de (límit suau, límit dur). Aquí, especifiquem resource.RLIMIT_STACK com a recurs, que representa la mida màxima de la pila de trucades del procés actual.
- resource.getrlimit() — Resource usage information — Python 3.10.0 Documentation
- resource.RLIMIT_STACK — Resource usage information — Python 3.10.0 Documentation
print(resource.getrlimit(resource.RLIMIT_STACK))
# (8388608, -1)
A l’exemple, el límit suau és 8388608 (8388608 B = 8192 KB = 8 MB) i el límit dur és -1 (il·limitat).
Podeu canviar el límit del recurs amb resource.setrlimit(). Aquí, el límit suau també s’estableix en -1 (sense límit). També podeu utilitzar el recurs constant.RLIM_INFINIT per representar el límit il·limitat.
Ara es pot realitzar una recursivitat profunda, que no es va poder realitzar a causa d’un error de segmentació abans del canvi de mida de la pila.
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
print(resource.getrlimit(resource.RLIMIT_STACK))
# (-1, -1)
recu_test(10 ** 5)
# Finish
Aquí, el límit suau s’estableix a -1 (sense límit) per a un experiment senzill, però, en realitat, seria més segur limitar-lo a un valor adequat.
A més, quan vaig intentar establir un límit suau il·limitat també al meu Mac, es va produir el següent error.ValueError: not allowed to raise maximum limit
Executar l’script amb sudo no va ajudar. Pot estar restringit pel sistema.
Un procés amb l’UID efectiu d’un superusuari pot sol·licitar qualsevol límit raonable, inclòs cap límit.
Tanmateix, una sol·licitud que superi el límit imposat pel sistema encara donarà lloc a un ValueError.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation
Windows no té un mòdul de recursos i el Mac no ha pogut canviar la mida màxima de la pila a causa de les limitacions del sistema. Si podem augmentar la mida de la pila d’alguna manera, hauríem de ser capaços de resoldre l’error de segmentació, però no ho hem pogut confirmar.