2014-02-11 8 views
8

Erstens, wenn ich nach Einheiten frage, meine ich Maßeinheiten wie Zoll, Fuß, Pixel, Zellen. Ich beziehe mich nicht auf Datentypen wie int und float.Python-Konvention für Variablennamen zur Anzeige von Einheiten

Wikipedia bezeichnet dies als logische Datentyp statt physischen Datentyp.

Ich würde gerne die beste Möglichkeit, Variablen zu benennen, kennen.

Hier ist ein Code, durch zu gehen, was ich frage:

board_length=8 #in inches 
board_length=8*12 #Convert from feet to inches 

Beachten Sie, dass diese beide ganze Zahlen sind (oder schwimmt, ist mir egal), aber ich habe Einheiten verändert. Ich habe auch den Variablennamen beibehalten. Ich könnte eine Konvention aufstellen, und das ist der Zweck dieser Frage. Ohne Anleitung könnte ich so etwas tun:

board_length=8 
board_length_inches=8*12 

Ich würde dies eine Ad-hoc-Art der Dinge zu tun. Oder ich könnte eine Konvention etablieren:

Fboard_length=8 
Iboard_length=8*12 

Oder andere Varianten, die ich ebenso nicht mag. Wie kann ich Variablen in einer beschreibenden Weise benennen, aber so nah wie möglich an PEP-08 bleiben?

Nur um so klar, wie ich kann, können die Variablen verschiedene Datentypen haben, aber die Einheiten wären der gleiche (Zoll würde die gleiche Namensgebung hat, unabhängig davon, ob sie als und integer oder float gespeichert wurden)

+0

Je nachdem, wie wichtig die Einheiten für Ihr Skript sind, könnten Sie in Betracht ziehen, Unterklassen basierend auf jeder Einheit zu erstellen. Jede "Maßeinheit" (Länge, Gewicht usw.) hätte ihre On-Klasse, die die eingebauten Typen erbt, und hat ihre eigenen Unterklassen für die einzelnen Einheiten. Diese Einheiten hätten dann Methoden zur Umwandlung in alle anderen Einheiten des gleichen Typs.Dies wäre eine Menge Arbeit, so dass Sie fragen müssen, ob es wirklich wert ist – wnnmaw

+0

Oder Sie könnten die Builtins dekorieren, um ein Attribut oder eine Methode zu haben, die Einheiten überwacht – wnnmaw

+1

Ich würde mir darüber nicht zu viele Sorgen machen. Ich kann mir keine Fälle vorstellen, in denen Sie denselben Wert für längere Zeit in verschiedenen Einheiten speichern müssten. Ich würde das einfach tun - "board_length = 24 # in inches" (mehrere Zeilen später) 'print (to_feet (board_length))' oder 'FEET = 12; print (board_length * FEET) '. – rlms

Antwort

1

Ich würde weiter gehen und separate Objekttypen haben, die Typsicherheit bieten, anstatt sich einfach auf Namenskonventionen zu verlassen. Andernfalls könnten Sie eine Variable, die Zoll repräsentiert, an eine Methode übergeben, die Meilen erfordert.

Ich denke, dass Konventionen Unter Berufung auf die Namensgebung wird problematisch, langfristig zu erhalten und die Nutzung von Arten machen werden Sie viel mehr Flexibilität und Sicherheit (zB Bereitstellung von Conversions usw. in die Objekttypen gebaut)

+0

Das ist ein guter Rat. Wenn der Zweck einer Namenskonvention darin besteht, dem Entwickler zu helfen, Verwirrung und Fehler zu vermeiden, werden Sie noch viel mehr lernen, wenn Sie dem Python-Klassensystem erlauben, die Regeln für Sie durchzusetzen. Wenn Sie nur eine Namenskonvention verwenden, könnte ein verwirrter Entwickler leicht Dinge wie 12 (Zoll) + 1 (cm) = 13 (oops) tun. –

+0

Ich werde diese Antwort akzeptieren, obwohl sie keine Namenskonvention vorschlägt, sie schlägt eine Alternative vor, die für andere, die an dieser Frage interessiert sind, funktionieren würde. Vielen Dank. –

2

Wenn Wenn Sie eine robustere Geräteunterstützung wünschen, sollten Sie sich die Nummer PyPi's Pint module ansehen. Es befasst sich nicht direkt mit Ihrer Frage der Namenskonvention, aber es kann einen großen Teil der Arbeit mit häufigen Konvertierungen erfordern. Sie können hier Informationen über sie und einige andere Einheitsmodule finden:

http://www.drdobbs.com/jvm/quantities-and-units-in-python/240161101

+0

Ich mag diesen Vorschlag im Allgemeinen und es scheint eine gute Möglichkeit zu sein, im Wesentlichen umzusetzen, was @BrianAgnew vorgeschlagen hat. –

9

Während Sie mit einer Namenskonvention kommen könnte, sollten Sie besser durch den Bau eines Objekts darstellt, „Abstand“ mit Eigenschaften bedient werden könnten, lesen/schreibe in verschiedene Einheiten. Zum Beispiel:

class Distance(object): 

    def __init__(self): 
     self._inches = 0 

    @property 
    def inches(self): 
     return self._inches 

    @inches.setter 
    def inches(self, value): 
     self._inches = value 

    @property 
    def feet(self): 
     return self._inches/12 

    @feet.setter 
    def feet(self, value): 
     self._inches = value * 12 

Sie könnten es sogar generischer machen, so dass Sie problemlos mit neuen Konvertierungen erweitern können. (Hinweis: Bearbeitet zur Erinnerung basierend auf Kommentaren)

from collections import defaultdict 

class Distance(object): 

    _conversion_map = defaultdict(lambda: {'to' : None, 'from' : None}) 

    def __init__(self, **kwargs): 
     self._memo = {} 
     if kwargs: 
      unit, value = kwargs.iteritems().next() 
      if unit == 'inches': 
       self.inches = value 
      else: 
       setattr(self, unit, value) 
     else: 
      self.inches = 0 

    def __getattr__(self, name): 
     if name in self._conversion_map: 
      try: 
       return self._memo[name] 
      except KeyError: 
       converter = self._conversion_map[name]['to'] 
       if converter is None: 
        raise AttributeError 
       converted = converter(self.inches) 
       self._memo[name] = converted 
       return converted 
     else: 
      raise AttributeError 

    def __setattr__(self, name, value): 
     if name == '_memo': 
      super(Distance, self).__setattr__(name, value) 
     else: 
      # Clear memoized values if setting the value of the object 
      self._memo = {} 
     if name == 'inches': 
      super(Distance, self).__setattr__(name, value) 
     if name in self._conversion_map: 
      converter = self._conversion_map[name]['from'] 
      if converter is None: 
       raise AttributeError 
      self._memo[name] = value 
      self.inches = converter(value) 
     else: 
      raise AttributeError 

    @classmethod 
    def converter(cls, func): 
     direction, unit = func.__name__.split('_', 1) 
     cls._conversion_map[unit][direction] = func 
     return func 

@Distance.converter 
def to_feet(value): 
    return value/12 

@Distance.converter 
def from_feet(value): 
    return value * 12 

board_1_length = Distance(feet=2) 
board_2_length = Distance(inches=14) 
board_1_length.inches # 24 
board_2_length.feet # 1 (integer division) 
+0

Für meine Anwendung bin ich weniger geneigt, diese Technik zu verwenden (obwohl möglich). Der Fehler war in meinem übermäßig einfachen Beispiel. Das Problem ist, dass die Konvertierung zwischen Einheiten langsam und im Wesentlichen eine Art ist ... in meinem speziellen Fall würde es Formen als Vektordaten stellen und als ein Feld von Graustufen in anderen darstellen (dh SVG gegen BMP). –

+0

Sie könnten diese Art von Muster mit einem Caching-System kombinieren, so dass die vollständige Konvertierung nur beim ersten Mal erfolgt (obwohl immer noch träge), dann wird die zwischengespeicherte konvertierte Struktur danach zurückgegeben. –