Python-utvecklingsläge

Tillagd i version 3.7.

Python Development Mode introducerar ytterligare körtidskontroller som är för dyra för att aktiveras som standard. Det bör inte vara mer mångordigt än standardvärdet om koden är korrekt; nya varningar utfärdas endast när ett problem upptäcks.

Det kan aktiveras med kommandoradsalternativet -X dev eller genom att ställa in miljövariabeln PYTHONDEVMODE till 1.

Se även Python debug build.

Effekter av Pythons utvecklingsläge

Aktivering av Python Development Mode liknar följande kommando, men med ytterligare effekter som beskrivs nedan:

PYTHONMALLOC=debug PYTHONASYNCIODEBUG=1 python -W default -X faulthandler

Effekter av Pythons utvecklingsläge:

I Pythons utvecklingsläge aktiveras inte modulen tracemalloc som standard, eftersom kostnaden (för prestanda och minne) skulle bli för stor. Om du aktiverar modulen tracemalloc får du ytterligare information om ursprunget till vissa fel. Till exempel loggar ResourceWarning spårningen där resursen allokerades, och ett buffer overflow-fel loggar spårningen där minnesblocket allokerades.

Python Development Mode hindrar inte kommandoradsalternativet -O från att ta bort assert-satser eller från att sätta __debug__ till False.

Pythons utvecklingsläge kan endast aktiveras när Python startas. Dess värde kan läsas från sys.flags.dev_mode.

Ändrad i version 3.8: Destruktorn io.IOBase loggar nu close()-undantag.

Ändrad i version 3.9: Argumenten encoding och errors kontrolleras nu för kodning och avkodning av strängar.

Exempel på ResourceWarning

Exempel på ett skript som räknar antalet rader i den textfil som anges på kommandoraden:

import sys

def main():
    fp = open(sys.argv[1])
    nlines = len(fp.readlines())
    print(nlines)
    # The file is closed implicitly

if __name__ == "__main__":
    main()

Skriptet stänger inte filen explicit. Som standard ger Python inte ut någon varning. I exemplet används README.txt, som har 269 rader:

$ python script.py README.txt
269

Om du aktiverar Python Development Mode visas en ResourceWarning-varning:

$ python -X dev script.py README.txt
269
script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='README.rst' mode='r' encoding='UTF-8'>
  main()
ResourceWarning: Enable tracemalloc to get the object allocation traceback

Om du aktiverar tracemalloc visas dessutom den rad där filen öppnades:

$ python -X dev -X tracemalloc=5 script.py README.rst
269
script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='README.rst' mode='r' encoding='UTF-8'>
  main()
Object allocated at (most recent call last):
  File "script.py", lineno 10
    main()
  File "script.py", lineno 4
    fp = open(sys.argv[1])

Lösningen är att stänga filen explicit. Exempel med hjälp av en kontexthanterare:

def main():
    # Close the file explicitly when exiting the with block
    with open(sys.argv[1]) as fp:
        nlines = len(fp.readlines())
    print(nlines)

Att inte stänga en resurs explicit kan lämna en resurs öppen mycket längre än förväntat; det kan orsaka allvarliga problem när Python avslutas. Det är illa i CPython, men det är ännu värre i PyPy. Att stänga resurser explicit gör en applikation mer deterministisk och mer tillförlitlig.

Exempel på fel i dålig filbeskrivare

Skriptet visar den första raden av sig själv:

import os

def main():
    fp = open(__file__)
    firstline = fp.readline()
    print(firstline.rstrip())
    os.close(fp.fileno())
    # The file is closed implicitly

main()

Som standard ger Python inte ut någon varning:

$ python script.py
import os

Python Development Mode visar en ResourceWarning och loggar ett ”Bad file descriptor”-fel när filobjektet slutförs:

$ python -X dev script.py
import os
script.py:10: ResourceWarning: unclosed file <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'>
  main()
ResourceWarning: Enable tracemalloc to get the object allocation traceback
Exception ignored in: <_io.TextIOWrapper name='script.py' mode='r' encoding='UTF-8'>
Traceback (most recent call last):
  File "script.py", line 10, in <module>
    main()
OSError: [Errno 9] Bad file descriptor

os.close(fp.fileno()) stänger filbeskrivaren. När filobjektets slutbehandlare försöker stänga filbeskrivaren igen misslyckas den med felet Bad file descriptor. En file descriptor får bara stängas en gång. I värsta fall kan det leda till en krasch om den stängs två gånger (se bpo-18748 för ett exempel).

Lösningen är att ta bort raden os.close(fp.fileno()) eller öppna filen med closefd=False.