[python] Давайте писать всякие не очень очевидные для новичков примеры
def f(a, L=[]):Это так "интуитивно понятно" замыкание выглядит?
Надо твёрдо понимать, что они инициализируются один раз, поэтому, к сожалению,
приходится либо делать их None, а потом ставить нужное значение, либо явным образом копировать.
Последнее тоже не всегда прокатывает.
А по теме - гугл "Python Warts".
Ну, это засада только с мьютбл типами, есс-но, а потому бывает относительно редкоУ кого как, я на arg=[] напарывался несколько раз, теперь None ставлю и присваивание через arg or [] делаю в таких случаях.
Еще один раз было невозможно перехватить вывод у функции, подменяя sys.stdout, ибо она его использовала как значение по умолчанию.
Выводов два.
1. В питоне 2.6 переменные list comprehension находятся в родительской области видимости и переписывают значения
z = 4
s = [z*z for z in range(256)]
print z
вернёт не 4 как ожидалось, а 255.
В третьем питоне пофиксили.
2. В питоне 3, как и во 2, применяется динамическое связывание замыканий, что приводит к странным и неожиданным результатам (смотри тред в начале топика). Лучше вообще замыкания не юзать, наверное. А если хочется замыканий - stackless python или PyPy тебя ждут.
Ну и вообще, культуры программирования в питон среде не предусмотрено. При минимальных отличиях синтаксиса второго и третьего питона, на последнее большинство лаб перелезть без затрат так и не смогло, потому как поставило себя в зависимость ото всяких мелких багов (ну или фич - как смотреть вроде того, что я демонстрировал с list comprehension
2. В питоне 3, как и во 2, применяется динамическое связывание замыканий, что приводит к странным и неожиданным результатам (смотри тред в начале топика). Лучше вообще замыкания не юзать, наверное. А если хочется замыканий - stackless python или PyPy тебя ждут.2. Прежде чем использовать что-то, стоит почитать, как это работает. Проблема новичка в питоне, который приходит и делает, как привык в другом языке, обсосана миллион раз. Читайте доки, проблемы там описаны. В обычном туториале на оф сайте, кстати, есть описание проблемы с дефолтным значением. Но никто же не хочет ничего читать, правда?
Ну и вообще, культуры программирования в питон среде не предусмотрено. При минимальных отличиях синтаксиса второго и третьего питона, на последнее большинство лаб перелезть без затрат так и не смогло, потому как поставило себя в зависимость ото всяких мелких багов (ну или фич - как смотреть вроде того, что я демонстрировал с list comprehension
Не осилил (не захотел) понять, как работает замыкание-лябда в питоне - не используй. Но делать дурацкие глобальные выводы "лучше не использовать вовсе" - это смешно.
Последний абзац - это откровенная ересь. Абсолютное большинство не использует лист компрехеншн баги, как ты показал. И не перелезают на питон 3 тоже не поэтому. Все нормальные конторы/сообщества сидят на том, что используют, пока есть возможность. Нахрена куда-то мигрировать, тратить ресурсы, если все и так зашибись? Пока питон 3 не предоставит убедительных преимуществ для тех, кто считает деньги, или пока окончательно не закончится поддержка версии 2.х, полной миграции и не будет. Я уже молчу про то, что версия 3.0 была серьезно перелопачена, а 2.х эволюционно правилась дохрена лет, и вопрос о надежности существует.
Читайте доки, проблемы там описаны.проблем быть не должно и на это рассчитывают наивные новички
2. Прежде чем использовать что-то, стоит почитать, как это работает. Проблема новичка в питоне, который приходит и делает, как привык в другом языке, обсосана миллион раз. Читайте доки, проблемы там описаны. В обычном туториале на оф сайте, кстати, есть описание проблемы с дефолтным значением. Но никто же не хочет ничего читать, правда?Во-первых, доки большие, и этот тред создан специально для того чтобы рассказать новичкам о таких багах.
Не осилил (не захотел) понять, как работает замыкание-лябда в питоне - не используй. Но делать дурацкие глобальные выводы "лучше не использовать вовсе" - это смешно.
Во-вторых, потому я и рассказал про весёлости с лист компрехеншином. И между прочим о надвидимости переменных лисп компрехешина я ничего не нашёл на оффсайте. И более того большая часть питонокодеров, которым я показывал этот трюк с z, сильно удивлялись и начинали отчаянно скрести в затылках, пытаясь вспомнить, не писали ли они когда код, который может попасться на этот баг.
В-третьих, с дефолтным значением - это не проблема, куча туториалов рекомендует этот хак с мутабл коллекцими как способ задания статических переменных в функциях.
В-четвёртых, где я хоть слово писал про лямбду? Ты замыкание от лямбды отличить умеешь? Все проекты, существенно использующие замыкания, написаны на стеклесс версиях питона.
В-пятых, я не жаловался на такую особенность лямбда выражений в питоне. Динамическое связывание - это не баг, это фича. Оно и в первых версиях Великого Лиспа было. Я просто честно предупредил. Сразу сказал, крупным планом, потому что на мой взгляд это знание заслуживает того, чтобы о нём узнали сразу, а не нашли случайно в доках.
Вот заодно ещё один хак (работает для новых классов, с неопределённым свойством __slots__)
def become(a,b):
a.__dict__ = b.__dict__
a.__class__ = b.__class__
> python
Python 2.5.2 (r252:60911, Jun 23 2008, 09:16:18)
[GCC 3.4.6 [FreeBSD] 20060305] on freebsd6
Type "help", "copyright", "credits" or "license" for more information.
>>> f=lambda x="8<:477\02092020162\020\037",y="01001000110100101":reduce(lambda x,y:x+y,map(lambda y,x:chr(ord(y)*2+xx,map(int,y;print f;
python readable ?
>>>
такого рода страниц в инете выше крыши
конкретно твой пример на каждом углу встречается
уж лучше какиенить красивые решения хитрых задач
хотя опять же в инете полно решений
хотя опять же
вона я в соседнем треде спрашивал как сделать генератор начинающийся не сначала
дык не подсказал никто
Они еще и структурированы, чтобы такие отмазки не прокатывали.
>В-третьих, с дефолтным значением - это не проблема, куча туториалов рекомендует этот хак с мутабл коллекцими как способ задания статических переменных в функциях
Ссылку на что-то официальное. Рекомендации дяди Васи меня не устроят.
>В-четвёртых, где я хоть слово писал про лямбду?
Первая ссылка в твоем посте о чем по-твоему?
>Ты замыкание от лямбды отличить умеешь?
Ты не можешь построить замыкание на лямбде?
>Все проекты, существенно использующие замыкания, написаны на стеклесс версиях питона.
Приехали, мама дорогая. Декораторы, по-твоему, как пишутся?
>В-пятых, я не жаловался
"Лучше вообще замыкания не юзать, наверное"
>Вот заодно ещё один хак (работает для новых классов, с неопределённым свойством __slots__)
Мля, теперь сюда еще и разнообразные хаки будут писать? Чтобы новички плодили тоннами говнокод?
Что ты имеешь в виду?
как сделать генератор начинающийся не сначала
Ты не можешь построить замыкание на лямбде?полноценное - нет. Поэтому к лямбдам я не имею никаких претензий, но к некоторым моментам использования - имею. Конечно, кое-что можно предусмотреть и в некоторых случаях будет работать, но динамическое связывание - это системная проблема. Представить нормальные замыкания с динамическим связыванием - трудно, представить питон без оного - ещё труднее.
А чем тебе become не понравился? Вполне удобный способ подменить объект, сохранив все ссылки на него.
Что ты имеешь в виду?там в топике читай после P.S.
генератор начинающийся не сначалатак у тебя там проблема не в том, чтобы сделать генератор, начинающийся не сначала, а в том чтобы установить нормально начальное состояние.
причём тут язык? напиши что ты хочешь на руби или на другом языке, тогда понятно будет.
а так, пожалуйста, вот тебе генератор, начинающийся не сначала:
def count(start=0, step=1):
# count(10) --> 10 11 12 13 14 ...
# count(2.5, 0.5) -> 3.5 3.0 4.5 ...
n = start
while True:
yield n
n += step
Неясно, кстати, раз уж ты пользуешься itertools, то почему не взял и dropwhile, а фактически переопределяешь его в next.
Нужно по-другому определить переход к следующей строке, не через product. Тогда можно начинать с любой.
def asciiinc(c):
x = ord(c)
if x >= ord('Z'):
x = ord('A')-1
return chr(x + 1)
def chariter(start='A'):
n = start
while True:
yield n
if n == 'Z': break
n = asciiinc(n)
def aaaiter(start = 'AAA'):
v1,v2,v3 = start
for s1 in chariter(v1):
for s2 in chariter(v2):
for s3 in chariter(v3):
yield(s1+s2+s3)
v3 = 'A'
v2 = 'A'
def alphanumiter(start = "AAA0000"):
alpha = start[:3]
num = string.atoi(start[3:])
for s in aaaiter(alpha):
for n in xrange(num,10000):
yield s + "%04d"%n
num = 0
Скорее всего, можно как-то упростить.
Неясно, кстати, раз уж ты пользуешься itertools, то почему не взял и dropwhile, а фактически переопределяешь его в next.dropwhile нет в хаскеле
P.S.
тьфу, ступил
я не понял про что речь
причём тут язык? напиши что ты хочешь на руби или на другом языке, тогда понятно будет.я ж написал
в руби это встроено в язык
"lala".next
А как он понимает, что часть с "AAA" нужно гонять только по буквам, а часть с "0000" — только по цифрам?
dropwhile нет в хаскелеесть же
может я в этом треде буду спрашивать как чтонить сделать?
как вот например tail -f сделать?
понятно что я могу это in-place сделать прям в коде
но хочется тчоб это была некая утилита которую можно реюзать
простейший вариант с генератором:
def tail_f(file, interval=1.0):
while True:
where = file.tell
line = file.readline
if not line:
time.sleep(interval)
file.seek(where)
else:
yield line
проблема в том что непонятно как это остановить?
g.next заснет же мертвым сном если в файле долго ничего не будет...
хочет в этот next таймаут чтоли передавать
в руби это встроено в языктак это тебе нужен не
"lala".next
генератор начинающийся не сначала, а функция по строке выдающая "следующую" строку.
dropwhile нет в хаскеленуууу
если таймаут исчерпан, то он отваливается.
ты dropwhile от dropWhile отличаешь? а ghc - отличает
а давайте не будем из генераторов делать микротреды? Либо заюзаем стандартные питоновские средства - PyPy, stackless haskell, либо и вовсе перейдём на использование go каналов?
>А чем тебе become не понравился? Вполне удобный способ подменить объект, сохранив все ссылки на него
Во-первых, не подменить, так как при добавлении атрибута у одного, он автоматически добавиться к другому.
Во-вторых, зачем такие хаки вместо copy.deepcopy?
В-третьих, приведи пример конкретной задачи, где это используется? То есть, зачем для редкой задачи генерить неявный хак, когда можно длиннее, но понятней и без хаков написать?
В-четвертых, зачем новичкам эта жуть?
а нельзя таймаут в генератор передавать?как-то некрасиво...
если таймаут исчерпан, то он отваливается.
тогда уж передавать функцию, которая если false вернет то перестать работать
g.next заснет же мертвым сном если в файле долго ничего не будет...ну так ты определись, что ты хочешь от этой функции?
чтоб блокировалась или нет?
микротреды я, кстати, не предлагал создавать.
я думал, что исполнение вполне последовательно,
то есть счетчик в генераторе просто следит, не превысили ли ожидаемые интервалы таймаут.
конечно, это сразу же приводит к багу, когда таймаут не кратен интервалу, что ждать придется дольше - но ради простоты можно на это забить. или можно описать такое поведение в комменту к функции, чтобы не забыть.
ну так ты определись, что ты хочешь от этой функции?я хочу чтобы блокировалась
чтоб блокировалась или нет?
но при этом чтобы у программы была возможность завершиться не только по ctrl+c
или вы предлагаете поток который вычитывает файл просто убивать?
P.S.
как кстати в питоне ctrl+c отловить?
верней нужно не отловить а грамотно завершить работу проги в случае убивания
2. Очень простой пример. У нас есть матрица, интерфейс для работы с ней. И мы сделали два класса - для плотных и разряженных матриц. В определённый момент плотная матрица (пересчитав себя в бекграунде) обнаруживает, что она не такая уж и плотная и подсовывает вместо себя разряженную, собой инициализированную. Можно конечно задействовать включение, сделать ещё один класс proxy, который будет вызывать для каждой функции интерфейса соответствующую функцию для self.matrix, но тогда это отображение функций нужно делать руками. А так мы создаём MatrixProxy, наследником AbstractMatrix, и в нужным местах подставляем вместо себя инстанс либо SparceMatrix, либо DenseMatrix
P.S.http://docs.python.org/library/signal.html
как кстати в питоне ctrl+c отловить?
верней нужно не отловить а грамотно завершить работу проги в случае убивания
ну если интервал передавать, то и таймаут не сильно портит по-моему.блин
таймаут нафик не нужен
сделал пока так:
def tail_f(file, interval=1.0, shouldStopReadingF=lambda: False):
while True:
if shouldStopReadingF:
return
where = file.tell
line = file.readline
if not line:
time.sleep(interval)
file.seek(where)
else:
yield line
def _readLogFile(filename, callback, interval, shouldStopReadingF):
file = open(filename, 'r')
file.seek(0, 2) # go to end of file
lines = utils.tail_f(file, interval=interval, shouldStopReadingF=shouldStopReadingF)
try:
for line in lines:
callback.onNextLine(line)
except StopIteration:
pass
finally:
file.close
class Application(object):
def __init__(self, logfile):
self.logfile = logfile
self.reader = None
def onNextLine(self, line):
print line
def start(self):
self.isStopped = False
self.reader = threading.Thread(target=_readLogFile, args=(self.logfile, self, 1, lambda: self.isStopped
self.reader.start
def stop(self):
self.isStopped = True
if self.reader:
self.reader.join
a = Application('lala')
a.start
time.sleep(10)
print 'stopping'
a.stop
print 'stopped'
time.sleep(20)
вот кстати
в рамках этого треда подскажите
можно ли в качестве дефолтного аргумента указывать лямду?
можно ли лямду ссылающуюся на self передавать чужому потоку?
то есть для этого генератора будет отдельная нитка?
> но при этом чтобы у программы была возможность завершиться не только по ctrl+c
ну да, timeout, функция или флаг
вроде другого ничего не придумали
> или вы предлагаете поток который вычитывает файл просто убивать?
мы ничего не предлагаем, мы дико тупим и пытаемся понять что вообще нужно
PS Реализация с readline плохая, может разбить одну строчку посередине.
PPS Я бы всё же использовал poll + read вместо sleep + readline
можно, в чем проблема?
> можно ли лямду ссылающуюся на self передавать чужому потоку?
аналогично, пусть насяльника меня поправит, но вроде как лямбда
это почти обычная функция, только анонимная
upd
while True:
if shouldStopReadingF:
return
Ужас!
while not shouldStopReadingF:
...
2. Очень простой пример. У нас есть матрица, интерфейс для работы с ней. И мы сделали два класса - для плотных и разряженных матриц. В определённый момент плотная матрица (пересчитав себя в бекграунде) обнаруживает, что она не такая уж и плотная и подсовывает вместо себя разряженную, собой инициализированную. Можно конечно задействовать включение, сделать ещё один класс proxy, который будет вызывать для каждой функции интерфейса соответствующую функцию для self.matrix, но тогда это отображение функций нужно делать руками. А так мы создаём MatrixProxy, наследником AbstractMatrix, и в нужным местах подставляем вместо себя инстанс либо SparceMatrix, либо DenseMatrixУ меня, честно говоря, возникает ощущение, что либо я не осознал задачу, либо архитектура решения хреновая.
момент первый: почему матрицы сами себя подменяют вместо того, чтобы отдать управление чехардой третьему лицу
момент второй: почему класс полной матрицы проверяет себя на полноту
я увидел задачу так (поправь): в системе появляются данные, по ним определяется, какую матрицу использовать, матрица используется - замыкаем цикл
но вроде как лямбдалямбда в питоне - это синтаксический сахар. обычная функция с синтаксическими ограничениями на тело
это почти обычная функция, только анонимная
задача - сделать эффективное представление матрицы. Возможно выполнение функции normalize в фонов режиме (таким же образом, как и работа garbage collectorа либо просто в момент операции определяется что делать с результатом: конвертировать или нет (посчитать во время умножения количество ненулевых элементов не усложняет задачу умножения хранить одну версию представления или обе.
задача - сделать эффективное представление матрицы. Возможно выполнение функции normalize в фонов режимеКак бы тут противоречие...
При "эффективном" представлении, решении или еще чего там у тебя просто _нет_ фонового режима.
пишите на жабе
> момент второй: почему класс полной матрицы проверяет себя на полноту
> я увидел задачу так (поправь): в системе появляются данные, по ним определяется, какую матрицу использовать, матрица используется - замыкаем цикл
если сделать так как ты говоришь, то как будет выглядеть в коде, например, сложение двух полных матриц, в результате которых получается разреженная матрица?
в решении код будет аля matrix1 += matrix2; и в результате matrix1 автоматически становится разреженной.
в решении код будет аля matrix1 += matrix2; и в результате matrix1 автоматически становится разреженной.опустим вопрос про копирования, но вспомним, что перевод в/из разреженного формата весьма не бесплатен
и если у тебя более одной операции матричной то на этом можно погореть, прыгая постоянно из одного в другой формат
вопрос быстрого определения когда действительно необходимо перепрыгнуть тоже стоит опустить, потому что он не имеет отношения к поднятому ранее вопросу
проблема - это рюхнуть что конверсия действительно _нужна_
а это может решить только пользователь, который знает, что он там будет делать потом
это я к тому что пример дурацкий
>>проблема - это рюхнуть что конверсия действительно _нужна_
>dg>вопрос быстрого определения когда действительно необходимо перепрыгнуть тоже стоит
вопрос быстрого определения когда действительно необходимо перепрыгнуть тоже стоит опустить, потому что он не имеет отношения к поднятому ранее вопросузначит можно ещё ввести класс DelayedMatrix
У меня, честно говоря, возникает ощущение, что либо я не осознал задачу, либо архитектура решения хреновая.да к черту матрицы, он про шаблон State.
момент первый: почему матрицы сами себя подменяют вместо того, чтобы отдать управление чехардой третьему лицу
момент второй: почему класс полной матрицы проверяет себя на полноту
я увидел задачу так (поправь): в системе появляются данные, по ним определяется, какую матрицу использовать, матрица используется - замыкаем цикл
Фишка вот в чем: он по сути сказал, что шаблон State реализуется на питоне гораздо лаконичнее, чем на C++. Таких примеров для разных языков и шаблонов довольно много. В пример привел применение шаблона State к матрицам. Все замечания тут относятся к адекватности применения этого шаблона к этой задаче, но не к питону и его преимуществах, State — довольно часто используемый шаблон, лаконичность его реализации — это аргумент.
Да даже еще сильнее: State в питоне вообще не нужен по сути, там эта функциональность доступна напрямую.
значит можно ещё ввести класс DelayedMatrixLazy.
LazyMatrix и
Оставить комментарий
SCIF32
выводит:
[1]
[1, 2]
[1, 2, 3]