2009-06-29 25 views
8

mi chiedo se è possibile mantenere i metodi per una classe Python in un file diverso dalla definizione di classe, qualcosa di simile:metodi Importazione di una classe Python

main_module.py:

class Instrument(Object): 
    # Some import statement? 
    def __init__(self): 
     self.flag = True 
    def direct_method(self,arg1): 
     self.external_method(arg1, arg2) 

to_import_from.py:

def external_method(self, arg1, arg2): 
    if self.flag: 
     #doing something 
#...many more methods 

Nel mio caso, to_import_from.py è generato da computer e contiene molti metodi. Io preferirei non copiare e incollare questi in main_module.py o importare uno per uno, ma li hanno tutti riconosciuti come metodi della classe strumento, proprio come se fossero stati definiti c'è:

>>> instr = Instrument() 
>>> instr.direct_method(arg1) 
>>> instr.external_method(arg1, arg2) 

Grazie!

+0

Sei tu a controllare la generazione di to_import_from.py o devi usarla "così com'è"? – itsadok

+0

Sì, posso controllarlo un po 'modificando il codice di ctypeslib. –

risposta

7

Non penso che ciò che desideri sia direttamente possibile in Python.

Si potrebbe, tuttavia, provare uno dei seguenti.

  1. Quando si genera to_import_from.py, aggiungere anche le cose non generate. In questo modo, tutti i metodi sono nella stessa definizione di classe.
  2. to_import_from.py contiene una definizione di classe base che eredita la classe Instrument .

In altre parole, in to_import_from.py:

class InstrumentBase(object): 
    def external_method(self, arg1, arg2): 
     if self.flag: 
      ... 

e poi in main_module.py:

import to_import_from 

class Instrument(to_import_from.InstrumentBase): 
    def __init__(self): 
     ... 
+2

L'opzione 2 si presenta come la soluzione di cui ho bisogno. Grazie molto! –

3

Mi dispiace che questo è una specie di "You shouldn't be putting nails in the wall" answer, ma ti manca la punto delle definizioni di classe Python. Si dovrebbe piuttosto mettere la classe con tutti i suoi metodi nel proprio file python, e nel vostro main_module.py fare

from instrument import Instrument 

Se si pensa di utilizzare i metodi per diverse classi, si dovrebbe prendere in considerazione la creazione di sottoclassi. Nel tuo caso, il file generato dalla macchina potrebbe contenere la classe base ereditata da Instrument.

Infine, dai alla tua classe una buona docstring che spieghi l'API al suo utente, quindi non c'è bisogno di un "file di intestazione" usato come una panoramica della tua classe.

4

si può fare questo con il metodo __getattr__

external.py

def external_function(arg): 
    print("external", arg) 

main.py:

import external 

class Instrument(object): 
    def __getattr__(self, name): 
     if hasattr(external, name): 
      return getattr(external, name) 
     else: 
      return Object.__getattr__(self, name) 

    def direct_method(self, arg): 
     print("internal", arg) 


i = Instrument() 
i.direct_method("foo") 
i.external_function("foo") 
2

Quello che stai facendo sta estendendo una classe base con un po ' " codice "generato dalla macchina".

Scelta 1. Estendere una classe base con codice generato dalla macchina.

machine_generated.py

# Start of boilerplate # 
import main_module 
class Instrument_Implementation(main_module.Instrument_Abstraction): 
    def direct_method(self,arg1): 
     # End of boilerplate # 
     ...the real code... 

L'applicazione può quindi import machine_generated e utilizzare machine_generated.Instrument_Implementation.

Scelta 2. Utilizzare semplicemente funzioni di prima classe.

machine_generated.py

def external_method(self, arg1, arg2): 
    ...the real code... 

main_module.py

import machine_generated 

class Instrument(object): 
    def direct_method(self,arg1): 
     return machine_generator.external_method(arg1, ...) 

l'applicazione può import main_module e utilizzare main_module.Instrument.

6

E 'più facile di quanto si pensi:

class Instrument(Object): 
    def __init__(self): 
     self.flag = True 
    def direct_method(self,arg1): 
     self.external_method(arg1, arg2) 

import to_import_from 

Instrument.external_method = to_import_from.external_method 

Fatto!

Sebbene il codice generato dalla macchina generi una definizione di classe e una sottoclasse da essa sarebbe una soluzione più ordinata.

0

Ecco il mio tentativo. Penso che un approccio più bello potrebbe essere fatto con metaclassi ...

to_import_from.py:

def external_method(self, arg1, arg2): 
    if self.flag: 
     print "flag is set" 
    else : 
     print "flag is not set" 

instrument.py:

import imp 
import os 
import inspect 
import new 

import pdb 

class MethodImporter(object) : 
    def __init__(self, path_to_module) : 
     self.load_module(path_to_module) 

    def load_module(self, path_to_module) : 
     name = os.path.basename(path_to_module) 
     module_file = file(path_to_module,"r") 
     self.module = imp.load_module(name, module_file , path_to_module, ('','r',imp.PY_SOURCE)) 
     print "Module %s imported" % self.module 
     for method_name, method_object in inspect.getmembers(self.module, inspect.isfunction) : 
      print "adding method %s to %s" % (method_name, self) 
      setattr(self, method_name, new.instancemethod(method_object, self, self.__class__)) 


class Instrument(MethodImporter): 
    def __init__(self): 
     super(Instrument,self).__init__("./to_import_from.py") 
     self.flag = True 
    def direct_method(self,arg1): 
     self.external_method(arg1, arg2) 

quando si esegue questo codice

arg1, arg2 = 1, 2 
instr = Instrument() 
instr.direct_method(arg1) 
instr.external_method(arg1, arg2) 

ecco l'output:

Module <module 'to_import_from.py' from './to_import_from.pyc'> imported 
adding method external_method to <__main__.Instrument object at 0x2ddeb0> 
flag is set 
flag is set 
0

Tecnicamente, sì, questo è possibile, ma risolverlo in questo modo non è veramente un pitone idiomatico, e ci sono probabilmente soluzioni migliori. Ecco un esempio di come farlo:

import to_import_from 

class Instrument(object): 
    locals().update(dict((k,v) for (k,v) in 
        to_import_from.__dict__.iteritems() if callable(v))) 

    def __init__(self): 
     self.flag = True 
    def direct_method(self,arg1): 
     self.external_method(arg1, arg2) 

che consente di importare tutte le funzioni richiamabili definite in to_import_from come metodi della classe Instrument, così come l'aggiunta di ulteriori metodi. Nota: se si desidera copiare anche variabili globali come variabili di istanza, è necessario perfezionare il controllo. Si noti inoltre che aggiunge tutti gli oggetti richiamabili che trova nel namespace di to_import_from, tra cui le importazioni da altri moduli (ad esempio from module import some_func importazioni di stile)

Tuttavia, questo non è un terribilmente bel modo per farlo. Sarebbe preferibile invece modificare la generazione del codice in producendo una classe e ereditarlo dalla classe. Ciò evita l'inutile copia dei metodi nello spazio dei nomi di Instrument e utilizza invece l'ereditarietà normale. es .:

class Instrument(to_import_from.BaseClass): 
    # Add new methods here. 
7

Le persone sembrano pensarci troppo sopra. I metodi sono solo variabili locali valutate a livello funzionale nell'ambito della costruzione di classi.Quindi funziona come segue:

class Instrument(Object): 
    # load external methods 
    from to_import_from import * 

    def __init__(self): 
     self.flag = True 
    def direct_method(self,arg1): 
     self.external_method(arg1, arg2) 
+1

SyntaxWarning: import * consentito solo a livello di modulo –

+2

+1 Anche se * è sbagliato, è un suggerimento eccezionale. – thethinman

+1

Questa dovrebbe essere la risposta. – bgusach

Problemi correlati