2015-04-16 6 views
13

Nehmen wir an, ich habe viele Funktionen in alotoffunc.py, die von mehr als 1 Objekttyp verwendet wird.Erstellen von Klassen mit vielen importierten Funktionen hier und da

Sagen wir ObjectI und ObjectII und ObjectXI alle einige Funktionen in alotoffunc.py verwendet. Und jedes Objekt verwendete verschiedene Funktionen, aber alle Objekte haben die Variable object.table.

alotoffunc.py:

def abc(obj, x): 
    return obj.table(x) * 2 

def efg(obj, x): 
    return obj.table(x) * obj.table(x) 

def hij(obj, x, y): 
    return obj.table(x) * obj.table(y) 

def klm(obj, x, y): 
    return obj.table(x) *2 - obj.table(y) 

Und dann importiere ich die Funktionen und überlasten sie:

import alotoffunc 

class ObjectI: 
    def abc(self, x): 
    return alotoffunc.abc(self, x) 

    def efg(self, x): 
    return alotoffunc.efg(self, x) 

class ObjectII: 
    def efg(self, x): 
    return alotoffunc.efg(self, x) 
    def klm(self, x, y): 
    return alotoffunc.klm(self, x, y) 

class ObjectXI: 
    def abc(self, x): 
    return alotoffunc.abc(self, x) 
    def klm(self, x, y): 
    return alotoffunc.klm(self, x, y) 

Es sieht wie ein großes Durcheinander jetzt, wie soll ich mich über meine Objektklasse zu bauen und organisieren meine alotoffunc.py?

+3

Es sieht nicht wie ein Chaos für mich aus. Wenn es Sie stört, können Sie eine Basisklasse haben, die alle Methoden implementiert und dann die unnötigen überschreibt, um einen "NotImplementedError" in den Unterklassen zu erzeugen oder Methodengruppen zu Mixins zu konsolidieren. – Selcuk

+0

Ich stimme Selcuk zu. Was du getan hast, sieht vernünftig aus. Subclassing kann die Menge an Code leicht reduzieren, kann aber auch die Übersichtlichkeit beeinträchtigen, da Sie nicht gewünschte Funktionen überschreiben würden, anstatt Funktionen hinzuzufügen, die Sie möchten. – Vorticity

+0

mixins hört sich gut an, aber die Kontrolle von Polymorphie könnte mir später Kopfschmerzen bereiten, irgendwelche Hinweise, wie ich damit umgehen soll, nachdem ich Mixins benutzt habe? – alvas

Antwort

6

(1) Sie können eine Basisklasse haben, die alle Methoden implementiert und dann die unnötigen überschreibt, um eine NotImplementedError in den Unterklassen zu erzeugen.

(2) Sie können Mixins müssen Wiederholung reduzieren:

import alotoffunc 

class MixinAbc: 
    def abc(self, x): 
     return alotoffunc.abc(self, x) 

class MixinEfg: 
    def efg(self, x): 
     return alotoffunc.efg(self, x) 

class MixinKlm: 
    def klm(self, x, y): 
     return alotoffunc.klm(self, x, y) 

class ObjectI(MixinAbc, MixinEfg): 
    pass 

class ObjectII(MixinEfg, MixinKlm): 
    pass  

class ObjectXI(MixinAbc, MixinKlm): 
    pass 

Sie können diese Methode auch kombinieren mit der @cpburnz.

3

Sie könnten tun:

from alotoffunc import * 

Und dann, wenn -für Beispiel- wir haben die Variablen o1, o2, die Instanzen von Object1 und Object2 sind, was wir tun können:

abc(o1,x) 
efg(o2,x) 
... 

Es ist nicht so 'hübsch' wie der OO-Ansatz, o1.abc (x) aufzurufen, aber es ist so viel wartbar, als alle Methoden überschreiben zu müssen.

Was die from ___ import * tut ist, Sie von der Verwendung des Paketnamens wie alotoffunc.abc und so weiter zu befreien.

bearbeiten

Als @JamesKing Kommentare, ist diese Lösung nicht funktionieren, wenn Sie eine Funktion mit dem gleichen Namen innerhalb der Klassen haben. Da sie unbrauchbar erscheinen - sie nennen einfach die importierten Funktionen - dachte ich daran, sie zu entfernen. Wenn das mit Ihrem Code nicht funktioniert, sollten Sie from ___ import ___ as ___ wie er sagte verwenden.

+0

Schauen Sie genauer hin. Die Funktion innerhalb der Klasse hat denselben Namen wie die importierte Funktion. Vielleicht 'von ... importieren ... als ...' –

+0

Das ist wahr, aber es sieht so aus, als ob er nur diese Funktionen erstellt, um die importierten zu verwenden. In meiner Lösung dachte ich daran, diese Funktionen aus der Klasse zu entfernen. Ich werde meine Antwort bearbeiten, um das klarzustellen! –

+0

Das Problem ist, dass ich nicht will, dass "ObjectII" 'abc()' tut. Indem ich alles importiere, löst es die Kodierungsredundanz auf, aber später habe ich mich damit beschäftigt, dass Benutzer alles aufrufen, was sie wollen, auch wenn das Objekt es nicht erlaubt. Trotzdem ist es eine Lösung. – alvas

5

Die einfachste Möglichkeit besteht darin, die gewünschten Funktionen direkt als Instanzmethoden an eine Klasse in ihrer Definition zu binden. Beachten Sie, dass jede Funktion self als das erste Argument erhält.

