Эта функция сильно вдохновлена ответом @renocor. Это делает функцию многобайтового безопасного.
function str_replace_limit($search, $replace, $string, $limit)
{
$i = 0;
$searchLength = mb_strlen($search);
while(($pos = mb_strpos($string, $search)) !== false && $i < $limit)
{
$string = mb_substr_replace($string, $replace, $pos, $searchLength);
$i += 1;
}
return $string;
}
function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = null)
{
$string = (array)$string;
$encoding = is_null($encoding) ? mb_internal_encoding() : $encoding;
$length = is_null($length) ? mb_strlen($string) - $start : $length;
$string = array_map(function($str) use ($replacement, $start, $length, $encoding){
$begin = mb_substr($str, 0, $start, $encoding);
$end = mb_substr($str, ($start + $length), mb_strlen($str), $encoding);
return $begin . $replacement . $end;
}, $string);
return ( count($string) === 1 ) ? $string[0] : $string;
}
Список передается как ссылка на функцию. Таким образом, список разделяется между глобальным пространством и функцией. Первое изменение изменяет список, и это изменение отражается в обоих пространствах. Но тогда вы делаете и присваиваете переменной списка. Это создает новый список в функции. Исходный список существует в глобальном пространстве, но он больше не существует в этой функции. Таким образом, все изменения, внесенные в список в функции из этой точки, видны только внутри функции.
Другой способ думать об этом экземпляре состоит в том, что этот список является типом контейнера. Первая строка функции меняет то, что находится в контейнере. Вторая строка (назначение) фактически изменяет используемый вами контейнер. Это то, что верно для списков, но также и для любого объекта. Вот почему решение, данное @Chris_Rands в комментариях, работает: оно изменяет то, что находится в контейнере, оно не меняет контейнер.
Нет, это не так, потому что в первой строке вы переопределяете первое значение параметра elements
, а на втором вы определяете новую локальную переменную для функции.
Глядя на ID, вы поймете ...
def change(elements):
print('inner first elements ID ',id(elements))
elements[0] = 888
print('inner second elements ID ',id(elements))
elements = [-3, -1, -2, -3, -4]
print('inner third elements ID ',id(elements))
print('inner third numbers ID ',id(numbers))
numbers = [1, 4, 5]
print(numbers[0])
print('outer numbers ID ',id(numbers))
change(numbers)
print('c ',numbers[0])
print('d', numbers)
Это классическая путаница ссылки на переменную Python. Что я действительно хотел сделать, чтобы понять это, хотя и печатает ссылку, чтобы увидеть, что происходит.
def change(elements):
elements[0] = 888
print("ID of elements is: %d",id(elements))
elements = [-3, -1, -2, -3, -4]
print("ID of elements is: %d",id(elements))
print(elements[0])
numbers = [1, 4, 5]
print("ID of number is: %d",id(numbers))
print(numbers[0])
change(numbers)
print(numbers[0])
print(numbers)
>>>> ('ID of number is: %d', 140036366181584)
1
('ID of elements is: %d', 140036366181584)
('ID of elements is: %d', 140036366181944)
-3
888
[888, 4, 5]
Идентификатор здесь представляет собой размещение в памяти. Если вы запустите код, число может отличаться, но поведение остается прежним.
В основном, когда вы вызываете
elements[0] = 888
Вы на самом деле мутируете numbers
(тот же идентификатор 140036366181584
в моем примере).
Но , когда вы вызываете
elements = [-3, -1, -2, -3, -4]
. Вы создаете новый список (в моем примере - другой идентификатор 140036366181944
) и перенаправляете ему локальное имя elements
. Просто присвойте имя elements
другому объекту. Это уже не тот список.
Итак, на этом этапе все, что вы сделали с numbers
, изменило свой первый индекс со значением 888
, и это то, что результат показывает эмпирически.
В функции change
сначала вы используете elements
из внешней области, которая была передана в качестве аргумента и ссылается - может быть изменена внутри функции, а те, которые были изменены, будут влиять на объект даже вне локальной области.
Затем вы создаете локальный экземпляр elements
, модифицируете его и завершаете функцию. Поскольку elements
в глобальной области действия были изменены ранее, вы видите «неожиданный» результат.
Проверьте https://docs.python.org/3/reference/executionmodel.html для более подробной информации.