Найти - Пользователи
Полная версия: как работать с dictproxy?
Начало » Python для экспертов » как работать с dictproxy?
1
Нави Гатор
Помогите, пожалуйста.
Я переопределил метод __setattr__ для класса следующим образом:
class SomeClass(SomeMetaClass):
def _setattr(cls,name,val):
try:
cls.__getattribute__(name)
except:
cls.__dict__[name]=val
SomeMetaClass.__setattr__=_setattr
В результате при вызове SomeClass.someattr='value' вылезает ошибка:

TypeError: Error when calling the metaclass bases
‘dictproxy’ object does not support item assignment

Что сдесь можно сделать?
Андрей Светлов
нужен полный пример. Что за SomeMetaClass?
Нави Гатор
Да без разницы, пусть будет:
class SomeMetaClass(object):
pass
Вопрос в том, как переопределить __setattr__. SomeMetaClass трогать нельзя, SomeClass.__dict__ должен показывать правильные аттрибуты

Вообще, речь идет о скюэльалхемовской примочке elixir. На класс SomeClass процедурой setattr() внутри elixir навешиваются методы, один из которых очень нужно переопределить. Для этого я этот метод объявляю внутри класса SomeClass, а потом делаю умный __setattr__, который устанавливает новые аттрибуты только если они не существуют.
Полный код:
from elixir import * 
class BigClass(Entity):
def _setattr(cls,name,val):
if not cls.__dict__.has_key(name):
cls.__dict__[name]=val
EntityMeta.__setattr__=_setattr
@classmethod
def select_by(*args,**kwargs):
cls=args[0]
kwargs[type]=cls.type
return cls[0].__class__.select_by(**kwargs)
class SomeClass(BigClass):
type=1
#EntityMeta и Entity для данной задачи можно считать одним и тем же классом
Андрей Светлов
Скажу сразу: с Эликсиром не работал. В отличие от алхимии.
Но, как я вижу из его сорцов, select_by он сам не навешивает.
И уж тем более не совсем через setattr.
elixir/entity.py: 167 - прикладывается assign_mapper к entity, который, используя assignmapper extension инструментирует entity.

Посмотри на sqlalchemy/ext/assign_mapper.py: 4 monkeypatch_query_method. Им же и твою реализацию прикрутить можно.

Если, конечно, я правильно понял цель - в select_by один из критериев выборки жестко зашивать в самом entity

Алхимия 0.3.9, Эликсир 0.3.0

Если я совсем тебя не понял - попытайся по другому сформировать вопрос.

Кстати, assingmapper - кривоватая штука, рудимент от первой бородатой версии
Нави Гатор
Спасибо. Про monkeypatch_query_method то я знаю, именно из него вызывается setattr, но насколько я понял метод select_by он вытаскивает прямо из Query. А как бы его заставить цеплять свой select_by? Все-таки сырцы sqlalchemy менять как-то не хочется.
Андрей Светлов
Нави Гатор
Спасибо. Про monkeypatch_query_method то я знаю, именно из него вызывается setattr, но насколько я понял метод select_by он вытаскивает прямо из Query. А как бы его заставить цеплять свой select_by? Все-таки сырцы sqlalchemy менять как-то не хочется.
Это то, что ты хотел?

from elixir import *
from elixir.entity import EntityMeta

metadata.connect(“sqlite:///sample.sqlite”)


class SelectDescr(object):
def __init__(self, cls, fixed_name):
self._cls = cls
self._old_select_by = cls.select_by
self._fixed_name = fixed_name

def __get__(self, instance, owner):
def f(*args, **kwargs):
new_kw = dict()
new_kw.update(kwargs)
if self._fixed_name is not None:
new_kw = self._fixed_name
return self._old_select_by(instance, *args, **new_kw)
return f


class PersonMeta(EntityMeta):
def __init__(cls, name, bases, dict_):
EntityMeta.__init__(cls, name, bases, dict_)
cls.select_by = SelectDescr(cls, getattr(cls, ‘fixed_name’, None))


class Person(Entity):
__metaclass__ = PersonMeta
has_field('name', Unicode(255))

def __repr__(self):
return ‘Person @ 0x%08x (%s)’%(id(self), self.name)

#instrument(Person)
#Person.select_by = SelectDescr(Person)


drop_all()
create_all()

def fill():
p = Person(name='Jack')
p2 = Person(name='John')

objectstore.flush()

fill()

print Person.select_by()

print Person.select_by(name='Jack')

class Jack(Person):
fixed_name = ‘Jack’

print Jack.select_by()


Если нет - давай отталкиваться от примера и выяснять, что таки нужно.
Нави Гатор
Пасиибаа!
Как раз то, что надо
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB