2009-06-29 8 views
8

me preguntan si es posible mantener métodos para una clase de Python en un archivo diferente de la definición de clase, algo como esto:métodos de importación para recibir una clase 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 

En mi caso, to_import_from.py se genera en máquina, y contiene muchos métodos. Prefiero no copiar y pegar éstos en main_module.py o importarlos uno por uno, pero tener a todos ellos reconocidos como métodos de la clase de instrumento, al igual que si se hubieran definido allí:

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

Gracias!

+0

¿Controla la generación de to_import_from.py, o tiene que usarla "tal cual"? – itsadok

+0

Sí, puedo controlarlo un poco ajustando el código de ctypeslib. –

Respuesta

7

No creo que lo que desee sea directamente posible en Python.

Sin embargo, puede intentar uno de los siguientes.

  1. Cuando genere to_import_from.py, agregue las cosas no generadas allí también. De esta manera, todos los métodos están en la misma definición de clase.
  2. Have to_import_from.py contiene una definición de clase base que hereda la clase de instrumento .

En otras palabras, en to_import_from.py:

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

y luego en main_module.py:

import to_import_from 

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

La opción 2 parece ser la solución que necesito. ¡Muchas gracias! –

3

Siento que esto es una especie de "You shouldn't be putting nails in the wall" answer, pero que se está perdiendo la punto de las definiciones de clase de python. Usted no debe poner la clase con todos sus métodos en su propio archivo de pitón, y en su subclasificación main_module.py hacer

from instrument import Instrument 

Si usted planea usar los métodos de varias clases, usted debe considerar. En su caso, el archivo generado por la máquina podría contener la clase base heredada de Instrument.

Finalmente, proporcione a su clase una buena carpeta de documentos que explique la API a su usuario, por lo que no es necesario utilizar un "archivo de encabezado" como resumen de su clase.

4

se puede hacer esto con el método __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

Lo que estás haciendo está extendiendo una clase base con un poco de " código generado por la máquina.

Elección 1. Amplíe una clase base con el código generado por la máquina.

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

su aplicación, entonces import machine_generated y puede utilizar machine_generated.Instrument_Implementation.

Opción 2. Simplemente use las funciones de primera clase.

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

su aplicación puede utilizar import main_module y main_module.Instrument.

6

Es más fácil de lo que piensa:

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 

Hecho!

Aunque generar el código generado por la máquina genera una definición de clase y crear una subclase a partir de ella sería una solución más ordenada.

0

Aquí está mi intento. Creo que un enfoque mejor podría hacerse con metaclases ...

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) 

cuando se ejecuta este código

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

aquí está la salida:

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

Técnicamente, sí, esto es posible, pero solucionarlo de esta manera no es realmente una pitón idiomática, y es probable que haya mejores soluciones. Aquí está un ejemplo de cómo hacerlo:

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) 

Eso importará todas las funciones definidas en la que se puede llamar to_import_from como métodos de la clase Instrument, así como la adición de algunos métodos más. Nota: si también desea copiar variables globales como variables de instancia, deberá refinar la verificación. También tenga en cuenta que añade todos los objetos que se puede llamar que encuentra en el espacio de nombres to_import_from, incluyendo las importaciones de otros módulos (es decir, from module import some_func importaciones de estilo)

Sin embargo, esto no es una terriblemente buena manera de hacerlo. Mejor sería ajustar la generación de tu código a producir una clase, y que tu clase herede de ella. Esto evita la copia innecesaria de métodos en el espacio de nombres del Instrumento, y en su lugar utiliza la herencia normal. es decir:

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

Parece que la gente piensa demasiado en esto. Los métodos son solo variables locales con valores de función en el ámbito de construcción de clases.Entonces, lo siguiente funciona bien:

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

SintaxisAdvertencia: importación * solo permitida en el nivel de módulo –

+2

+1 Aunque * sea incorrecto, es una sugerencia excelente y limpia. – thethinman

+1

Esta debería ser la respuesta. – bgusach

Cuestiones relacionadas