Pull to refresh

Comments 77

спасибо, сделал.
он был, но в ходе «доводки» потерялся.
Да, приятно и полезно.

Но как-то… Декораторы сами собой теперь напрашиваются :) Главное, чтобы авторы не опустили рассказ про разницу между staticmethod и classmethod :)))
Думаю, не упустит :) Можно еще до кучи про instancemethod рассказать, который types.MethodType :)
я то напишу. без проблем. но похоже особо это никому на хабре не надо.
Но-но! Давайте не разводить декаданс в комментариях? :)
очень даже надо! спасибо огромное за порцию знаний! и оч жду продолжения
Прочитал про дефолтные параметры интереса ради, ой ну и жуть это ваш питон. Можно прострелить себе ногу совершенно неожиданным способом!
гм… во-первых ими же можно не пользоваться
во-вторых — оно так работает почти везде, где есть
То что дефолтный объект сохраняется — это очень не хорошо, по-моему. Каждый вызов функции должен быть с нуля, а тут переменная неявно объявлена статиком, что только путает людей.

Может быть я ничего не понимаю в скриптовых языках :)
я бы сказал это не баг а фича :)
достаточно один раз это запомнить и больше не наступать на такие грабли.

в общем-то это конечно нелогично, но любой язык полон подобных фокусов.

ЗЫ я понимаю что «другие не лучше» — не аргумент, но так уж сделали изначально. видимо для ускорения работы интерпретатора.
мы же можем написать и так:
def my_func(param=some_other_func()):
    pass

в подобном случае правило «значения по-умолчанию инициируются один раз — приобретает смысл, как по мне по крайней мере.
Написать так:
def my_func(param=some_other_func()):

это прямой прострел ноги :) Потому что неизвестно какое значение выдаст функция во время инициализации объекта.
не надо вызывать функцию которая возвращает неизвестные значения :-)
я просто примел очень надуманный пример

опять таки — лично я стараюсь использовать только «простые» значения по умолчанию. потому не имею в целом проблем.
Это я и хотел сказать собственно :)
Ну почему не известно? Во-первых, мы не инициализируем объект в нашем случае, а объявляем функцию (да, я знаю, что функция — тоже объект, но сейчас это не играет роли). Во вторых, даже если бы это был объект, что тут странного? Рассмотрим поближе:
def some_func():
    return 'Hello!'

def some_func2():
    return [1, 2, 3]

def my_func(a = some_func(), b = some_func2()):
    print a, b

my_func()


Этот код выведет, соответственно, Hello! [1, 2, 3]. Почему? Потому что все функции были выполнены на момент объявления функции. Естественно, если попытаться из some_func-ов потрогать my_func, нам просто скажут, что нет такого объекта. И правильно сделают — сначала объект создается, а лишь потом ему назначается референс в виде идентификатора.

Какбэ несколько другая ситуация, если мы захотим из my_func-а поизменять b — в данном случае, мы будем всегда работать с одним и тем же списком, потому что его значение уже было однажды вычислено, а списки являются mutable объектами (т.е. могут менять своё содержимое), тогда как строка 'Hello!' — immutable, т.е. значение своё менять не может и после каждой операции со строками создается новый экземпляр.

Ффух. Вот. Надеюсь, я всё это не зря писал и к концу текста понятно, что я хотел сказать в начале :)
Ну это понятно :) Я в питоне не силён, поэтому напишу на сях что я имел ввиду:

class A{
public:
static int a=0;
int inc(){a++; return a;};
}

Понятно, что случай гипотетический, в плюсах такого быть не может, но мы создаём функцию у которой значение по умолчанию как раз это самое A::int(). Получится полная чушь. А ещё предствьте это у нас в разных тредах…
К сожалению, подходы C++ неприменимы к Python и наоборот. И к тому же наличие какой-то функции в языке не требует её повсеместного применения.
Статические объекты есть, по моему, в любом ООП. Может, конечно, у меня мозги работают иначе, но тут я бы предупредил программистов что злоупотреблять значениями по умолчанию с функциями внутри не следует.
естественно!!! тот кто думает иначе — опасен для общества.

разумеется, все приведенные тут примеры — гипотетические.
Ну хорошо, давайте рассмотрим ваш пример на C++. Я перевел его в эквивалентный исходный код на Python (он немного «грязен» из-за «некрасивости» примера):
class A:
    a = 0
    
    def inc(self):
        A.a += 1
        return A.a


При вызове inc() в любом экземпляре класса A значение a (т. н. class attribute в терминологии Python) изменится сразу во всех экземплярах класса. Программист волен пользоваться и instance attribute — при этом аттрибут будет персональным для каждого экземпляра класса. Собственно, лично я не вижу никакой путаницы :) При многопоточном программировании надо будет всего лишь обернуть inc в lock-и.
естественно, при многопоточном доступе, и т.п. — почти что угодно может стать опасным.
потому к любой возможности надо подходить с умом, и соотвтственно использовать ее разумно.
а вот тут чучуть другой пример:

перменные спачала какбы инициализруются:
operator['+'][1] = lambda x: x+parse()
а функция parse определяется совсем потом.

вероятно, такойже выкрутас можно сделать и с объявлениями функций.

Ну вот эта лямбда-функция, как и любая другая функция, при запросе символа, которого нет в локальном пространстве имен, будет смотреть в более верхней(-ем?) «scope» — области видимости (технически — сначала в sys._getframe().f_locals, затем в f_globals и f_builtin) и так пока не найдет нужный символ, либо «наступит» NameError.

Поэтому значение parse станет известно непосредственно при вызове этой функции. Можно вообще написать нечто вида def abc(): return this_name_will_never_exist + 1 и оно нормально скомпилируется и даже запустится, правда, вывалив NameError.
тоесть имя ищется только при вычислении выражения,
а в случае с лямбдой это вычисление какраз откладывается.
Да, в принципе, всё верно.

Хочу только заметить, что лямбда функция и обычная функция (через def) суть есть одно и то же, они ничем не отличаются даже в мелочах. В лямбдах можно точно так же задавать keyword- и расширенные аргументы и делать аргументы по умолчанию.
о! про такие аргументы не задумывался.

с аргументами по умолчанию можно получить и лямбды без аргументов. просто так они не объявляются.
f = lambda(null=None):…
f()

и вродебы какието отличия всётаки были.
например, yield туда не впихнуть :)
а тогда это не функция, а генератор, почувствуйте разницу :)
Лямбда без аргументов делается просто: print lambda: 10 - 3. :) По вкусу можно написать print (lambda: 10 - 3), чтобы избежать неоднозначностей при возврате tuple-ов.
И, естественно, с помощью лямбд можно делать замыкания (closures), рекурсию и все другие прикольные вещи, которые можно сделать, используя именованную форму записи функции.
хм… странннно, почему у меня не получалось.
гдето я подогнался…
и хочу еще обратить внимание на то, что lambda (x, y): expr и lambda x, y: expr — две разных ф-ции. Первая принимает один параметр, который должен мочь распаковаться (т.е. быть iterable) в ровно два элемента, тогда как вторая функция принимает два аргумента. Пример использования первой:
t = (a, b) # либо [a, b], iter([a, b]) и т.д.
print (lambda (x, y): x + y)(t)

или короче print (lambda (x, y): x + y)((a, b)) (скобки не лишние).
Вторая используется, соответственно, print (lambda x, y: x + y)(a, b).
Или, если взять t из первого примера, то так: print (lambda x, y: x + y)(*t).

Надеюсь, я всех окончательно запутал :)
Так же возможны различные сочетания positional и keyword аргументов.

def foo(a,b,**kwargs,*args):?
Почти :) Вот как выглядит пример полного синтаксиса — def foo(a, b, c, d = 1, e = None, f = '3', *args, **kwarg). Порядок важен — сначала позиционные аргументы, затем keyword-аргументы, только затем *args и **kwarg. args и kwarg — просто общепринятые названия, и могут быть любыми по вкусу :)
да про названия то понятно.
непонятно, почему нельзя *args после **kwargs
Ну, так захотел Гвидо, это раз. А два — так написано в полной грамматике языка:

varargslist: ((fpdef ['=' test] ',')*
              ('*' NAME [',' '**' NAME] | '**' NAME) |
              fpdef ['=' test] (',' fpdef ['=' test])* [','])
потому что непонятен будет порядок сопоставления.
если у нас есть

func foo(a, b, c):
pass

мы можем ее вызвать и так:
x = [1, 2, 3]
foo(*x)

и так:
y = {«c»:4, «b»:2, «a»:17}
foo(**y)

и даже эдак
z = {«b»: 5, «c»:2}
t = [1]
foo(*t, **z)

при обратном порядке аргументов (сначала keyword, потом positional) — будет непонятен порядок их сопоставления
Функции — это практически неисчерпаемая тема. Правда, при углубленном изучении придётся вдаваться в основы ФП, но, может, это и к лучшему.

Мне кажется, было бы полезно для начала рассказать о лямбде, map, reduce и прочих (как вариант следующих выпусков :) ). О карринге. Это достаточно универсальные вещи, которые в другом языке могут пригодиться.
О, действительно. Первая как-то вообще не заметил.
точно-точно, а вместо всего хабра — гугл
А еще можно было не писать этот комментарий, потому что это и так ведь всем понятно, а тем, кому не понятно, не смысла объяснять.
Спасибо за статью, как раз Питон нужен.
всегда пожалуйста
Автор не понимает причин имеющего место в Python поведения дефолтных парметров функций: ни слова про mutable/immutable.

При этом автор пытается объяснять это поведение обоснованно задающим вопросы читателям. Читатели в недоумении, имидж Python в жопе. Все счастливы.

Руки за такие статьи отрывать.

Начинающим про Python читать здесь: www.intuit.ru/department/pl/python/
слишком умный — напиши лучше! кто не дает?

а то ходить и гадить — умных много. а включить мозг, и подумать что в статья для начинающих — допустимы упрощения, это видимо слишком сложно.
Я дал ссылку на то где написано лучше.
я могу 3 десятка ссылок найти и постить их в каждый топик на хабре. но смысл в том что сначала стоит что-то сделать самому. а не написав 30 коментариев учить всех жизни
я код пишу, а не комментарии на хабре.
кстати, код пишу сам.
ну так и писали бы…
я тоже в принципе не статьями на жизнь зарабатываю. но это ж тут не при чем.
тем более что в данном случае mutable/immutable — не более чем красивые слова.
а не объяснение причины такого поведения.
Это кто вам рассказал, что эти слова красивые?

Объяснением такого поведения является как раз различная обработка mutable и immutable объектов в параметрах функций. Я сам до конца не понимаю причин такого поведения, потому и не пишу таких опусов.

Почитайте сами Сузи по ссылке, вам тоже полезно будет.

А насчет упрощать: это вы нам, дуракам, чтоб попроще, чтоб мы поняли, объяснили. Спасибо вам большое!
если для вас начинающий == дурак, мне вас жаль, но тем не менее — не обощайте.
mutable и immutable — это значит изменяемый и неизменный. параметры по умолчанию — mutable. почему — я честно сказал что не знаю. дда и вам чтение романа не сильно помогло. но тем не менее, хотя бы как данность — это следует принять.
или мне обойти эту тему?

и вообще -вы уверенны что тут есть какой-то скрытый «подсмысл»?
1. про дураков вы не поняли

2. про «параметры по умолчанию — mutable» я не понял:
tuple — immutable
list — mutable
и те и другие могу быть параметрами по умолчанию
по поводу параметров.
логично. но это неимеет отношения к параметрам по умолчанию не имеет. речь же идет о том что они прсваиваются один раз.
естественно что мутабельность классов стоит выше. но это тут не при чем. вопрос — почему такое поведение у параметров по-умолчанию в целом.
Автор постарался, написал статью, надо уважать это рвение, но не более, к сожалению.

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

Гвидон ещё в 1999 году писал шикарную книгу, в рунете она есть на русском. В ней ясно описаны структуры данных, именованые аргументы и прочие вещи, которые так удивляют находящихся тут людей. Это так, для начала.

Проблема со списками как со входным параметром? Узнайте, что это такое, список. И как передаются параметры функций в питоне. Об этих вещах доступно написано профессионалами. Сузи тут не зря предлагали почитать.

Если Вы пишете на питоне, то любИте язык, а не пишите посты, намекающие неосведомлённому программисту, что в питоне всё неясно и неоднозначно. Отсюда и начинают расти ноги, типа «велосипедисты», «пистонисты» и т.д.

От подобного отношения к языку страдает его представление. Давайте всё-таки уважать то, на чем разрабатываем и правильно описывать преимущества. А не в стиле: «ой-ой-ой, там такое… там списки не пересоздаются и т.д. и т.п.». Люди думают, что это бага и там нужен какой-то костыль, что неверно.

ЗЫ: прошу не указывать мне на то, что постов я не пишу, мне хватает, что я каждый год питонизирую 30 человек, из которых 10 продолжает разработку после обучения. Поэтому знаю, что материал надо излагать четко и ясно с нормальными примерами, точными ссылками и объяснениями, не разводя паники.
А я считаю, что вы:
1. никудышний специалист :)
2. не удосужились прочитать статью перед тем, как делать потуги её раскритиковать :)
3. кичитесь количеством бедняг, которые по неосведомленности посчитали вас программистом :)

А царь Гвидон рассмешил, да :) Может быть, оземь ударитесь три раза, полегчает? :)
А я считаю, что Вы зря переходите к оскорблению человека за то, что он выразил свое мнение о том, что не следует плодить нечеткие туториалы, когда лучше было бы помочь человеку указав правильное справочное руководство. Я конечно не призываю всех тыкать носами в гугол…

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

Если бы всё было хорошо, то не было бы подобных комментариев, типа:
ivlis: «Прочитал про дефолтные параметры интереса ради, ой ну и жуть это ваш питон. Можно прострелить себе ногу совершенно неожиданным способом!»

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

Собственно, конструктивно, по теме критики статьи, вы не сообщили ни-че-го. Если законспектировать ваше изречение, то это будет выглядеть так:
Статью прочитал, хотел порекомендовать, но не порекомендую, потому что я ничего не понял. То, что я ничего не понял — ваша вина, я должен был понять, потому что я должен был, а вы виноваты, что я не понял. И вот, тут тоже есть один, который ничего не понял. Ну вы же сами понимаете, что я хочу сказать, поэтому я не буду этого говорить, вы и так всё поняли, что я сказать-то хотел.


Исправитесь? :)
Вам сказать, что эта статья велосипед? Это велосипед.

Выше были ссылки где четко и доступно рассказывалось про это.

Закапываем?
Хорошему программисту достаточно и обычной официальной документации, идущей в комплекте с языком :) Бо-о-о-олее чем достаточно :)

А вы тут дискутируете далеко не над официальной документацией, обсасывая её значимость. Намёк понятен? :)
Намек дурацкий, т.к. было указано, что я просматривал подобную статью в целях рекомендации студентам новичкам.

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

ЗЫ: как же вы тут прикольно тандемно плюсуетесь, прямо радостно смотреть!
давайтееще теорию заговора развивать…
У меня плюсики закончились, увы :-)
А намёк — он целиком и полностью на целевую аудиторию рассчитан, тут извиняйте :)
зачем нужны книги по патону, если есть оф. документация и исходники?
собственно, закапывайтесь.
блин! сколько можно говорить!!!
если включить мозг, то я не писал что список в качестве входного параметра — проблема!
я написал что РАБОТАЕТ не совсемтак как ожидает новичек.
я написал что параметры инициализируются один раз. «значения по-умолчанию вычисляются и ассоциируются только один раз – в момент объявления функции»
остальное — вытекает из свойств используемых типов данных. какое еще объяснение вам, «профессионалам» надо?

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

ЗЫ собственно из за таких как вы — у нормальных людей отпадает желание что-то писать.
Блин, ну давайте мы не будем тут кипятиться. Кажись по одну сторону и цель одна — научить. Объяснили и объяснили, а теперь посмотрите как об этом писал Гвидо в своей книге (кстати, скоро он и вторую накропает :). Я потратил время на чтение статьи, дублирующей большое количество подобных и на пререкание с Вами… Вот жалко, что все упираются и говорят «я старался, писал… нет, ну я же старался». Другие мыслят так же, «он старался», поэтому будем минусовать всю критику и плюсовать подобных. Верной дорогой, как говорится.

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

удивитесь. я преподаю больше 2 лет. и в общем-то не только пайтон. пайтон сейчас просто инструмент основной работы.
и в общем-то у меня студентов выпущено не меньше. и я думаю даже не хуже.

и за свои статьи на храбре мне не стыдно. я их писал как краткий туториал, для быстрого «вхождения» в суть дела, а не книгу. и ссылки и на сузи и на россума и на курсы интуита и на «вглубь пайтона» дал сразу.

так все-таки, чем же плохо приведеноне объяснение «поведения параметров»-то?

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

Сейчас сделано почти как у Гвидона, только развесистей, поэтому под краткий туториал не совсем подпадает…

1. Терминология, «параметры по умолчанию» хорошо, а можно ещё «именованые аргументы», чтобы новичкам было проще понимать англопишущих товарищей. Этот термин проскакивает только в комментариях от вашего друга.

2. Изложение. Может лучше было бы сразу на примерах показать, что можно вот так, а можно вот так (код+результаты). А потом уже написать теорию о том, как и в каком порядке располагаются и присваиваются параметры. Про «подводные» камни было бы лучше писать назвав это дело, например, «особенности структур данных в питоне», отделив этот пункт от всех прочих, тем самым определив, как следует корректно обращаться со списками, как с аргументами, к примеру.

Увидимся на pyCon в следующем году?
— я писал кратко. попросили детальнее. пишу сейчас детальнее.
— об переводах терминов — долгая и отдельная тема, соласны? тем более что термины по сути немного отличаются логически.
— а про подводные камни я и написал

а на счет PyCon — вряд ли. мы еще рожей не вышли к клашный ряд лезть…
— Я тогда извиняюсь, что не заметил краткий пост на эту тему;
— Про переводы согласен, просто глаз немного резануло. Прикольная история на тему, ко мне подошла девушка и сказала: «я вот тут недопоняла про скрытые методы...», и книгу мне протягивает россумовскую. Видимо поздно было и я только глянув в книгу понял, что речь идет о приватном доступе :), гы.
— Да, но не выделили как важную часть. А это важно.

Про pyCon смешная тема, не относящаяся к делу:
Возможно видели: xkcd.com/541
А теперь пост про автора: pycon.blogspot.com/2009/02/randall-munroe.html
Такие дела.
… Терминология, «параметры по умолчанию» хорошо, а можно ещё «именованые аргументы»...
Думаю, вам, конечно же, известно, что «параметры по умолчанию и «именованные аргументы» — две больших разницы, поэтому просто будем считать, что вы нечаянно оговорились :)
Спасибо, что поправили, действительно в раже описался ;).
Sign up to leave a comment.

Articles

Change theme settings