#python #attributes #metaprogramming
#python #атрибуты #метапрограммирование
Вопрос:
Могу ли я динамически добавлять атрибуты к экземплярам класса нового стиля (того, который является производным от object
)?
Подробные сведения:
Я работаю с экземпляром sqlite3.Подключение. Простое расширение класса — это не вариант, потому что я не получаю экземпляр, вызывая конструктор; я получаю его, вызывая sqlite3.connect()
.
Создание оболочки не сильно экономит объем кода, который я пишу.
Python 2.7.1
Редактировать
Правильные ответы на все. Но я все еще не достигаю своей цели; экземпляры sqlite3.Панель подключения my пытается установить атрибуты следующими способами (как и экземпляры object
самого себя). Я всегда получаю ошибку 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'
Помогите?
Комментарии:
1. Вы можете изучить фактический dict , чтобы узнать, что использует sqlite3. Но это может быть подпрограммой C, и в этом случае вам придется как-то ее обернуть.
2. 1. Даже
object.__setattr__(conn, 'a', 'foo')
вызывает ошибку AttributeError. Интересный вопрос!
Ответ №1:
Да, если только класс не использует __slots__
или не запрещает запись атрибута путем переопределения __setattr__
, или внутреннего класса Python, или класса Python, реализованного изначально (обычно на C).
Вы всегда можете попробовать установить атрибут. За исключением действительно странных __setattr__
реализаций, присвоение атрибута экземпляру класса одного из упомянутых выше типов должно вызывать AttributeError
. В этих случаях вам придется использовать оболочку, подобную этой:
class AttrWrapper(object):
def __init__(self, wrapped):
self._wrapped = wrapped
def __getattr__(self, n):
return getattr(self._wrapped, n)
conn = AttrWrapper(sqlite3.connect(filepath))
Комментарии:
1. Теперь я вижу, что вы правы, но это не работает для экземпляров sqlite3. Подключение или
object
само по себе. (См. Редактирование выше.) Любая помощь?2. @JellicleCat Оба относятся к «внутреннему классу Python». Я расширил ответ с помощью оболочки. Вы упомянули об использовании одного из них в вопросе; но я не уверен, почему это не решило бы проблему. Если эта оболочка не работает, пожалуйста, дополните свой вопрос (или комментарий здесь) сценарием, в котором он завершается неудачей.
Ответ №2:
Простой эксперимент:
In []: class Tst(object): pass
..:
In []: t= Tst()
In []: t.attr= 'is this valid?'
In []: t.attr
Out[]: 'is this valid?'
Итак, действительно, кажется, это возможно сделать.
Обновить:
Но из документации: SQLite — это библиотека C, которая … поэтому кажется, что вам действительно нужно ее обернуть.
Комментарии:
1. Теперь я вижу, что вы правы, но это не работает для экземпляров sqlite3. Подключение или
object
само по себе. (См. Редактирование выше.) Любая помощь?
Ответ №3:
conn.a = 'foo',
или любое динамическое присвоение допустимо, если conn является
<type 'classobj'>.
Такие вещи, как:
c=object()
c.e=1
вызовет ошибку атрибута. С другой стороны: Python позволяет выполнять фантастическое программирование в метаклассах:
>>>from new import classobj
>>>Foo2 = classobj('Foo2',(Foo,),{'bar':lambda self:'bar'})
>>>Foo2().bar()
>>>'bar'
>>>Foo2().say_foo()
>>>foo