netch: (Default)
[personal profile] netch
Если Питон вымрет, то самым толстым гвоздём в крышку гроба будет не система отступов, к которой привыкнуть - дело пары часов, не динамическая типизация и не отсутствие ограничения видимости при инкапсуляции, а клинически неестественная схема видимости переменных.

Простейший пример:


def main():
  p += 1
if __name__ == '__main__':
  p = 0
  main()


Оно отвечает:


Traceback (most recent call last):
  File "1.py", line 6, in ?
    main()
  File "1.py", line 3, in main
    p += 1
UnboundLocalError: local variable 'p' referenced before assignment


А теперь если убрать назначение p всё будет работать:


def main():
  print p
if __name__ == '__main__':
  p = 0
  main()


Но если мы после 'print p' добавим инкремент - всё снова сломается, и не выполнится даже print:


def main():
  print p
  p += 1
if __name__ == '__main__':
  p = 0
  main()


будет ошибка дословно повторяющая первый случай, 'print p' не сработает.

Смотрим как это сказано в описании языка (пункт 4.1, 'Naming and binding'):

Each occurrence of a name in the program text refers to the binding of that name established in the innermost function block containing the use.

Ну да, если внимательно вчитаться (и с поправкой далее сказанной очень туманно) что function block это и уровень модуля - да, поведение соответствует описанию. Только вопрос - из какой такой логики переменные можно читать (а заодно вызывать в них методы, и вообще вытворять всё что угодно), но нельзя делать только одно - присвоение?

Как для меня вывод однозначен - результат бессмысленной экономии на (в терминах перла) my и local.

global в использующем блоке это лечит (thx2 ormuz, я как-то пропустил из-за чрезмерной лаконичности документации). Но только по отношению к глобальным переменным (тем что в globals). И логика этого действия противоположна тому что принимается в более нормальных средствах - когда надо явно объявить переменную какая она (local, global, из внешнего блока) при жёстком контроле. Проверки компилятора и pychecker'а слабоваты.

Более скрытая вариация на ту же тему:


$ tail +1 main.py A.py
==> main.py <==
#!/usr/bin/env python
import A
from A import g1
if __name__ == '__main__':
    g1 = {}
    print id(g1), A.f1()
    A.g1 = g1
    print id(g1), A.f1()

==> A.py <==
## module A
g1 = None
def f1():
    return id(g1)


Запустив получаем:


136034476 135227424
136034476 136034476


Опять g1 оказалось локальным только потому что ему есть хотя бы одно присвоение. 'global g1' не помогло.

UPDATED (12:56) UPDATED(28.08 18:16)

Date: 2006-08-27 06:01 pm (UTC)
From: [identity profile] trivee.livejournal.com

> если ты сделаешь в main() чтение значения g1, то у тебя почему-то:) прочтётся A.g1. А вот присвоение - пойдёт отдельно.

Еще раз, постепенно.

Мне кажется, ты понимаешь import как способ изменить видимость переменных. Это не так.

"from A import g1" вводит имя g1 в модуле main. С этим именем связывается объект, который был связан с именем g1 в модуле A. Объект, а не имя. Мы не начинаем видеть переменную A.g1 как g1, мы получаем новую переменную g1, которая в начальный момент имеет то же значение.

После этого, когда ты делаешь присваивание g1 в main, ты изменяешь связывание этого имени в main. На каталог A это не оказывает никакого влияния. Что твой пример и иллюстирует.

Для полной ясности, попробуй вот так:

#!/usr/bin/env python
import A

from A import g1
print id(g1), id(A.g1) # both variables are bound with the same object

g1 = {}
print id(g1), id(A.g1) # variable in main is rebound, object identities are different

A.g1 = {}              
del(g1)
from A import g1
print id(g1), id(A.g1) # variable in A is rebound, g1 is reimported, now
                       # they are the same again

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

(Я бы не завелся, если бы единственным твоим тезисом было "у Питона неадекватная документация", что есть правда.)

Date: 2006-08-27 06:38 pm (UTC)
From: [identity profile] trivee.livejournal.com
> Никакого "начального момента" нет, это всё время одна и та же переменная, введённая в глобальные данного модуля. Что чётко и сказано в документации.

Совершенно неверно. Опять же, читай описание import, del, и изучай мой пример. Ты его прочел и запустил, ведь правда? И разобрался, как он работает, да?



Date: 2006-08-28 12:53 am (UTC)
From: [identity profile] trivee.livejournal.com

1) Первое утверждение совершенно неверно. from ... import присваивает имени в текущем контексте значение аналогичного имени в другом контексте. То есть в определенном смысле создает новую переменную.

A.py:
    g1 = 1

B.py:
    import A
    from A import g1
    A.g1 = 2
    print g1, A.g1

python B.py:
    1 2

В этом контексте нет никакой разницы между "from A import g1" и "g1 = A.g1". Что я тебе собственно и пытаюсь объяснить.

2) Второе утверждение правильно. Более того, "import" в блоке тоже создает локальные переменные:


A.py:
    g1 = 1

B.py:
    def f():
        from A import g1
        print "in f, g1 =", g1
    f()
    print "outside of f, g1 = ", g1

python B.py:
    in f, g1 = 1
    outside of f, g1 =
    Traceback (most recent call last):
      File "B.py", line 6, in ?
        print "outside of f, g1 = ", g1
    NameError: name 'g1' is not defined

Опять же, это все очень хорошо описано в 4.1 Naming and binding и PEP 227 - Statically Nested Scopes.

Поэтому вопрос к тебе: в чем собственно состоит "клиническая дурость" видимости имен в Питоне (если прочитать документацию)?

Date: 2006-08-28 10:47 am (UTC)
From: [identity profile] virkony.livejournal.com
A.py:
  g1=1
  g2=[1]

B.py:
  import A
  from A import g1, g2
  g1+=1
  g2+=[2]
  print A.g1, g1
  print A.g2, g2

python B.py:
1 2
[1, 2] [1, 2]

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

Date: 2006-08-28 11:05 am (UTC)
From: [identity profile] virkony.livejournal.com
class mumap:
    def __init__(self, proc, seq):
        self.__proc = proc
        self.__seq = seq
        self.__len__ = seq.__len__

    def __contains__(self, y):
        for val in self.__seq:
            if self.__proc(val) == y: return True
        return False

    def __eq__(self, y):
        if len(self) != len(y): return False
        i = iter(self.__seq)
        j = iter(y)
        try:
            if self._proc(i.next()) != j.next(): return False
        except StopIteration:
            return True

    def __getitem__(self, y): return self.__proc(self.__seq[y])
    def __getslice__(self, i, j): return mumap(self.__proc, self.__seq[i:j])
    def __iter__(self):
        i = iter(self.__seq)
        while True: yield self.__proc(i.next())
    def __str__(self): return ", ".join(self)


x = ["a","b"]

y = mumap(lambda x: x+"z", x)
print y
x[0]="g"
print y

Date: 2006-08-28 02:49 pm (UTC)
From: [identity profile] trivee.livejournal.com
> чем такая схема принципиально лучше схемы в стиле, например, перла с его my, local, use vars и теми ограничениями которые накладываются при -Mstrict?

Лучше, хуже - в данном случае сугубо вопрос личных стилистических предпочтений. Обе схемы внутренне вполне логичны и даже (my vs. global) в каком-то смысле симметричны. (Встроенного в язык аналога local в питоне вроде как нету?)

Date: 2006-08-28 06:16 am (UTC)
From: [identity profile] geovit.livejournal.com
Увидев в первый раз подобный вариант:

from A import g1
A.g1 = {чтототам}

поставил в голове птичку (v) Питон - НЕ МОДУЛА-2
дальше разбираться нужды пока не было.

Date: 2006-08-28 02:58 pm (UTC)
From: [identity profile] trivee.livejournal.com
Здесь обсуждают аналогичную проблему.

Date: 2006-08-28 04:43 pm (UTC)
From: [identity profile] trivee.livejournal.com
Эрлангом кто-то для чего-то пользуется? Ужас :)

Популярность языка программирования, как известно, обеспечивается:

(1) понятностью программ, написанных на этом языке

(2) рекламой языка и культуры

(3) техническими достоинствами

Перл выигрывает по критериям (2) и (3) (но читать код на перле нельзя), питон - (1) и (3) (но рекламы в мейнстриме ему явно не хватает).

Profile

netch: (Default)
netch

December 2023

S M T W T F S
     12
3456789
10111213141516
171819 20212223
24252627282930
31      

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Mar. 22nd, 2026 07:28 pm
Powered by Dreamwidth Studios