LINUX.ORG.RU

Python, conditional compilation


0

1

Если честно, то долбаный питон. :)
Нужно сделать 2-3 независимый код.

if sys.hexversion >= 0x03000000: 
    тут что-то для 3 питона
else:
    тут для второго
Но, коряво это. И в случае когда зависит само определение класса, у меня вообще ступор.
Для 3 питона это будет так:
class MyClass(metaclass=MyMetaClass):
    ....

Для 2 питона это будет так:
class MyClass(object):
    __metaclass__=MyMetaClass
    ....
Вот что бы тут придумать? Как вариант, MyClass=MyMetaClass('MyClass', (object,), {}), но тут косяк если MyClass это парент класс. Может есть у кого мысли?

★★
Ответ на: комментарий от AIv

>Проблемы с мутабельностья аргументов по умолчанию можно рассматривать как особенность реализации. Ну вот такой ЯП. все данные висят в общем графе, надо об этом помнить и кто не спрятался - Гвидо не виноват.

Да, но это будет не ЯП, а ад какой-то, где смысл тех же переменных по-умолчанию для функции исчезнет.

Ладно, я то ко всему уже привык, но у неподгтовленного пользователя такие вещи вызывают ступор.

ИМХО полная мутабельность всего вокруг вызовет не меньший ступор. Тем более что питон 2 с его привычным поведением уже есть, потому настолько сильно ломать обратную совместимость не будет даже Гвидо.

anonymous
()
Ответ на: комментарий от tia

def gen_my_class_py2():
...class MyClass(object):
......__metaclass__ = Smthng
def gen_my_class_py3():
...class MyClass(metaclass=Smthng):
......pass

А ещё, ты делаешь бред и велосипед, хотя чего от тебя можно было бы ожидать...

Мой совет: брось это дело, Py3 пока не используй, ибо после выхода PyPy, возможно, ты и не захочешь(даже до тебя, надеюсь, дойдёт).

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

Конгениально Ватсон! Если еще предложите как к уже сгенерированному классу прицепить авоську методов к-е независят от версии, причем сделать это без лишних телодвижений - собака Баскервиллей наложит в штаны от восторга;-)

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

>Мой совет: брось это дело, Py3 пока не используй, ибо после выхода PyPy, возможно, ты и не захочешь(даже до тебя, надеюсь, дойдёт).

Это как? И что значит «выход PyPy», он же уже до версии 1.4 добежал, и умеет почти всё запускать?

anonymous
()
Ответ на: комментарий от AIv

как написали на одном из форумов:

The only cure I know for this is a good editor. Sorry.

нормальные редакторы позволяют комментировать выделенный блок

тем не менее, как вариант можно сделать C-style:

if False:
    this_code_will_never_run()

но, стоит помнить о правильных отступах и...

The only cure I know for this is a good editor. Sorry.

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

> Да, но это будет не ЯП, а ад какой-то, где смысл тех же переменных по-умолчанию для функции исчезнет.

А его и так нет, если это скажем список.

К полной мутабельности привыкнуть куда проще, чем к частичной мутабельности определяемой запутанными и противоречивыми правилами.

В конце концов можно ввести еще оператор присваивания заточенный именно на изменение содержимого объекта а не на переключени индентификатора. Вообще создание имени объекта и создание самого объекта вещи разные, местами их можно объединять но когда все лежит на одном графе понятоно что лучше б развести а то будут проблемы. Да много есть решений... константные объекты опять таки никто не отменял.

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

>В конце концов можно ввести еще оператор присваивания заточенный именно на изменение содержимого объекта а не на переключени индентификатора. Вообще создание имени объекта и создание самого объекта вещи разные, местами их можно объединять но когда все лежит на одном графе понятоно что лучше б развести а то будут проблемы. Да много есть решений... константные объекты опять таки никто не отменял.

Поздравляю, вы изобрели новый ЯП:)

Серьёзно, с таким подходом то, что получится, уже не стоит называть питоном. И уж тем более нельзя обвинять Гвидо в том, что питон 3 не получился таким.

anonymous
()
Ответ на: комментарий от shty

Фи... я весьма консервативен, понятно что на питоне можно сделать все что угодно, но все таки я предпочитаю комментить код комментариями. И потом, а если я хочу закомментить кусок кода ВНУТРИ строки?;-))))

Да, редактор наверное может закомментить блок... а раскомменитить? Я кстати емакс так и не научил (просто не пытался, может оно умееет и надо что то нажать хитрое?))))

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

>Да, редактор наверное может закомментить блок... а раскомменитить? Я кстати емакс так и не научил (просто не пытался, может оно умееет и надо что то нажать хитрое?))))