import alotoffunc 

class ObjectI: 
    abc = alotoffunc.abc 
    efg = alotoffunc.efg 

class ObjectII: 
    efg = alotoffunc.efg 
    klm = alotoffunc.klm 

class ObjectXI: 
    abc = alotoffunc.abc 
    klm = alotoffunc.klm 

Dies kann zu definieren Verwechslung in Klassen ein einfacherer Ansatz, wenn es nicht eine klare, logische Gruppierung für die verschiedenen Funktionen ist. Die Gruppierung hängt jedoch von Ihrem Anwendungsfall ab, daher kann der Mix-In-Ansatz je nach Situation besser sein.

5

Wenn ich wollte Mixins vermeiden, vielleicht um die Opazität meines Codes zu minimieren, würde ich es wie folgt aus:

class ObjectI: 
    from alotoffunc import abc, efg 

class ObjectII: 
    from alotoffunc import efg, klm 

class ObjectXI: 
    from alotoffunc import abc, klm 

Die importierten Methoden automatisch gebunden bekommen, wenn Sie Instanzen der Klasse erstellen . Mit anderen Worten, sie sind standardmäßig Instanzmethoden.

Falls Sie sie statische Methoden sein, verwenden staticmethod wie folgt:

class ObjectI: 
    from alotoffunc import abc, efg 
    abc = staticmethod(abc) 

Auch würde ich mich über Performance-Probleme keine Sorgen zu viel von diesen mehrere Import-Anweisungen, die, weil Python intelligent genug ist, um Führen Sie ein importiertes Modul nur einmal aus und speichern Sie es im Speicher, falls es später benötigt wird.

Wenn die Funktionen, die Sie importieren möchten, eine Art von logischen Gruppierungen haben, dann sollten Sie entweder Mixins verwenden oder die Funktionen in separaten "Mixin-Modulen" organisieren, so dass Sie vielleicht sogar from mixinmodule import * tun können. Für den Mix-in-Klasse Ansatz halte ich die reguläre Import-Anweisung für besser als den from-Import, es sei denn, Ihre Funktionsnamen sind sehr lang und Sie möchten sie nur einmal eingeben!

3

Dies ist ein "Fabrik" -Ansatz. Könnte über kompliziert sein, wenn Sie nicht so viele Funktionen haben, aber wenn Sie wirklich "viel" haben, könnte es funktionieren.

import alotoffunc 

class Builder(object): 
    def __init__(self, objtype): 
     objtypes = { 'ObjectI': ['abc', 'efg'], 
        'ObjectII': ['efg', 'klm'], 
        'ObjectXI': ['abc', 'klm']} 

     for func in objtypes[objtype]: 
      self.__dict__[func] = getattr(alotoffunc, func) 
+0

cool, ich dachte nicht, dass 'getattr()' könnte so verwendet werden. – alvas

3

Wie wäre es damit:

import alotoffunc 
import types 

class ObjectI: 
    def __init__(self): 
     setattr(self, abc, types.MethodType(alotoffunc.abc, self)) 
     setattr(self, efg, types.MethodType(alotoffunc.efg, self)) 

class ObjectII: 
    def __init__(self): 
     setattr(self, efg, types.MethodType(alotoffunc.efg, self)) 
     setattr(self, klm, types.MethodType(alotoffunc.klm, self)) 

class ObjectXI: 
    # ... 

(Es könnte einige Fehler oder Tippfehler sein, aber die Grundidee ist richtig ich etwas ähnliches in meinem Code verwenden

Dies bindet das Original.. Funktionen für jede Instanz bei der Erstellung. setattr() ist nicht notwendig, aber ich bevorzuge dies, um zu signalisieren, dass dort etwas "Magie" passiert.

Ich bin ziemlich sicher, es gibt eine bessere Möglichkeit, das Meth zu erstellen ods im Klassenobjekt, aber dies könnte Metaklassen und/oder mehr Magie erfordern.

1

Ich denke, ein sauberer Weg, um Ihr Ziel zu erreichen, ist die Verwendung der Mehrfachvererbung von Python. Viele Programmierer hassen MI und behaupten, dass es chaotischen Code produziert oder dass es schwer zu pflegen ist. Solange Sie bei der Planung Ihres Unterrichts vorsichtig sind, kann die Verwendung von MI sehr hilfreich sein.

One of the many links returned by Google

SomeClasses.py - Normalerweise jede Klasse ist Speicher in einer separaten Datei.

TheProject.py - Es ist kein zusätzlicher Code erforderlich, es sei denn, Sie müssen die Funktionalität der Basisklassen überschreiben.

Natürlich ist dies ein triviales Beispiel, bei dem jede Basisklasse nur eine einzige Funktion hat. Ein echtes Beispiel, das einem einfällt, ist das Packen von Bildern auf eine gemeinsame Texturressource. Sie möchten die Funktionalität, die PIL.Image kommt, aber in der Lage sein, die Bilder als Blattknoten in einer selbstgebrauten Baumdatenstruktur zu speichern. Sie können die Mehrfachvererbung verwenden, um die Methoden beider Klassen mit minimalem Code zu erhalten. LeafImage würde alle Methoden beider Klassen haben, und wenn Sie sich entscheiden, TreeLeaf zu ändern, wird kein zusätzlicher Code in LeafImage benötigt.

class LeafImage (PIL.Image, TreeLeaf): 
    pass 
Verwandte Themen