Python – Beste/sauberste Art, konstante Listen oder Wörterbücher zu definieren

Lesezeit: 5 Minuten

Erstmaliger Benutzer von Stack Overflow und ich freue mich, hier zu sein.

EINFÜHRUNG: Ich habe vor kurzem das magische Abenteuer in die Welt der Python-Programmierung begonnen – ich liebe es. Jetzt ist bei meinem umständlichen Übergang von C alles glatt gegangen, aber ich habe Probleme, etwas zu erstellen, was auch eine HEADER-Datei (.h) wäre.

PROBLEM: Ich habe mittelgroße Wörterbücher und Listen (etwa 1.000 Elemente), lange Aufzählungen und ‘#defines’ (na ja, nicht wirklich), aber ich kann keinen SAUBEREN Weg finden, sie alle zu organisieren. In C würde ich sie alle in eine Header-Datei werfen und nie wieder darüber nachdenken, aber in Python ist das nicht möglich, denke ich.

AKTUELLE SCHMUTZIGE LÖSUNG: Ich initialisiere alle CONSTANT-Variablen oben im MODULE oder FUNCTION (Modul, wenn mehrere Funktionen es benötigen).

FAZIT: Ich wäre für immer dankbar, wenn jemand einen Weg gefunden hätte, konstante Variablen SAUBER zu organisieren.

VIELEN DANK!

  • Ich wollte nur sagen, willkommen bei Stack und danke, dass Sie hier mit einer gut organisierten Frage angefangen haben!

    – jdi

    20. Juni 2012 um 1:26 Uhr

Setzen Sie Ihre Konstanten in ein eigenes Modul:

# constants.py

RED = 1
BLUE = 2
GREEN = 3

Importieren Sie dann dieses Modul und verwenden Sie die Konstanten:

import constants

print "RED is", constants.RED

Die Konstanten können beliebige Werte sein, ich habe hier ganze Zahlen gezeigt, aber Listen und Diktate würden genauso funktionieren.

  • Großartige Idee. Wissen Sie, wie die Latenz oder der Effizienzverlust ist? Weil Sie es technisch gesehen importieren und das nicht jedes Mal nachschlagen muss, wenn Sie auf den Wert verweisen?

    – Schmied

    20. Juni 2012 um 1:30 Uhr

  • Sie führen jedes Mal eine Attributsuche durch, was die Art von Operation ist, die sowieso die ganze Zeit passiert, es ist wirklich kein Grund zur Sorge.

    – Ned Batchelder

    20. Juni 2012 um 1:31 Uhr

  • @TSmith: Und wenn Sie sehr daran interessiert sind, dieses bisschen Zeit zu sparen, können Sie das immer tun from constants import REDoder weisen Sie es einer Variablen kurz vor einer superlangen Schleife zu: red = constants.RED

    – jdi

    20. Juni 2012 um 1:35 Uhr


  • Danke Ned und Jdi! Ich weiß es wirklich zu schätzen und ja, das ist mehr von dem, was ich hören wollte, aber wird eine lokale Variable eine Kopie oder einen Verweis auf die global importierte Konstante erhalten? Nur aus Neugier.

    – Schmied

    20. Juni 2012 um 1:37 Uhr


  • @TSmith: Mach dich nicht verrückt mit Optimierungen. Die Chancen stehen gut, dass Ihr Code zum Beispiel nicht rechengebunden ist.

    – Ned Batchelder

    20. Juni 2012 um 1:42 Uhr

Normalerweise mache ich das:

Datei: konstanten.py

CONSTANT1 = 'asd'
CONSTANT_FOO = 123
CONSTANT_BAR = [1, 2, 5]

Datei: your_script.py

from constants import CONSTANT1, CONSTANT_FOO
# or if you want *all* of them
# from constants import *

...

