Jellicle
Jellicle

Reputation: 30216

Python: dynamically add attributes to new-style class/obj

Can I dynamically add attributes to instances of a new-style class (one that derives from object)?

Details:

I'm working with an instance of sqlite3.Connection. Simply extending the class isn't an option because I don't get the instance by calling a constructor; I get it by calling sqlite3.connect().

Building a wrapper doesn't save me much of the bulk for the code I'm writing.

Python 2.7.1

Edit

Right answers all. But I still am not reaching my goal; instances of sqlite3.Connection bar my attempts to set attributes in the following ways (as do instances of object itself). I always get an 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'

Help?

Upvotes: 6

Views: 3710

Answers (3)

yet
yet

Reputation: 804

    conn.a = 'foo',

or any dynamic assignment is valid, if conn is

    <type 'classobj'>.

Things like:

    c=object() 
    c.e=1

will raise an Attribute error. On the otherhand: Python allows you to do fantastic Metaclass programming:

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

Upvotes: 0

phihag
phihag

Reputation: 287835

Yes, unless the class is using __slots__ or preventing attribute writing by overriding __setattr__, or an internal Python class, or a Python class implemented natively (usually in C).

You can always try setting an attribute. Except for seriously weird __setattr__ implementations, assigning an attribute to an instance of a class of one of the types mentioned above should raise an AttributeError. In these cases, you'll have to use a wrapper, like this:

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

Upvotes: 4

eat
eat

Reputation: 7530

Simple experimentation:

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

So, indeed it seems to be possible to do that.

Update:
But from the documentation: SQLite is a C library that ..., so it seems that you really need to wrap it.

Upvotes: 1

Related Questions