2014-02-19 5 views
11

У меня есть модуль Python, который содержит несколько классов, каждый из которых представляет определенный физический материал со своими свойствами (например, плотность, удельная теплоемкость). Некоторые из свойств - это только float членов класса, но многие зависят от некоторого параметра, например от температуры. Я реализовал это через @staticmethod с, т.е. все классы похожимодуль с классами только с статическими методами

class Copper(object): 
    magnetic_permeability = 1.0 

    @staticmethod 
    def density(T): 
     return 1.0/(-3.033e-9 + 68.85e-12*T - 6.72e-15*T**2 + 8.56e-18*T**3) 

    @staticmethod 
    def electric_conductivity(T, p): 
     return 1.0141 * T**2 * p 

    @staticmethod 
    def specific heat(T): 
     return ... 


class Silver(object): 
    ... 

class Argon(object): 
    ... 

... 

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

Любые подсказки?

+0

Если это статическое ... это означает, что это в основном фиксированные значения. Если это так, это действительно данные и, возможно, лучше обрабатываются как более традиционная структура данных. словарь, если вы хотите создать его в прямом эфире, что-то вроде xml/yaml, если вы хотите загрузить, если с диска. Я даже написал набор классов, которые будут загружать XML и выставлять его в качестве атрибутов, поэтому вы все равно можете делать такие вещи, как 'metals.copper.magnetic_permeability * 4', даже если« металлы »были загружены из XML. что-то подобное может дать вам лучшее из обоих миров ... –

+1

Но свойства зависят от температуры и т. д. –

+0

staticmethod на самом деле кажется вполне уместным. –

ответ

3

Вы можете назвать свой модуль copper и создать все это как функции уровня модуля, затем import copper; copper.density(0).

Но что, если кто-то делает from copper import density, и вы также модуль называется cobalt, а другой называется carbon, а другой называется chlorine и т.д., все со своими собственными density функциями? О, о.

С we're all consenting adults here вы можете документировать это и ожидать, что ваши пользователи будут знать достаточно хорошо, чтобы импортировать только модуль. Или вы можете принять ваш подход; в этом случае я бы рассмотрел возможность размещения всех ваших элементов в одном модуле под названием elements, тогда пользователь может from elements import Copper. Тогда были бы целесообразными статические методы.

+0

На самом деле, не может ли переменная уровня модуля '__all__' помочь пользователям не импортировать материал неправильно? –

+0

@ CédricVanRompay Я не думаю, что вижу, как «__all__» помешает людям затенять материал при импорте. Можете ли вы уточнить? – 2rs2ts

1

Это действительно «сезон по вкусу». Вы могли бы сделать так, как вы это делали, - методы класса или вы могли полностью исключить класс и просто пойти с функциями уровня модуля. В общем, я предпочитаю, чтобы было проще читать/понимать &.

Основываясь на ограниченном примере, который вы поделили, я наклоняюсь к функциям уровня модуля. Но, конечно, более сложный пример может изменить это мнение.

+0

Пример кода теперь должен дать более полное представление о содержимом файла. –

1

Определение статического метода практически всегда является ошибкой. Python имеет функции, поэтому вы всегда просто определяете функцию уровня модуля. (Вы должны были бы copper.py и внутри него есть обычный старый def density(T): вместо использования STATICMETHOD.)

То есть, copper.py будет выглядеть

magnetic_permeability = 1.0 

def density(T): 
    return 1.0/(-3.033e-9 + 68.85e-12*T - 6.72e-15*T**2 + 8.56e-18*T**3) 

def electric_conductivity(T, p): 
    return 1.0141 * T**2 * p 

def specific heat(T): 
    return ... 

В данном конкретном случае, у вас на самом деле есть несколько материалов? Если это так, то вы, вероятно, хотите, чтобы они были экземплярами, а не классами или модулями. Если вы, например, не хотите, чтобы все они имели одну и ту же рациональную кубическую форму для зависимости тепловой плотности, вы можете сделать подкласс и иметь экземпляр этого, или вы можете создать класс, который принимает функции в качестве аргументов.

class Material(object): 
    def __init__(self, density, electric conductivity): 
     self.density = density 
     self.electric_conductivity = electric_conductivity 

copper = Material(
    density=lambda T: 1.0/(-3.033e-9 + 68.85e-12*T - 
          6.72e-15*T**2 + 8.56e-18*T**3), 
    electric_conductivity=lambda T, p: 1.0141 * T**2 * p 
) 

Вы также можете создать метакласс, если хотите сохранить декларативный стиль.


Кстати

class Copper(): 
    def __init__(self): 
     self.magnetic_permeability = 1.0 
    ... 

, вероятно, не делать то, что вы хотите. Это делает magnetic_permeability доступным только для экземпляра of copper. Я не рекомендую использовать классы, а не экземпляры или модули для этого, но если вы сделали, вы должны были бы сделать

class Copper(object): 
    magnetic_permeability = 1.0 
    ... 

, чтобы быть в состоянии сделать Copper.magnetic_permeability


Обратите внимание, что Я наследую объект, чтобы использовать Python 2 «классы нового стиля». Изменения тонкие, но лучше, если вы просто убедитесь, что никогда не столкнетесь с ними.

+0

Спасибо за подсказку о 'object'. Я исправил пример в вопросе соответственно. –

1

Как получить свойства переменных, которые принимают все необходимые значения в качестве аргументов?

def density(T): 
    <some function of T> 

def electrical_conductivity(T, p): 
    <some function of T and p> 

def some_other_property(T, magnetic_permeability): 
    <some function of T and magnetic permeability> 

Затем фиксированные свойства могут быть определены через словарь.

copper_fixed_properties = {'magnetic_permeability': 1, ...} 

Вы могли бы использовать это следующим образом:

copper_some_other_property = some_other_property(T, copper.magnetic_permeability) 
4

Я подозреваю, что более уместно структура будет иметь Material класс, который принимает либо функции или коэффициенты в качестве аргументов, например

class Material(object): 

    def __init__(self, mag_perm, density_coeffs, ...): 
     self.mag_perm = mag_perm 
     self._density_coeffs = density_coeffs 
     ... 

    def density(self, T): 
     x0, x1, x2, x3 = self._density_coeffs 
     return 1.0/(x0 + (x1 * T) + (x2 * (T ** 2)) + (x3 * (T ** 3))) 

Каждый материал затем подают свои собственные коэффициенты для каждого расчетного параметра:

copper = Material(1.0, (-3.033e-9, 68.85e-12, 6.72e-15, 8.56e-18), ...) 
copper.density(300) 

Если вам нужно более сложных отношения (например, различные расчеты), вы могли бы использовать подклассы Material и над ТЕПЛОВОЙ НАГРУЗКОЙ соответствующие расчеты.

+0

Хорошее выравнивание в абстракции подходит здесь. – wim

+0

Имея метод под названием «плотность», когда вы передаете переменную, также называемую «плотность» на '__init__' (которая действительно является кортежем коэффициентов, используемых при некотором вычислении плотности), является своего рода безумным интерфейсом! – wim

+0

Хорошая точка, я переименую аргумент – jonrsharpe

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