Не знаю, что вы делали с имаксом, но он по-дефолту в python-mode комментирует и раскомментирует питоновский код по M-;. Первый раз комментирует, второй раз - разкомментирует.

Имеет значение только то, весь ли выделенный блок закомментирован, или нет, от этого может меняться мнение редактора, комментировать илил раскомментировать.

anonymous
()
Ответ на: комментарий от AIv

Легко:
if ...
...cls = get_my_class_py2()
else
...cls = get_my_class_py3()
map(lambda x: cls.__setattr__(x.__name__, x), methods)

Конечно, сама идея делать совместимый код между двумя, фактически разными языками - идиотизм.

tia
()
Ответ на: комментарий от anonymous

>И что значит «выход PyPy», он же уже до версии 1.4 добежал, и умеет почти всё запускать?
Дебил? Хотя да, ты просто не владеешь русским языком, всё нормально.
Понимаешь, «ибо после выхода PyPy, возможно, ты и не захочешь» - будущее время.

А так PyPy почти «добежал» до релиза. Прохождение больше 95% тестов и стабильность об этом говорят.

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

> А так PyPy почти «добежал» до релиза.

Ага, уже несколько раз (текущая версия - 1.4).

Прохождение больше 95% тестов

- Петька, приборы?!!!

- 15!

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

> Поздравляю, вы изобрели новый ЯП:)

Во первых не я, смалток вроде по такому принципуц построен, не? Во вторых я это сделал еще 10 лет назад, а когда увидел питон то понял что мою поделку можно смело прятать - питон лучше;-))))

В третьих - повторюсь, у меня претензии к Гвидо в том, что он ограничился полумерами - совместимость потерял, а концептуально ничего не улучшил, хотя мог бы. Это как 3.14..сы (разработчики гнуплота) погнавшись за лингфистической чистотой поменяли

set data style ...

на

set style data ...

и ВСЕ МОИ GP СКРИПТЫ НАПИСАННЫЕ ЗА ПОСЛЕДНИЕ 10 ЛЕТ ПЕРЕСТАЛИ РАБОТАТЬ. Уроды! Лучше б нормальное сглаживание в хидден-моде сделали, но это ж надо алгоритм поменять...

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

> Не знаю, что вы делали с имаксом, но он по-дефолту в python-mode комментирует и раскомментирует питоновский код по M-;.

Опа... и правда. Спасибо, не знал!

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

Лучшее? Ты серьезно? Лучшее решение было написано сразу MyClass=MyMetaClass('MyClass', (object,), {}). То что он написал за а) не избавляет от дублирования кода, за б) смысл в метаклассе, если делать позднее связывание аттрибутов которые нужны для генерации объекта, о чем я распинался на предыдущей странице. Все его решение это по сути аналог того что написал tailgunner. Ну и к тому же это решение никак не избавляет от того что, к примеру, PyQt генерит разные по api (версии 1 для 2 питона и 2 для 3) файлы для разных версий питона.

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

Погодь, какое дублирование?

if PY3 :
   class A(...) : ... #PY3 code
else :
   class A(object) : ... #PY2 code

def f(self, ... ) : #PY2&3 code

A.f = f

....
a=A()

Где тут дублирование? Одна строчка для позднего свзывания, так если у тебя этих методов много, начинай их имена скажем с имени класса и потом по dir() автоматом все вяжи. Я правда с метаклассами толком не работал, но для обычных классов это точно прокатывает;-)

Выбранный tia стиль общения конечно вызывает неприятие и у меня в т.ч., то да.

AIv ★★★★★
()

Ну и вот ище решение, которое гарантированно работает всегда и везде (с поздним связыванием смутно помнится бывали какие то грабли):

def _A_f( self, x ) : ... #PY2&3 code
def _A_g( self, x, y, z ) : ... #PY2&3 code
...

if PY2 :
   def class A(object):
       for i in dir() :
             if i.startswith('_A_') : exec 'def %s( self, *arg, **kwarg) : %s( self, *arg, **kw_arg ) '%( i[len('_A_'):], i )
else : ...

Если хоцца, можно ручками разобрать сигнатуру объявленного ранее метода и сделать обертку с такой же сигнатурой что бы хэлп красивше смотрелся, ну и для выборки по dir какую нить ф-ю привесить;-)

AIv ★★★★★
()
Ответ на: комментарий от tia
def gen_my_class_py2():
...class MyClass(object):
......__metaclass__ = Smthng
def gen_my_class_py3():
...class MyClass(metaclass=Smthng):
......pass

Ты как был идиотом, так и остался, парсер не распарсит. В py3 другая грамматика.

anonymous
()
Ответ на: комментарий от AIv

> Конгениально Ватсон!

То, что он написал - это чушь, которая естественно не сработает.

anonymous
()
Ответ на: комментарий от tia

> map(lambda x: cls.__setattr__(x.__name__, x), methods)

Твою мать, ты даже не понимаешь, что такое __setattr__

Как у тебя вообще язык поворачивается говорить, что ты знаешь (пишешь) на питоне?

anonymous
()
Ответ на: комментарий от AIv

Не люблю я экзеки. :)
Да и как уже написал anonymous парсер 3 питона сломается. exec в 3 питоне - функция.

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

Ну в 2х ехес тоже вызывается как ф-я, такой синтаксис допустим. Хуже с классами, это я ступил, но это дело тоже можно в ехес сунуть. В общем мысль ясна - общий код объявляем до объявления класса отдельными методами, дальше формируем для создания класса строку, туда же добавляем объявления методов как оберток к ранее объявленным, потом эту строку exec.

Либо делаем позднее связывание - в приницпе у меня на 2х и для метаклассов вроде работает, но тут надо быть внимательным. С обертками будет неск хуже производительность, с поздним связыванием могут быть какие то грабли гипотетические (не помню, что то когда то у меня по этому поводу отвалиолвалось, но сейчас все ок).

Еще вариант - весь общий код оъявляем в обычном классе, а потм объявляем метакласс с множетсвенным наследованием. Но это я так... поскольку с метаклассамми не работал, мог и глупость сказать;-)))

Главное что это все крайне просто выглядит, не требует велосипедостроения с препроцессорами, изменениями сист сборки и пр.

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

>> map(lambda x: cls.__setattr__(x.__name__, x), methods)

Твою мать, ты даже не понимаешь, что такое __setattr__

tia хотело сказать setattr( cls, x.__name__, x )

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

> В общем мысль ясна - общий код объявляем до объявления класса отдельными методами, дальше формируем для создания класса строку, туда же добавляем объявления методов как оберток к ранее объявленным, потом эту строку exec.

Это ужаснейшая мысль. Намного легче и правильнее будет использовать препроцессор, а не городить кучу костылей, которые неизвестно где потом вылезут.

anonymous
()
Ответ на: комментарий от AIv

> не требует велосипедостроения с препроцессорами

m4 и никакого велосипедостроения.

anonymous
()
Ответ на: комментарий от AIv

> tia хотело сказать setattr( cls, x.__name__, x )

Оно уже свое сказало, он просто не понимает, что для классов cls.__setattr__ работает совсем не так, как для обычных объектов.

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

Препроцессор тоже неплохо, но надо все таки идти от задачи. Скажем если изначально ситсемы сборки вообще не было (а нафига она в питон???) то заводить ее по каким то причинам может оказаться некузяво. Что касается костылей - и то и то решение кривовато ИМНО (противоестесвенно что ли), но и то и то выглядит вполне работоспособным. Я часто юзаю exec для каких нить уныло-монотонных десйтвий типа перегрузки операторов - это тот же препроцессор, тока гораздо гибче.

ЧЕго все злые такие на ЛОР-е, никак понять не могу? Толерантней надо быть товарисчи, толерантней... ;-)))) tia, повесь в профайле фото симпатишной девушки - увидишь какие все станут сразу галантные и внимательные!;-))))))))

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

> Скажем если изначально ситсемы сборки вообще не было (а нафига она в питон???) то заводить ее по каким то причинам может оказаться некузяво

Какая система сборки? Shell или python script в 10 строчек + 10 строчек для m4.

Я часто юзаю exec для каких нить уныло-монотонных десйтвий типа перегрузки операторов - это тот же препроцессор, тока гораздо гибче.

Не надо юзать exec, это самый последний рубеж, если ничто уже больше помогает. Он ужасно снижает читаемость кода.

типа перегрузки операторов -

чего?

ЧЕго все злые такие на ЛОР-е, никак понять не могу? Толерантней надо быть товарисчи, толерантней

Если напыщенному идиоту не говорить, что он напыщенный идиот, у него не появится никакого желания стать умней.

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

эти 10 строчек кода надо еще запустить, и это может не вполне укладываться в используемую идеологию. ТС ведь не с нуля код пишет, а имеет дело с уже готовым проектом, ХЗ что там у него творится. У меня напр. в одном проекте система сборки настока запутанная, что никакой дополнительный парсер без ящику коньяка туда не всунуть;-(((((

Читаемость кода зависит от числа строк в первую очередь. Мне для система комп алгебры удалось за счет ехес уменьшить размер ядра с 600 строк до 60ти, при этом читаемость возрасла неимоверно. Напр, есть некий класс, у которого надо перегрузить все арфметические операторы так, что бы при вызове возвращался некий объект (в зависмости от оперратора), т.о. выражение переводитсья в дерево. Если это делать в лоб, сдохнуть можно, такая нудятина... а так имена классов коррелируют с названиями операторов и вся перегрузка ложится в две строки.

Если напыщенному идиоту говорить что он напыщенный идиот, он Вас просто не услышит. Хоите что б он услышал - будьте вежливы, не хотите - а нафик Вы ему тогда вообще отвечаете????;-)))))))

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

> Читаемость кода зависит от числа строк в первую очередь. Мне для система комп алгебры удалось за счет ехес уменьшить размер ядра с 600 строк до 60ти, при этом читаемость возрасла неимоверно. Напр, есть некий класс, у которого надо перегрузить все арфметические операторы так, что бы при вызове возвращался некий объект (в зависмости от оперратора), т.о. выражение переводитсья в дерево. Если это делать в лоб, сдохнуть можно, такая нудятина... а так имена классов коррелируют с названиями операторов и вся перегрузка ложится в две строки.

Я не совсем понял задачу, но судя по «нужно перегрузить все арифметические операторы» и «имена классов коррелируют с названиями операторов», это все делается с помощью метаклассов.

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

Мысль интересная, но я не представляю как это сделать с помощью метаклассов:

class base :
    def __add__( self, other ) : return op_add(self,other)
    def __sub__( ... ) : ...
    ...

class op_add(base) :
    def __init__( self, a, b ) : self.a, self.b = a, b
    ...

вместо этого пишем

class base :
    for i in 'add sub pow mul ...'.split() : exec 'def __%s__( self, other ) : return op_%s(self,other)'%(i,i)

на самлом деле стуркутра классов op_... чуток сложнее, и нужный класс просто объявляется с неск статичскими переменными, все методы тащщутся от его родителя.

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

OMG. Зачем тебе столько классов? Какого черта используются подклассы в базовом классе? Если ты хочешь просто разбора алгебраического выражения то можно сделать значительно правильнее и легче.

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

Нет, там далеко не просто разбор. В общем прими как данность - для той задачи такой дизайн был оптимален. Мы над этим несколько лет работали.

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

OPERATIONS = ['__add__', '__sub__', '__mul__', '__pow__']

class NodeMeta(type):
    def __new__(metacls, name, bases, attrs):
        def makeop(op):
            return lambda self, *args: type(self)(operands=list(args)+[self], operation=op)
        for op in OPERATIONS:
            attrs[op] = makeop(op)
        return super(NodeMeta, metacls).__new__(metacls, name, bases, attrs)
    
class Node(object):
    __metaclass__ = NodeMeta
    def __init__(self, operands=None, operation=None):
        self.operands = list(operands if operands else [self])
        self.operation = operation

def ast(node):
    if issubclass(Node, type(node)) and node.operation:
        r = [node.operation]
        for op in node.operands:
            r.append(ast(op))
        return r
    return node

Вот что делает моя наколеночная поделка

>>> ast((n+m+6)*n)
['__mul__', <__main__.Node object at 0x1691790>, ['__add__', 6, ['__add__', <__main__.Node object at 0x1691550>, <__main__.Node object at 0x1691790>]]]

Нет, там далеко не просто разбор. В общем прими как данность - для той задачи такой дизайн был оптимален.

Что за задача?

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

Это сист кмопьютерной алгебры для числ. моделирования, заточенная на кодогенерацию. Вводишь числ схему, получаешь работающий код. Мы над ней уже года 4ре работаем, виден свет в конце туннеля, но возможно это электричка;-)

Там и так все очень непросто что б еще мосг на местаклассы вывихивать. Напр у некторых операторов некоторые форматы вывода работают специфически - типа степнь в LaTeX и С++, или умножение и деление. Поэтому и дизайн такой - под каждый оператор свой класс, у некторых операторов некторые методы перегружены. ПолиморфизЪм...

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

> Там и так все очень непросто что б еще мосг на местаклассы вывихивать.

метаклассы - это просто :)

Напр у некторых операторов некоторые форматы вывода работают специфически - типа степнь в LaTeX и С++, или умножение и деление.

А как же single responsibility принцип? Если вдруг понадобиться выражения на scheme или еще каком языке, что делать будете - для каждого класса будете писать еще один метод? Вывод должен быть в других классах (или функциях), ответственных за кодогенерацию.

Что нибудь типа ast_to_latex(ast) или ast_to_c_plus(ast).

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

> что такое n и m?

Instances of the Node class.

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

> метаклассы - это просто :)

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

А как же single responsibility принцип?

Я существо темное и необразованное, я таких словей не знаю;-)

Для каждого формата вывода пишется один метод для общего предка, который при необходимости дополнительно перегружается для каких то отдельных операторов.

Я не сторонник разводить зоопарк классов там, где этого не нужно, даже если это диктуется какими то высшими теоретическими соображениями;-)))

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

> > метаклассы - это просто :)

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

Непонимание != большая сложность

Возможно, вы просто идио^W не прочитали полностью ман по пайтону.

-- the other anonymous

P.S. Йоптвуюналево, что только не используют для усложнения жизни себе. Есть куча нормальных инструментов для этих целей. Нет же нужно python & c++. Брррр

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

Меня всегда умиляла такая позиция - не разобравшись в вопросе высказывать предположения об уровне собеседника и критиковать изложенный подход. Вы видели код проекта целиком? Вы разобрались в том что за задача решается, откуда она возникла?

В моем представлении люди позволяющие себя так вести отличаются весьма низким IQ как мин. МНЕ ВАШЕ МНЕНИЕ НЕ ИНТЕРЕСНО. Идите дальше читайте маны.

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

> Меня всегда умиляла такая позиция - не разобравшись в вопросе высказывать предположения об уровне собеседника и критиковать изложенный подход. Вы видели код проекта целиком? Вы разобрались в том что за задача решается, откуда она возникла?

Ты не понял простой пример. Причём здесь код твоего проекта?

1) Я уже писал, что я другой анонимус, к тому, который привёл сэмпл кода - я не имеею отношения

2) Скажи, твоя отсылка к «коду проекта целиком» - это что, намёк, что у вас всё уже идеально и проще/читабальнее сделать нельзя? Бред.

В моем представлении люди позволяющие себя так вести отличаются весьма низким IQ как мин. МНЕ ВАШЕ МНЕНИЕ НЕ ИНТЕРЕСНО. Идите дальше читайте маны.

В моём представлении люди, которые не могут изучить инструмент, которым пользуются, отличаются весьма низким IQ. Мнения таких людей мне не интересно.

И прекратите использовать бесполезные сокращения. Освойте метод слепой печати и таки осильте дописывать три буквы оставшиеся буквы в словах.

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

Я понял что ты другой анаонимус. И я тебе уже сказал - МЕНЯ ТВОЕ МНЕНИЕ НЕ ИНТЕРЕСУЕТ.

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

> Если я не смог поянть Ваш код с первого просмотра - значит это сложнее чем то, что сейчас реализовано.

Я существо темное и необразованное, я таких словей не знаю;-)

Жаль, главные принципы софтверной разработки прошли мимо вас.

Для каждого формата вывода пишется один метод для общего предка, который при необходимости дополнительно перегружается для каких то отдельных операторов.

Это и есть зоопарк классов, там где он не нужен.

Я не сторонник разводить зоопарк классов там, где этого не нужно, даже если это диктуется какими то высшими теоретическими соображениями;-)))

На самом деле это диктуется практикой. Большое количество классов - это не страшно, страшно, когда много связей между этими классами.

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

> Это и есть зоопарк классов, там где он не нужен.

поясню: мои 1 метакласс и 1 класс заменяют десяток лишних классов по одному для каждой операции.

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

> Жаль, главные принципы софтверной разработки прошли мимо вас.

Увы да - я физик, а не программист, не отрицаю.

Это и есть зоопарк классов, там где он не нужен.
На самом деле это диктуется практикой. Большое количество классов - это не страшно, страшно, когда много связей между этими классами.

Гы... я чего то не понял, у меня связей между классами мало, так что в таком кол-ве классов плохого???

Еще раз - есть дерево, в узлах к-го сидят нек-е объекты. Объекты оечнь похожи, но для разных видов (намеренно не пишу - типов) объектов есть точечные различия. Мы сделали свой класс под каждый вид объекта, с общим предком (ну там чуть сложнее - есть бинарные операторы с общим предком, унарные и есть ф-ии и вот они уже наследуют самого общего предка), новый класс создается одной строчкой (задание нек-х статичских полей определяющих поведение класса) + перегрузка тех методв, к-е требуются. Если б не требовалась перегрузка отдельных методов - был бы один класс для бинарных операторов, один для унарных и еще один для ф-й. Это обеспечивает хранение выражения, анализ выражения (один общий метод для рекурсивного обхода дерева) и вывод выражения в нужном формате, а больше ничего от этой части и не требуется.

Вы хотите предложить что то более простое?

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

Да, и такая система легко перестаривается под какие то новые требования.

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