LINUX.ORG.RU

[python][metaclasses] автоматическое создание слотов

 


0

0

Вот сдесь есть две идеи как создавать классы с автоматическими слотами: http://code.activestate.com/recipes/435880/

В первой есть костыль в виде вызова специальной функции в __init__, а вторая работает ещё кривее: сначала берётся исходник всего класса, потом строится синтаксическое дерево(abstract syntax trees, ast) и уже оно обходится и находятся все присвоения к self.

Как превратить __code__ во что-то что можно распарсить я не придумал. Взять __code.co_varnames тоже не получится т.к. в итоге из self.field = 666 туда попадёт только self(что логично). Модуль disasm мне тоже не понравился.

Пока самое элегантное что придумал это получить исходник функции и регекспом его, регекспом! Работает отлично, даже конструкции вида self.x=1;self.y=1; проглотит.

Может у кого ещё есть идеи как это можно реализовать?

class AutoSlots(type):
    def __new__(self, cls_name, bases, namespace):
        if bases:
            #slots can be used with subclassing. For this two problem should be solved:
            #  exclude slot variables appeared in base classes
            #  check if all parrents doesn't have __dict__ or slots will be useless
            raise Exception("Do not use slots with in nested classes")

        #__slots__ may be tuple or other iterable, so we converting it to list
        slots = list(namespace.get('__slots__', []))
        if '__init__' in namespace:
            init = namespace['__init__']
            init_source = inspect.getsourcelines(init.__code__)[0]
            for line in init_source:
                slots += re.findall(r"\s*self\.(\w+)\s*=\s*\w*;?",line)
        namespace['__slots__'] = slots
        return type.__new__(self, cls_name, bases, namespace)

★★★★★

>автоматическое создание слотов

Зачем оно вообще нужно? Лишний повод выстрелить себе в ногу

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Просто решил автоматизировать процесс. Я стараюсь писать проги так чтобы если что-то надо было добавить то менять пришлось только в одном месте. А так надо и в __init__ пихать и __slots__ править.

Ногу не отстрелишь, код рабочий :)

true_admin ★★★★★
() автор топика
Ответ на: комментарий от true_admin

> Просто решил автоматизировать процесс.

Ты просто забыл сказать, что это за ЯП, на самом деле. Если б в заголовке было написано, что это пистон, то сразу все вопросы о вменяемости топика отпали бы.

name_no ★★
()
Ответ на: комментарий от true_admin

Я правильно понимаю, что оно проходится по исходникам класса, ищет все упоминания переменных объекта, и если таковых не находится, потом определяет нужные слоты? А если произошла очепятка, вместо одного слота myUberSlot будут myUbrSlot и myUberSolt?

yoghurt ★★★★★
()
Ответ на: комментарий от yoghurt

Ищет только в пределах __init__, опечатки, конечно, не отловит, но код ищет не упоминания объектов а только присвоение типа self.myslot=blah . Если ты дважды не будешь инициализироватьодно и то же поле(зачем такое может понадобится?) в __init__ проблемы не будет.

true_admin ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

Как раз наоборот работа со слотами упростилась. Ящитаю что лучше один раз создать автоматизированное средство которое в дальнейшем будет решать мои проблемы. Единственно что немного коробит это способ решения проблемы(регекспы в таком месте это как-то неожиданно), а по коду у меня претензий пока нет :)

И почему ты скрываешь личность ЛММ?

true_admin ★★★★★
() автор топика
Ответ на: комментарий от yoghurt

Кстати, наоборот этот метод позволяет избежать ошибки когда какой-то из слотов перестал использоваться но остался объявлен в __slots__. Вот.

true_admin ★★★★★
() автор топика
Ответ на: комментарий от true_admin

>И почему ты скрываешь личность ЛММ?

Летающий Макаронный Монстр

yoghurt ★★★★★
()
Ответ на: комментарий от true_admin

> по коду у меня претензий пока нет :)

Да? И вот это:

raise Exception(«Do not use slots with in nested classes»)

по-твоему, нормально? Это не говоря о том, что «nested classes» кажется просто неправильной формулировкой.

И почему ты скрываешь личность ЛММ?

Чтобы его появление было сюрпризом для тебя.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

по-твоему, нормально? Это не говоря о том, что «nested classes» кажется просто неправильной формулировкой.

У меня просто не было такой задачи, но раз ты просишь, special for you доработанная версия(untested):

class AutoSlots(type):
    def __new__(self, cls_name, bases, namespace):
        base_slots = []
        for base in bases:
            try:
                base_slots += list(base.__slots__)
            except NameError:
                raise Exception("OMG, base class %s without slots! See http://docs.python.org/py3k/reference/datamodel.html?highlight=__ne__#notes-on-using-slots" % base)

        slots = list(namespace.get('__slots__', [])) #__slots__ may be tuple or other iterable, so we converting it to list
        if '__init__' in namespace:
            init = namespace['__init__']
            init_source = inspect.getsourcelines(init.__code__)[0]
            for line in init_source:
                slots += re.findall(r"\s*self\.(\w+)\s*=\s*\w*;?",line)
        namespace['__slots__'] = []

        for slot in slots:
            if slot not in base_slots:
                namespace['__slots__'].append()

        return type.__new__(self, cls_name, bases, namespace)

(не знаю как сократить текст в Exception так чтобы было понятна суть сообщения, вариант Exception(«base class without __slots__») не очень нравится)

«nested classes» кажется просто неправильной формулировкой.

Согласен, просто писалось в 3 ночи, не хотел тратить время на раздумья по этому поводу. Щас на трезвую голову очевидно что это base classes. Поправил у себя.

true_admin ★★★★★
() автор топика
Ответ на: комментарий от true_admin

>> по-твоему, нормально? Это не говоря о том, что «nested classes» кажется просто неправильной формулировкой.

У меня просто не было такой задачи, но раз ты просишь

Я просил забить на эту идею.

special for you доработанная версия(untested):

Мде. Мне кажется, или первая версия кода тоже была untested? Потому что с непустым bases она не работала.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Есть разная степень неработоспособности. Не смешивай untested и unimplemented. Как только потребуется я допилю. Да и тред не об этом.

true_admin ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.