2014-02-11 4 views
8

Во-первых, когда я спрашиваю об элементах, я имею в виду единицы измерения, такие как дюймы, футы, пиксели, ячейки. Я не имею в виду типы данных, такие как int и float.Соглашение Python для обозначения переменных для обозначения единиц

Wikipedia относится к этому как логического типа данных, а нетипа физические данные.

Я хотел бы знать, как лучше всего использовать переменные.

Вот код, чтобы пройти через то, что я спрашиваю:

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

Обратите внимание, что эти оба целые числа (или поплавки, я не забочусь), но я изменил единицы. Я также сохранил имя переменной одинаково. Я мог бы создать конвенцию, и это цель этого вопроса. Без руководства я мог бы сделать что-то вроде этого:

board_length=8 
board_length_inches=8*12 

Я бы счел это случайным способом делать вещи. Или, я мог бы установить соглашение:

Fboard_length=8 
Iboard_length=8*12 

Или другие варианты, которые мне в равной степени не нравятся. Как я могу назвать переменные описательным образом, но остаюсь как можно ближе к PEP-08?

Просто чтобы быть ясно, как я могу, переменные могут иметь различные типы данных, но эти подразделения будут одни и те же (в дюймах будет иметь тот же именование, независимо от того, если он был сохранен, как и целое число или число с плавающей точкой)

+0

В зависимости от того, сколько единиц относится к вашему сценарию, вы можете рассмотреть возможность создания подклассов типов на основе каждого устройства. Каждая «единица измерения» (длина, вес и т. Д.) Имела бы свой класс, который наследует встроенные типы и имеет свои собственные подклассы для отдельных единиц. Тогда эти единицы будут иметь методы для преобразования ко всем другим единицам того же типа.Это была бы большая работа, поэтому вам нужно спросить, действительно ли это стоит – wnnmaw

+0

Или вы можете украсить встроенные функции, чтобы иметь атрибут или метод, который отслеживает единицы – wnnmaw

+1

. Я бы не стал слишком беспокоиться об этом. Я не могу думать о каких-либо случаях, когда вам нужно будет хранить одно и то же значение в разных единицах в течение продолжительных периодов времени. Я бы просто сделал это: 'board_length = 24 # в дюймах' (несколько строк позже)' print (to_feet (board_length)) 'или' FEET = 12; печать (board_length * Лапа) '. – rlms

ответ

1

Я бы пошел дальше и имел отдельные типы объектов, обеспечивающие безопасность типа, а не просто полагающиеся на соглашения об именах. В противном случае вы можете передать переменную, представляющую дюймы, в метод, требующий миль.

Я думаю, что, опираясь на именование будет проблематично поддерживать длительный срок и сделать использование типов даст вам гораздо больше гибкости и безопасности (например, обеспечивающее преобразование и т.д., встроенное в типы объектов)

+0

Это хороший совет. Если цель соглашения об именах заключается в том, чтобы помочь разработчику избежать путаницы и ошибок - вы получите намного больше, позволяя системе класса Python применять правила для вас. Если вы используете только соглашение об именах, запутанный разработчик может легко делать что-то вроде 12 дюймов + 1 (см) = 13 (oops). –

+0

Я собираюсь принять этот ответ, даже если он не предлагает соглашение об именах, он предлагает альтернативу, которая будет работать для других, заинтересованных в этом вопросе. Спасибо. –

2

Если вам нужна более надежная поддержка устройства, вы должны проверить PyPi's Pint module. Он не имеет прямого отношения к вашему вопросу об именовании, но может потребоваться большая часть работы с частыми преобразованиями. Вы можете найти информацию о нем и некоторых других модулях единицы здесь:

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

+0

Мне нравится это предложение в целом и кажется хорошим способом существенно реализовать то, что предложил @BrianAgnew. –

9

В то время как вы могли бы придумать именование, вы могли бы лучше строить объект, представляющий «расстояние» со свойствами для чтения/пишите в разных единицах. Например:

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 

Вы даже можете сделать его более универсальным, чтобы вы могли легко расширить его с помощью новых преобразований. (Примечание: Отредактировано для того, чтобы оформить заметку на основе комментариев)

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

Для моего применения я менее склонен использовать эту технику (хотя это возможно). Недостаток был в моем чрезмерно простом примере. Проблема в том, что преобразование между единицами является медленным и по существу одним способом ... в моем конкретном случае он будет представлять фигуры как векторные данные несколько раз и как поле серого масштаба в других (то есть SVG против BMP). –

+0

Вы можете комбинировать этот тип рисунка с системой кеширования, поэтому полное преобразование выполняется только в первый раз (хотя и лениво), после чего возвращается кэшированная преобразованная структура. –

Смежные вопросы