Поведение экземпляра Python со списками

Эта функция сильно вдохновлена ​​ответом @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;
}
5
задан Aran-Fey 13 July 2018 в 13:03
поделиться

5 ответов

Список передается как ссылка на функцию. Таким образом, список разделяется между глобальным пространством и функцией. Первое изменение изменяет список, и это изменение отражается в обоих пространствах. Но тогда вы делаете и присваиваете переменной списка. Это создает новый список в функции. Исходный список существует в глобальном пространстве, но он больше не существует в этой функции. Таким образом, все изменения, внесенные в список в функции из этой точки, видны только внутри функции.

Другой способ думать об этом экземпляре состоит в том, что этот список является типом контейнера. Первая строка функции меняет то, что находится в контейнере. Вторая строка (назначение) фактически изменяет используемый вами контейнер. Это то, что верно для списков, но также и для любого объекта. Вот почему решение, данное @Chris_Rands в комментариях, работает: оно изменяет то, что находится в контейнере, оно не меняет контейнер.

2
ответ дан jdowner 17 August 2018 в 12:47
поделиться
  • 1
    & quot; Передавать по ссылке & quot; несет багаж, что не совсем корректно с Python (но это достаточно хорошо). & quot; Передача по заданию & quot; стал популярным способом его описания, поскольку следует за семантикой назначения Python. – Steven Rumbalski 13 July 2018 в 13:27
  • 2
    @StevenRumbalski Спасибо, что указали это. Я действительно не думал о различии между ссылкой на объект и ссылкой на память, но это имеет смысл. Я тоже узнал что-то новое! :) – jdowner 13 July 2018 в 13:36

Нет, это не так, потому что в первой строке вы переопределяете первое значение параметра elements, а на втором вы определяете новую локальную переменную для функции.

0
ответ дан Andriy Ivaneyko 17 August 2018 в 12:47
поделиться

Глядя на 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)
0
ответ дан Ravinder Karra 17 August 2018 в 12:47
поделиться

Это классическая путаница ссылки на переменную 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, и это то, что результат показывает эмпирически.

1
ответ дан scharette 17 August 2018 в 12:47
поделиться

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

Затем вы создаете локальный экземпляр elements, модифицируете его и завершаете функцию. Поскольку elements в глобальной области действия были изменены ранее, вы видите «неожиданный» результат.

Проверьте https://docs.python.org/3/reference/executionmodel.html для более подробной информации.

0
ответ дан Shan 17 August 2018 в 12:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: