Как стать автором
Обновить

Комментарии 33

nonlocal и global для модификации переменных на один уровень выше

не на один уровень выше, а ближайший выше, исключая глобальную
ну это и имелось ввиду, я не знаю какая формулировка понятнее
такой код <> приводит к тому, что переменные x и y ссылаются на различные данные, а такой <> нет
Может потому что в первом случае вы присваиваете значение переменной(==ссылке) повторно, а во втором э… нет? Ничего себе идентичные ситуации. Причём тут вообще мутабельность?
Да, надо придумать пример получше
>>> можно догадаться, что передача осуществляется по ссылке
Почти, но не всегда.
Мутабельные элементы, типа списка, да передаются по ссылке.
А иммутабельные, например строка, передаются по значению.
Такая вот гибридная система.
А насчет многопоточности.
В multiprocessing есть потоки, а есть процессы.
У каждого свое применение.
Для задач io лучше применять потоки, а для cpu вычислений лучше работают процессы.
А иммутабельные, например строка, передаются по значению.

Нет, строки тоже передаются по ссылке, это элементарно проверяется с помощью is или id() в CPython

Вот тут вы не правы. Да id функция показывает один id, но это не из-за того, что переменная передалась по ссылке.
В python все есть объекты, даже простые числа, например 1 — это тоже объект. А переменные не хранят никаких значений, python связывает их с объектами, точнее хранят ссылку на объект.
Поэтому когда вы передаете строку в функцию, передается сам объект.
Например:
mylist = [1, 2]
def func(x):
x.append(3)
print(mylist) # [1, 2, 3]
s = 'stroka_1'
def func2(x):
x = 'stroka_2'
print(s) # stroka_1
Может несколько сумбурно объяснил, но почитайте про объекты в python. На эту тему очень много публикаций.
это не из-за того, что переменная передалась по ссылке.

Я не просто так упомянул CPython — в нём реализация id() для большинства объектов такова, что она возвращает именно что адрес в памяти, то есть по сути значение ссылки. Которая одинаковая, да.


Поэтому когда вы передаете строку в функцию, передается сам объект.

Когда я передаю строку в функцию, она принимает ссылку на объект. На тот же самый объект. Переменная — это по сути ссылка с именем. Разные переменные могут ссылаться на один и тот же объект.


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


Вы сами-то свой код запускали? Мало того что вы забыли вызвать функции, так даже после их вызова код будет вести себя совершенно не так, как вы показали. Вам стоит подтянуть основы питона.

Да, вызовы функций случайно упустил, каюсь.
Вы конечно правы, и я с вами согласен что передаются ссылки на объекты. Вот только статья называется Что нужно запомнить программисту, переходящему на Python. Ключевое слово переходящему с других языков. Такая система с объектами, что переменные не хранят никаких значений кроме ссылок на объекты вот и вводит в путаность переходящих.
Например, в C++ переменная является именованной областью памяти, хранящей значение. Поэтому передача переменной по ссылки в функцию подразумевает передачу ссылки именно на переменную, значение которой потом в функции можно изменить. В python же передается значение переменной, то есть непосредственно ссылка на объект. Из-за чего и возникает вопрос как переменные передаются в функцию, по значению или по ссылке.
Наверно хорошо сказали тут:
jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither
Для того, чтобы не расщеплять сущности это назвали call by sharing и поскольку оно же используется в большинстве распространённых языков (Java, JavaScript и т.д.), то непонятно кого это может смущать…
Ну я с вами согласен, вот только языков программирования много, а не только Java и JavaScript. я, например, их не знаю вовсе, а в Python перешел с C++, где система несколько иная: call-by-value.
Я в первом своем комментарии неправильно выразился, надо было написать, что если сравнивать с языками по типу C/C++.
А иммутабельные, например строка, передаются по значению.

Иммутабельность тут ни при чем. Все передается по ссылке.
>>> s = 'abc' * 1024 * 1024
>>> id(s)
2381293081856
>>> def foo(s):
...     return id(s)
...
>>> foo(s)
2381293081856
в реальной жизни ключом может быть только число или строка
Кортеж координат как ключ тоже вполне востребованное решение, когда мы описываем объекты на игровой доске, например.
А вообще вопрос про ключи словаря он на понимание хешируемости, там есть не совсем очевидные вещи, когда (1, 2) — допустимый ключ, а (1, [2]) — нет, хотя оба являются кортежем!
a = (1, [2, 3], 4)
print(type(a))   # <type 'tuple'>
b = {a: 1}       # TypeError: unhashable type: 'list'
однако нельзя затереть исходную ссылку в функции:

def try_del(mylist):
    mylist = []
    return mylist

mylist = [1,2]
try_del(mylist)
print(mylist)
В Вашем примере создалась новая локальная переменная внутри функции, из функции она сама не вернется если нет присвоения при вызове функции (последний мой пример).

Можно так, даже без возврата обнулить коллекцию по ссылке:
def try_del(mylist):
    mylist.clear()

mylist = [1,2]
try_del(mylist)
print(mylist)  # []

А если Вы хотите возвращаемое из функции значение, нужно обязательно присвоить переменной, «в никуда» оно не вернется.
def try_del(mylist):
    mylist = [4, 5]
    return mylist

mylist = [1,2]
mylist = try_del(mylist)
print(mylist)  # [4, 5]
Именно " нельзя затереть исходную ссылку в функции" как раз и выполняется. Т.е. — передачей значения какой-то переменной — изнутри функции нельзя изменить адрес объекта, на который ссылается эта переменная, если конечно ее не указать в ф-и как global (выделал с помощью тире, чтобы путаницы не было).
«Оставь надежду всяк сюда входящий» больше ничего не надо :)
А вот мне кажется неправильным описывать поведение функции, в точности соответствующее шикарной документации, и дополнять эпитетами «неожиданно» и «внезапно».
Не знаю кто как, а я живу в мире где время очень лимитированный ресурс и индивиды не безупречны и поэтому хороший инструмент должен вести себя не только в соответствии с документацией, но и в соответствии с логикой, понятной специалисту в этой сфере, что минимизирует число ошибок.
в какой-то момент перл исчерпал себя

Это как? Надоело писать доллары перед именами скалярных переменных?
А если серьёзно, чего не хватило в перле, из-за чего вы перешли на питон?

НЛО прилетело и опубликовало эту надпись здесь
Это долго рассказывать (некоторые моменты я когда-то описывал тут), если кратко, то я понял, что нет смысла тратить время на инструменты, которые ты не считаешь лучшими, которые не кажутся тебе спроектированными максимально круто и максимально крутыми специалистами, питон мне кажется крутым (почти как хаскел), а перл нет, понятно это не значит, что в перле всё плохо, а в питоне всё идеально.
Ну и перл просто умер, это и скучно (поддержка легаси кода) и сужает пространство возможностей во всем смыслах — поди найди работу на перле с каким-нибудь машинным обучением, или захочешь релоцироваться в другую страну, а там ни одной вакансии на перле.
Спасибо — недавно перешел с C/C++ embedded в python и веб хайлоад)
Открыл некоторые вещи незнание которых было бомбой замедленного действия — например про ссылки, формально знал об этом, но так как в основном поведение было как у переменных — бдительность усыпило

Про деление с остатком/целой частью не совсем верно, по факту в питоне знак определяется по делителю, а не по делимому как в си например, то есть если вы будите делить например 7%-3 как в математике у вас будет 7=-3*2+1
А в питоне будет -2.
https://en.wikipedia.org/wiki/Modulo_operation
Здесь довольно хорошая картинка поясняющая суть.

Ничего не понял, знак определяется не делителем или делимым, а математическим определением по которому остаток только положительный, а из этого вытекает всё остальное.
Вы бы всёж-таки сходили по ссылке, а? Выше определение действительно удобнее для математиков — но его сложнее реализовать «в железе», потому современные процессоры считают, что остаток должен иметь тот же знак, что и делитель и быть меньше его по абсолютной величине — а отсюда уже вытекает всё остальное. А питон имеет аж два варианта — но «математического», о котором вы говорите — не имеет.
Вообще-то я ходил по этим ссылкам ещё в тот раз, по ссылке написано:
Given two positive numbers, a (the dividend) and n (the divisor), a modulo n (abbreviated as a mod n) is the remainder of the Euclidean division of a by n.

The range of numbers for an integer modulo of n is 0 to n − 1

In mathematics, the result of the modulo operation is the remainder of the Euclidean division.

Если этого недостаточно, то вот ещё:
Given two integers a and b, with b ≠ 0, there exist unique integers q and r such that

a = bq + r

and

0 ≤ r < |b|,

Т.е. по математическому определению, остаток должен быть положительным, и понятное дело должно выполняться равенство и питон как раз и реализует это поведение — остаток всегда положительный и равенство выполняется, что и должен делать высокоуровневый язык.
Ну то есть это случай «смотрю в книгу — вижу фигу»? Вообще-то по ссылке написано не только какими способоами можно определять остаток, но и о том, что у Питона есть даже не один способ, а аж два — и оба не совпадают с математическим определением:
$ python3
Python 3.5.3 (default, Jan 19 2017, 14:11:04) 
[GCC 6.3.0 20170118] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import math
>>> print(-14 % -3)
-2
>>> print(math.fmod(-14,-3))
-2.0

и питон как раз и реализует это поведение — остаток всегда положительный и равенство выполняется, что и должен делать высокоуровневый язык.
Ужос сколько пафоса. А проверять — не пробовали? Это куда меньше времени бы заняло, чем написание простыней в комментариях…

Мне казалось, что времена Аристотеля, который писал трактаты на тему количества ног у мухи, вместо того, чтобы взять — и их посчитать… таки прошли… но похоже, что нет.
Как говориться — посыпаю голову пеплом и извиняюсь, я теперь ничего не понимаю, набросал тест, запускать pytest-3 -v modulo.py, если я ничего не натупил вечером, то до математики питону как до Луны, а я так верил.
В качестве пометки тем у кого пост в закладках, попалось неплохое видео от James Powell о метаклассах, декораторах, генераторах и менеджерах контекста, в принципе ничего нового я не узнал, но автор отлично объясняет.
Вот ещё.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории