LINUX.ORG.RU

Python и локальные переменные внутри цикла

 


0

2

Нет ли способа поиметь в Python'е локальные переменные внутри циклов? Такие, которые не будут загромождать область видимости вовне? Иначе, когда код разрастается на экран-другой, понимать, что к чему, становится всё труднее.

Я знаю, что для хорошего кода тела циклов выносят в функции и методы. Однако клепаемый код - это, зачастую, одноразовые скрипты для статистических расчётов. Которые пишутся в духе «посмотрим на графики от предыдущей итерации и добавим/удалим пяток строк». О проектировании часто речь не идёт вообще, потому как я часто не знаю, что буду писать дальше.

Python здесь - это замена MATLABу.

И таки да, нет ли способа сделать так, чтобы переменные внутри циклов были локальными?


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

AIv ★★★★★
()

нет ли способа сделать так, чтобы переменные внутри циклов были локальными?

Есть. Взять вместо прыщеподелки любой вменяемый язык программирования.

//lovesan

anonymous
()

А какая разница, локальные они для цикла или локальные для функции. Это же не Си, в Питоне их можно использовать повторно для следующего цикла.

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

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

Можете показать кодом?

Yak
() автор топика
Ответ на: комментарий от Yak
class Dummy: pass
...
   for ... :
      ns = Dummy()
      ns.a = ...
      b = ... ns.a ...
      ...
      del ns

Это например какой же?

ЛИСП же! Не связывайтесь с лавсанчегом, он упорот чуть более чем полностью.

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

Это не лавсан, да и упорот он не более иных сиплюсплюсников, явовщиков, хаскелистов, эрлангистов и т.д. (список можно продолжать).

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

Это я знаю. Я только не знаю, как его правильно делать выражением. Неужели и правда втыкать класс-затычку как у AIv?

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

Можно свой оператор assignment'а написать, возвращающий строчку для exec'а, который будет кроме просто «=» дампать переменные в специальные Set'ы, а также свой for, который будет подчищать за собой.

Но разумеется, так делать не нужно.

aedeph_ ★★
()

Сам себе придумал проблему, сам её и решай, мы-то тут при чём.

anonymous
()

В Perl'ике перед переменной достаточно поставить my, например.

Наверняка в питоне есть что-то подобное.

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

Я сразу скажу что я чайник, и не понимаю.

Если допустим я сделаю так:

with a() as A:
   for:
      do_smth(A)

то для A по окончании будет вызываться __exit__(), который может это A прибивать. И вроде бы это то же самое, что предлагает AIv. Нет?

alpha ★★★★★
()
Последнее исправление: alpha (всего исправлений: 1)
Ответ на: комментарий от zz
def mahlopp:
  for blah

mahloop()

def mahotherlopp:
  for blah

mahotherlopp()

Можно прямо в теле метода локальные функции делать.

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

А вообще можно даже одно имя пользовать.

zz ★★★★
()

Переменные внутри циклов и так локальные. Тебе нужен аналог let из лиспа или что? Такого нет. И в питоне это особо вообще никак не мешает - если тебе нужны такие же имена после цикла: вариант с del'ом уже предложили, второй вариант - берешь и переопределяешь переменные.

alienclaster ★★★
()
# coding: utf-8

# быдлокодим
def foo():
    while 1:
        old_globals = globals().keys()
        yield
        new_globals = globals().keys()
        for var in new_globals:
            if var not in old_globals: 
                globals().pop(var)
        yield
foo = iter(foo())

# используем
next(foo)
for i in xrange(5):
    j = k = i
next(foo)

# проверяем
print i, j, k

# профит!
Virtuos86 ★★★★★
()
Ответ на: комментарий от alienclaster

Переменные внутри циклов и так локальные.

falsch

Тело цикла не является блоком кода, вводящим отдельное локальное пространство имен. Поэтому переменные в цикле определяются в том же неймспейсе, где определен цикл (то бишь переменная цикла). Если циклы находятся на уровне модуля (как у ТС), то есть в глобальном пространстве имен, то и их переменные глобальны. Такое же поведение у list comprehensions было, поправили не помню в какой версии.

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от Virtuos86

опять же, на немного лохматых версиях питоши вместо

next(foo)

будет

foo.next()

Virtuos86 ★★★★★
()

Как вариант делай приставку к переменным local_ Только не забывай их обнулять. Будешь знать что в local_ нету ничего важного и не страшно если переменная с таким именем уже встречалась. Как я понял тебе же главное не обратится к уже существующей переменной или не переопределить уже существующею? тогда прокатит. Помоему самый простой вариант.

local_num, local_f = '', ''

matrixd
()

ТС, тебе не стыдно? Смотри сколько говнокода уже сгенерировано. Если портянка большая, то ответ напрашивается сам собой — разбить. Если это одноразовая большая портянка, то опять всё очевидно — забить. Проблема яйца выеденного не стоит.

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

Предыдущее? Хех, тогда только в функции циклы выносить, иначе костыли будут шикарные.

Или фигню типа:

import copy

a, b, c = 1, 2, 3

code = '''\
a, b, c = 4, 5, 6
'''
exec code in copy.deepcopy(globals())
print a, b, c

Код не проверял, не на чем. Но сомнительно, что глубокое копирование будет хорошо работать на реальных пользовательских объектах, как на сферических примерах.

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

Тело цикла не является блоком кода, вводящим отдельное локальное пространство имен. Поэтому переменные в цикле определяются в том же неймспейсе, где определен цикл (то бишь переменная цикла).

Да, действительно - это я фигню сказал, хотя сказал там же, что let отсутствует.

Если циклы находятся на уровне модуля (как у ТС), то есть в глобальном пространстве имен, то и их переменные глобальны.

Не очень могу представить, зачем в библиотеки циклам бы находиться внутри модуля, а не в функции / классе...

Такое же поведение у list comprehensions было, поправили не помню в какой версии

Воистену быдлоязычок :)

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

Не очень могу представить, зачем в библиотеки циклам бы находиться внутри модуля, а не в функции / классе...

ТС написал, зачем ему. Хотя настоящий ответ — лень, первейший источник быдлокода :-}.

Воистену быдлоязычок :)

Но-но, без розжига. Не все так однозначно. Те же генераторные выражения такой болезнью изначально не страдали. А l.c. это практически сахар для цикла for с накопителем, потому и копирует его поведение. А оно вот такое. Короче, один из python tips.

Virtuos86 ★★★★★
()

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

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

P.S. за тролленг питона разве что зачёт. «Код разрастается» - ну, нашел причину)

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

Не не не, никакого deepcopy, это полный Содом. Изменение мутабельных (мутация того же объекта) трогать не надо, его могли, и это даже очень вероятно, изменять сознательно. А вот новый assignment в блоке, который затёр старый, следует откатить. Разумеется для питона этого сделать без переопределения (в голове, хотя бы) «=» не выйдет, поэтому и быдлоязычок, и говноскоупинг.

def x():
     a = False
     def y():
         print a
         a = True
     return y
aedeph_ ★★
()
Ответ на: комментарий от aedeph_

Потому что list(x for x in iterable) это сахар над list((x for x in iterable)), а генераторные выражения появились намного позднее генераторов списков.

Virtuos86 ★★★★★
()
Последнее исправление: Virtuos86 (всего исправлений: 1)
Ответ на: комментарий от aedeph_

Теперь понял. Однако, в питоне есть блоки кода — это функции, определяемые инструкциями «def» и «lambda». Если нужна функциональность блоков кода, то надо использовать их, а не пенять, что вещи, не предназначенные для этого, не удается использовать не по назначению. Теперь что касается переопределения «=». Есть два пути. Первый, чернокнижный: можно написать свой кодек, который при парсинге и разборе исходника будет запоминать определяемые переменные и бить по рукам при их повторном переопределении. Все это отслеживается на этапе даже не «компиляции», а чуть пораньше, и динамику не учитывает. Не говоря уже о том, что это уже и не питон будет. Кодек — это то, что указывается в модуле как

# coding: utf8

или

# -*- coding: cp1251 -*-

В принципе, для себя вполне приемлемый вариант.

Второй: наподобие того, что предложил AIv. Пишем свой класс-неймспейс, переопределяем для него __getattribute__/__setattr__, создаем инстанс этого класса (назовем его «let»), переменные регистрируем как атрибуты let. Дальше контролируем доступ к ним как угодно. Я такое видел, имхо неизящно и избыточно.

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

Странно, всегда считал, что genexpr появился за одну минорную версию до lc, но был неправ, 2.0 (2000) vs 2.4 (2002)

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

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

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

Мне понравился вариант с inline def функцией и её мгновенного вызова, не столь красиво и засирает собой пространство имён (в отличии от лямбды), но работает.

С логикой на __getattr__'ах и __setattr__'ах я тоже код видел, js-прототип стайл, выглядело чрезвычайно некрасиво, ruby тут конечно гораздо лучше.

ps: Семантику определения необходимости инициализировать локальные переменные вместо глобальных в 3 так и не починили.

aedeph_ ★★
()
Последнее исправление: aedeph_ (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Видите ли, этот б-длокод не предназначен для того, чтобы его было легко читать. Он предназначен для того, чтобы его было легко писать.

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

этот б-длокод не предназначен для того, чтобы его было легко читать

Не лги мне!

Yak> Иначе, когда код разрастается на экран-другой, понимать, что к чему, становится всё труднее.

Он предназначен для того, чтобы его было легко писать.

А, ну это всё оправдывает.

tailgunner ★★★★★
()

эээ вроде есть же вложенность функций - следовательно через замыкания инстанть локальные окружения :)

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

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

Какое же говнище этот ваш Пайтон.

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

Совсем старый стал, память уже большого одного сообщения не держит?

Парень с тугой струёй быдлокода, очевидно же.

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

Совсем старый стал, память уже большого одного сообщения не держит?

У тебя же рефлексия.

Парень с тугой струёй быдлокода

Эту струю сгенерировало несколько участников. Ты тоже отметился, кстати.

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