2011-05-21 14 views
7

¿Puedo agregar atributos de forma dinámica a las instancias de una clase de nuevo estilo (una derivada de object)?Python: agregue dinámicamente atributos a la clase de estilo nuevo/obj

Detalles:

que estoy trabajando con una instancia de sqlite3.Connection. Simplemente extender la clase no es una opción porque no obtengo la instancia llamando a un constructor; Lo entiendo llamando al sqlite3.connect().

Crear un contenedor no me ahorra la mayor parte del código que estoy escribiendo.

Python 2.7.1

Editar

respuestas correctas todos. Pero todavía no estoy alcanzando mi objetivo; Las instancias de barra sqlite3.Connection mis intentos de establecer atributos de las siguientes maneras (como lo hacen las instancias de object sí mismo). Siempre obtengo un AttributeError:

> conn = sqlite3.connect([filepath]) 
> conn.a = 'foo' 
Traceback (most recent call last): 
    File "<pyshell#2>", line 1, in <module> 
    conn.a = 'foo' 
AttributeError: 'object' object has no attribute 'a' 
> conn.__setattr__('a','foo') 
Traceback (most recent call last): 
    File "<pyshell#2>", line 1, in <module> 
    conn.__setattr__('a','foo') 
AttributeError: 'object' object has no attribute 'a' 

¿Ayuda?

+0

Puede examinar el __dict__ real para averiguar qué está usando sqlite3. Pero eso podría ser una rutina C, en cuyo caso se verá obligado a envolverlo de alguna manera. –

+1

+1. Incluso 'objeto.__setattr __ (conn, 'a', 'foo') 'aumenta AttributeError. ¡Interesante pregunta! – EOL

Respuesta

5

Sí, a menos que la clase esté usando __slots__ o evite la escritura de atributos anulando __setattr__, o una clase interna de Python, o una clase de Python implementada de forma nativa (generalmente en C).

Siempre puede intentar establecer un atributo. Excepto por las implementaciones __setattr__, que son muy raras, la asignación de un atributo a una instancia de una clase de uno de los tipos mencionados anteriormente debería generar un AttributeError. En estos casos, tendrá que utilizar un envoltorio, así:

class AttrWrapper(object): 
    def __init__(self, wrapped): 
    self._wrapped = wrapped 
    def __getattr__(self, n): 
    return getattr(self._wrapped, n) 
conn = AttrWrapper(sqlite3.connect(filepath)) 
+0

Veo ahora que está en lo cierto, pero no funciona para instancias de sqlite3.Connection o 'object'. (Ver edición arriba.) ¿Alguna ayuda? – JellicleCat

+0

@JellicleCat Ambos se incluyen en la "clase interna de Python". Extendí la respuesta con un envoltorio. Mencionaste usar uno en la pregunta; pero no estoy seguro de por qué no resolvería el problema. Si este contenedor no funciona, amplíe su pregunta (o comentario aquí) con un escenario en el que falle. – phihag

-1

La palabra mágica aquí es "parche de monos". Aquí está an SO answer con ejemplos.

+0

El parche de mono generalmente significa cambiar todas las instancias de una clase. Parece que el JellicleCat solo quiere cambiar las propiedades de una instancia específica. – phihag

+0

Esto es realmente hacia el punto, Charlie, así que gracias. Aún así, no me supera el problema donde me dejan mis propios dispositivos y las otras dos respuestas. – JellicleCat

2

experimentación simple:

In []: class Tst(object): pass 
    ..: 
In []: t= Tst() 
In []: t.attr= 'is this valid?' 
In []: t.attr 
Out[]: 'is this valid?' 

Así que, de hecho, parece ser posible hacer eso.

Actualización:
Pero desde el documentation:SQLite es una biblioteca de C que ..., por lo que parece que realmente necesita para envolverlo.

+0

Veo ahora que está en lo cierto, pero no funciona para instancias de sqlite3.Connection o 'object'. (Ver edición arriba.) ¿Alguna ayuda? – JellicleCat

+0

@JellicleCat: Actualizado mi respuesta. – eat

0
conn.a = 'foo', 

o cualquier asignación dinámica es válida, si conn es

<type 'classobj'>. 

Cosas como:

c=object() 
    c.e=1 

generará un error de atributos. Por otro lado: Python le permite hacer una fantástica programación de Metaclass:

>>>from new import classobj 
    >>>Foo2 = classobj('Foo2',(Foo,),{'bar':lambda self:'bar'}) 
    >>>Foo2().bar() 
    >>>'bar' 
    >>>Foo2().say_foo() 
    >>>foo 
Cuestiones relacionadas