Каковы варианты клонирования или копирования списка в Python?
blockquote>В Python 3 мелкая копия может быть выполнена с помощью:
a_copy = a_list.copy()
В Python 2 и 3 вы можете получить мелкую копию с полным фрагментом оригинала:
a_copy = a_list[:]
Объяснение
Существует два семантических способа копирования списка. Неглубокая копия создает новый список тех же объектов, глубокая копия создает новый список, содержащий новые эквивалентные объекты.
Короткая копия списка
Неглубокая копия копирует только сам список, который является контейнером ссылок на объекты в списке. Если объекты, содержащиеся в них, являются изменяемыми и один из них изменен, это изменение будет отражено в обоих списках.
Существуют разные способы сделать это в Python 2 и 3. Пути Python 2 также будут работать в Python 3.
Python 2
В Python 2 , идиоматический способ создания мелкой копии списка состоит из полного фрагмента оригинала:
a_copy = a_list[:]
Вы также можете выполнить одно и то же, передав список через конструктор списка,
a_copy = list(a_list)
, но использование конструктора менее эффективно:
>>> timeit >>> l = range(20) >>> min(timeit.repeat(lambda: l[:])) 0.30504298210144043 >>> min(timeit.repeat(lambda: list(l))) 0.40698814392089844
Python 3
В Python 3 списки получают метод
list.copy
:a_copy = a_list.copy()
В Python 3.5:
>>> import timeit >>> l = list(range(20)) >>> min(timeit.repeat(lambda: l[:])) 0.38448613602668047 >>> min(timeit.repeat(lambda: list(l))) 0.6309100328944623 >>> min(timeit.repeat(lambda: l.copy())) 0.38122922903858125
Создание другого указателя делает not сделать копию
Используя new_list = my_list, тогда изменяет new_list каждый раз, когда изменяется my_list. Почему это?
blockquote>
my_list
- это просто имя, которое указывает на фактический список в памяти. Когда вы скажетеnew_list = my_list
, что вы не делаете копию, вы просто добавляете другое имя, указывающее на этот исходный список в памяти. У нас могут быть подобные проблемы, когда мы делаем копии списков.>>> l = [[], [], []] >>> l_copy = l[:] >>> l_copy [[], [], []] >>> l_copy[0].append('foo') >>> l_copy [['foo'], [], []] >>> l [['foo'], [], []]
Список - это всего лишь массив указателей на содержимое, поэтому мелкая копия просто копирует указатели, поэтому у вас есть два разных списка, но они имеют одинаковое содержимое. Чтобы сделать копии содержимого, вам нужна глубокая копия.
Глубокие копии
Чтобы сделать глубокую копию списка в Python 2 или 3, используйте
deepcopy
в модулеcopy
:import copy a_deep_copy = copy.deepcopy(a_list)
Чтобы продемонстрировать, как это позволяет нам создавать новые под-списки:
>>> import copy >>> l [['foo'], [], []] >>> l_deep_copy = copy.deepcopy(l) >>> l_deep_copy[0].pop() 'foo' >>> l_deep_copy [[], [], []] >>> l [['foo'], [], []]
Итак, мы видим, что глубокий скопированный список - это совсем другой список из оригинала. Вы можете перевернуть свою собственную функцию, но не надо. Вероятно, вы создадите ошибки, которых иначе не было бы, используя функцию глубокой печати стандартной библиотеки.
Не использовать
eval
Вы можете видеть, что это используется как способ to deepcopy, но не делайте этого:
problematic_deep_copy = eval(repr(a_list))
- Это опасно, особенно если вы оцениваете что-то из источника, которому вы не доверяете.
- Это не надежный, если подэлемент, который вы копируете, не имеет представления, которое может быть доказано для воспроизведения эквивалентного элемента.
- Он также менее эффективен.
В 64-битном Python 2.7:
>>> import timeit >>> import copy >>> l = range(10) >>> min(timeit.repeat(lambda: copy.deepcopy(l))) 27.55826997756958 >>> min(timeit.repeat(lambda: eval(repr(l)))) 29.04534101486206
на 64-битном Python 3.5:
>>> import timeit >>> import copy >>> l = list(range(10)) >>> min(timeit.repeat(lambda: copy.deepcopy(l))) 16.84255409205798 >>> min(timeit.repeat(lambda: eval(repr(l)))) 34.813894678023644
Командная строка Windows очень ограничена в этом отношении. Обходной путь заключается в создании «дорожной банки». Это jar, содержащий только файл Manifest.mf
, чей Class-Path
указывает пути к диску вашего длинного списка баннеров и т. Д. Теперь просто добавьте этот путь jar в ваш путь к командной строке. Это обычно более удобно, чем упаковка фактических ресурсов вместе.
Как я помню, пути к диску могут относиться к самому файлу jar . Таким образом, Manifest.mf
может выглядеть примерно так:
Class-Path: this.jar that.jar ../lib/other.jar
Если ваш pathing jar содержит в основном базовые ресурсы, то он не будет меняться слишком часто, но вы, вероятно, будете все равно хотите сгенерировать его где-нибудь в вашей сборке. Например:
<jar destfile="pathing.jar">
<manifest>
<attribute name="Class-Path" value="this.jar that.jar ../lib/other.jar"/>
</manifest>
</jar>
(я полагаю, вы действительно не имеете в виду DOS, но обратитесь к cmd.exe.)
Я думаю, что это ограничение CLASSPATH меньше, чем переменная среды / среды размер ограничение. В XP отдельные переменные среды могут быть размером 8k, вся среда ограничена 64k. Я не вижу, что вы попали бы в этот предел.
Ограничение на окна, ограничивающее длину командной строки, ограничено WindowsNT +, это 8k для cmd.exe. Эта команда ограничена. Может быть, у вас есть более чем 8 тысяч каталогов в вашей команде? Возможно, вам не повезло, тогда даже если вы разделите их, как , предложил Nick Berardi .
Если бы я был в вашей обуви, я бы загрузил утилиту соединения из MS: http://technet.microsoft.com/en-us/sysinternals/bb896768.aspx , а затем отобразите ваш " C: \ path "сказать" z: \ "и" c: \ path2 ", чтобы сказать" y: \ ". Таким образом, вы уменьшите 4 символа на элемент в своем classpath
.
set CLASS_PATH=C:\path\a\b\c;C:\path\e\f\g;
set CLASS_PATH=%CLASS_PATH%;C:\path2\a\b\c;C:\path2\e\f\g;
Теперь ваш путь к классу будет:
set CLASS_PATH=z\a\b\c;z\e\f\g;
set CLASS_PATH=%CLASS_PATH%;y:\a\b\c;y:\e\f\g;
Он может сделать больше в зависимости от вашего фактического classpath
.
mklink /D
- еще один, возможно, уже присутствует в более поздних версиях Windows.
– mgaert
16 December 2011 в 13:32
Я думаю, что ты за рулем без весла здесь. Командная строка имеет ограничение на аргументы для вызова программы.
У меня есть 2 sugestion, которые вы могли бы попробовать. Во-первых, перед запуском тестов junit вы можете позволить скрипту / ant_task создавать JAR-классы различных классов в пути к классам. Затем вы можете поместить JAR в путь к классам, который должен быть короче.
Другой способ, которым вы могли бы попробовать, - создать антскрипт для запуска JUNIT, в ANT не должно быть такого предела для записей в классе.
Как упоминает HuibertGill, я бы обернул это в скрипт сборки Ant так, чтобы вам не пришлось самостоятельно управлять всем этим.
Вы пытались уложить их?
set CLASS_PATH = c:\path
set ALT_A = %CLASS_PATH%\a\b\c;
set ALT_B = %CLASS_PATH%\e\f\g;
...
set ALL_PATHS = %CLASS_PATH%;%ALT_A%;%ALT_B%
Не было никакого решения проблемы, кроме как-то сделать путь класса более коротким, перемещая файлы jar в папку типа «C: \ jars».
Вы можете попробовать это
@echo off
set A=D:\jdk1.6.0_23\bin
set B=C:\Documents and Settings\674205\Desktop\JavaProj
set PATH="%PATH%;%A%;"
set CLASSPATH="%CLASSPATH%;%B%;"
перейти в командную строку и запустить его дважды (не знаю, почему .... я должен сделать это на машине с Windows XP), также пути r, установленные только для текущего сеанса командной строки
Начиная с Java 6 вы можете использовать групповые символы classpath .
Пример: foo/*
, относится ко всем .jar-файлам в каталоге foo
foo;foo/*
или foo/*;foo
. Порядок определяет, что загружено первым.