2014-02-19 8 views
11

Ich habe ein Python-Modul, das eine Reihe von Klassen enthält, die jeweils ein bestimmtes physikalisches Material mit seinen Eigenschaften (z. B. Dichte, spezifische Wärme) darstellt. Einige der Eigenschaften sind nur float Mitglieder der Klasse, aber viele hängen von einem Parameter ab, z. B. der Temperatur. Ich implementiert dies durch @staticmethod s, dh alle Klassen aussehenModul mit Klassen mit nur statischen Methoden

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): 
    ... 

... 

Die Class es somit lediglich als Container fungieren für alle Daten, und die Fülle der @staticmethod s hat mir den Verdacht, dass es eine mehr sein geeignetes Designmuster für diesen Anwendungsfall.

Irgendwelche Hinweise?

+0

Wenn es statisch ist ... bedeutet das, dass es im Grunde feste Werte sind. Wenn dies der Fall ist, handelt es sich tatsächlich um Daten, die besser als herkömmliche Datenstrukturen behandelt werden können. Wörterbuch, wenn Sie es live erstellen möchten, etwas wie xml/yaml, wenn Sie von der Festplatte laden möchten. Ich habe sogar einmal eine Reihe von Klassen geschrieben, die ein XML laden und es als Attribute offenlegen, so dass Sie immer noch Dinge wie "metals.copper.magnetic_permeability * 4" tun können, obwohl 'metals' aus einem XML geladen wurde. so etwas könnte Ihnen das Beste aus beiden Welten geben ... –

+1

Aber die Eigenschaften sind abhängig von der Temperatur etc. –

+0

staticmethod scheint eigentlich ganz angemessen. –

Antwort

3

Sie könnten Ihr Modul copper benennen und alle diese als Funktionen auf Modulebene erstellen, dann import copper; copper.density(0).

Aber was, wenn jemand tut from copper import density, und Sie auch ein Modul cobalt und andere carbon und andere chlorine usw. genannt genannt genannt haben, alle mit ihren eigenen density Funktionen? Oh oh.

Seit we're all consenting adults here können Sie dies dokumentieren und erwarten, dass Ihre Benutzer gut genug wissen, um nur das Modul zu importieren. Oder Sie können Ihren Ansatz nehmen; In diesem Fall würde ich in Betracht ziehen, alle Ihre Elemente in ein Modul namens elements zu setzen, dann kann der Benutzer . Statische Methoden wären dann angebracht.

+0

Kann die '__all__'-Variable auf Modulebene den Benutzern nicht helfen, Dinge nicht ordnungsgemäß zu importieren? –

+0

@ CédricVanRompay Ich glaube nicht, dass ich sehe, wie '__all__' Leute davon abhalten würde, beim Importieren von Dateien zu blocken. Kannst du es ausarbeiten? – 2rs2ts

1

Dies ist wirklich eine Frage "Saison nach Geschmack". Sie könnten tun, was Sie getan haben - Methoden für eine Klasse ODER Sie könnten die Klasse komplett eliminieren und einfach mit Funktionen auf Modulebene gehen. Im Allgemeinen bevorzuge ich das, was einfacher zu lesen/zu verstehen ist & beizubehalten.

Basiert streng auf dem begrenzten Beispiel, das Sie geteilt haben - ich lehne mich den Funktionen auf Modulebene zu. Aber natürlich könnte ein konkreteres Beispiel diese Meinung ändern.

+0

Das Codebeispiel sollte jetzt ein vollständigeres Verständnis der Dateiinhalte geben. –

1

Das Definieren einer statischen Methode ist praktisch immer ein Fehler. Python hat Funktionen, also würden Sie immer nur eine Funktion auf Modulebene definieren. (Sie würden copper.py haben und in der es eine einfache alte def density(T): stattdessen eine static zu verwenden.)

Das heißt, copper.py würde aussehen wie

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 ... 

In diesem speziellen Fall, Hast du eigentlich mehrere Materialien? Wenn ja, dann möchten Sie wahrscheinlich, dass es sich um Instanzen handelt, nicht um Klassen oder Module. Wenn Sie beispielsweise nicht möchten, dass alle dieselbe rationale kubische Form für die thermische Dichteabhängigkeit haben, können Sie eine Unterklasse erstellen und eine Instanz davon haben, oder Sie können eine Klasse erstellen, die Funktionen als Argumente akzeptiert.

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 
) 

können Sie auch eine Metaklasse machen, wenn Sie einen deklarativen Stil pflegen wollen.


Durch die Art und Weise

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

wahrscheinlich nicht tut, was Sie wollen. Dies macht magnetic_permeability nur in einer Instanz von copper zugänglich. Ich nicht empfehlen Klassen anstatt Instanzen oder Module für dieses, aber wenn Sie getan haben, würden Sie tun müssen, um

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

der Lage sein, Copper.magnetic_permeability


Hinweis zu tun, dass Ich erben mit Objekt, so dass wir Python 2 "neue Stilklassen" verwenden. Die Änderungen sind subtil, aber es ist schöner, wenn Sie nur sicherstellen, dass Sie nie auf sie stoßen werden.

+0

Danke für den Hinweis über 'Objekt'. Ich habe das Beispiel in der Frage entsprechend korrigiert. –

1

Wie wäre es mit den Variableneigenschaften Funktionen, die alle erforderlichen Werte als Argumente nehmen?

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> 

Dann könnten die festen Eigenschaften über ein Wörterbuch definiert werden.

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

Sie würden dies auf folgende Weise verwenden:

copper_some_other_property = some_other_property(T, copper.magnetic_permeability) 
4

Ich vermute, dass eine passendere Struktur eine Material Klasse haben würde, die entweder Funktionen oder Koeffizienten als Argument übernimmt, zum Beispiel

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))) 

Jedes Material liefert dann seine eigene Koeffizienten für jeden berechneten Parameter:

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

Wenn Sie komplexere Beziehungen (zB verschiedene Berechnungen) müssen Sie die Unterklassen von Material und Überlastungs- nutzen könnten geeignete Berechnungen.

+0

Gut - hier in der Abstraktion aufzusteigen ist angebracht. – wim

+0

Mit einer Methode namens "Dichte", wenn Sie eine Variable übergeben auch "Dichte" zu "__init__" genannt (das ist wirklich ein Tupel von Koeffizienten in einigen Berechnung der Dichte verwendet), ist aber irgendwie eine verrückte Schnittstelle! – wim

+0

Guter Punkt, ich werde das Argument umbenennen – jonrsharpe