Jetzt befinden sich Ihre Konstanten in einer Datei und Sie können sie problemlos importieren und verwenden.

  • Danke, CC’ing Sie auf die Effizienzfrage, wenn Sie helfen können.

    – Schmied

    20. Juni 2012 um 1:34 Uhr

  • Wenn Sie alle importieren, werden die Konstanten zu globalen Variablen und erfordern keine Suche. Beachten Sie, dass Python etwa 200-mal langsamer als C ist, sodass Sie bei der Mikrooptimierung keinen großen Geschwindigkeitsschub bemerken werden.

    – Mixer

    20. Juni 2012 um 1:37 Uhr


  • Danke Blender. Kurze Neugierfrage: Wenn ich dieser importierten globalen Variablen eine lokale Variable (innerhalb einer Funktion) zuweise, wird diese lokale Variable eine Kopie oder einen Verweis auf die globale Variable haben?

    – Schmied

    20. Juni 2012 um 1:45 Uhr

  • @TSmith: Es wird eine Referenz haben, aber beachten Sie, dass das Verhalten davon abhängt, ob es sich um einen veränderlichen oder unveränderlichen Typ handelt. Wenn es sich um eine Zeichenfolge handelt, werden alle Änderungen, die Sie an dieser lokalen vornehmen, einfach die globale Konstante überschatten. Wenn die Konstante beispielsweise ein Listenobjekt ist, können Sie sie an die lokale Variable anhängen, und sie wird in der Konstante wiedergegeben, da sie immer noch dieselbe Referenz ist

    – jdi

    20. Juni 2012 um 1:48 Uhr


  • @jdi: Ja, ich habe auf die harte Tour etwas über veränderliche und unveränderliche Typen gelernt, haha. Vielen Dank für die Hilfe, ich weiß das sehr zu schätzen.

    – Schmied

    20. Juni 2012 um 1:52 Uhr

Erstellen Sie eine separate Datei constants.py, und fügen Sie dort alle global relevanten Konstanten ein. Dann kannst du import constants sie zu bezeichnen als constants.SPAM oder mach das (fragwürdig) from constants import * um sie einfach als zu bezeichnen SPAM oder EGGS.

Während wir hier sind, beachten Sie, dass Python nicht unterstützt wird Konstante Konstanten. Die Konvention besteht nur darin, sie zu nennen ALL_CAPS und versprechen, sie nicht zu mutieren.

  • Haha ja, ich verspreche es :), aber was ist mit der Laufzeiteffizienz? Wenn Sie ein Modul importieren, ist das wie “__inline” in C?

    – Schmied

    20. Juni 2012 um 1:32 Uhr

  • @TSmith: Ich würde es nicht mit einem Inline-Objekt vergleichen, da es wirklich nur in ein Namespace-Modulobjekt importiert wird, und dies nur einmal tut und es für nachfolgende Importe im Speicher teilt.

    – jdi

    20. Juni 2012 um 1:39 Uhr


  • Ja, das war eine dumme Frage, jetzt wo ich darüber nachdenke. Vielen Dank und einen schönen Tag!

    – Schmied

    20. Juni 2012 um 1:50 Uhr

Benutzeravatar von Mark Z
Markus Z.

Die akzeptierte Antwort ist in Ordnung, um noch einen Schritt weiter zu gehen, können Sie beim Definieren Ihrer Konstanten Typisierungen verwenden. Sie könnten einfach Final angeben oder noch einen Schritt weiter gehen und Final angeben[type] auch, zB:

from typing import Final, List
CONSTANT1: Final="asd"
CONSTANT_FOO: Final[int] = 123
ADLS_ENVIRONMENTS: Final[List[str]] = ["sandbox", "dev", "uat", "prod"]

# etc.

Sehen https://www.python.org/dev/peps/pep-0591/#the-final-annotation

Wenn Sie mit verschachtelten Konstanten herumspielen wollen und Diktate nicht mögen, habe ich mir diese lustige Lösung ausgedacht:

# Recursively transform a dict to instances of the desired class

import json
from collections import namedtuple

class DictTransformer():
    @classmethod
    def constantize(self, d):
        return self.transform(d, klass=namedtuple, klassname="namedtuple")

    @classmethod
    def transform(self, d, klass, klassname):
        return self._from_json(self._to_json(d), klass=klass, klassname=klassname)

    @classmethod
    def _to_json(self, d, access_method='__dict__'):
        return json.dumps(d, default=lambda o: getattr(o, access_method, str(o)))

    @classmethod
    def _from_json(self, jsonstr, klass, klassname):
        return json.loads(jsonstr, object_hook=lambda d: klass(klassname, d.keys())(*d.values()))

Ex:

constants = {
  'A': {
    'B': {
      'C': 'D'
    }
  }
}
CONSTANTS = DictTransformer.transform(d, klass=namedtuple, klassname="namedtuple")
CONSTANTS.A.B.C == 'D'

Vorteile:

  • behandelt verschachtelte Diktate
  • kann möglicherweise andere Arten von Diktaten/Klassen generieren
  • namedtuples bieten Unveränderlichkeit für Konstanten

Nachteile:

  • reagiert möglicherweise nicht auf .keys und .values, wenn diese nicht in Ihrer Klasse bereitgestellt werden (obwohl Sie manchmal mit ._fields und list(ABC) nachahmen können)

Gedanken?

h/t an @hlzr und euch für die originelle Unterrichtsidee

1400270cookie-checkPython – Beste/sauberste Art, konstante Listen oder Wörterbücher zu definieren

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy