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-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

Page Summary

Style Credit

Expand Cut Tags

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