Феликс уже дал отличный ответ, но я думал, что сделаю сравнение скорости различных методов:
copy.deepcopy(old_list)
Copy()
, копирующий классы с глубокой копией Copy()
метод не копирует классы (только dicts / lists / tuples) for item in old_list: new_list.append(item)
[i for i in old_list]
(понимание списка ) copy.copy(old_list)
list(old_list)
new_list = []; new_list.extend(old_list)
old_list[:]
( list slicing ) Таким образом, самая быстрая сортировка списка. Но имейте в виду, что copy.copy()
, list[:]
и list(list)
, в отличие от copy.deepcopy()
и версии python, не копируют списки, словари и экземпляры класса в списке, поэтому, если оригиналы меняются, они будут меняться в скопированный список тоже и наоборот.
(Вот скрипт, если кто-то заинтересован или хочет поднять какие-либо проблемы:)
from copy import deepcopy
class old_class:
def __init__(self):
self.blah = 'blah'
class new_class(object):
def __init__(self):
self.blah = 'blah'
dignore = {str: None, unicode: None, int: None, type(None): None}
def Copy(obj, use_deepcopy=True):
t = type(obj)
if t in (list, tuple):
if t == tuple:
# Convert to a list if a tuple to
# allow assigning to when copying
is_tuple = True
obj = list(obj)
else:
# Otherwise just do a quick slice copy
obj = obj[:]
is_tuple = False
# Copy each item recursively
for x in xrange(len(obj)):
if type(obj[x]) in dignore:
continue
obj[x] = Copy(obj[x], use_deepcopy)
if is_tuple:
# Convert back into a tuple again
obj = tuple(obj)
elif t == dict:
# Use the fast shallow dict copy() method and copy any
# values which aren't immutable (like lists, dicts etc)
obj = obj.copy()
for k in obj:
if type(obj[k]) in dignore:
continue
obj[k] = Copy(obj[k], use_deepcopy)
elif t in dignore:
# Numeric or string/unicode?
# It's immutable, so ignore it!
pass
elif use_deepcopy:
obj = deepcopy(obj)
return obj
if __name__ == '__main__':
import copy
from time import time
num_times = 100000
L = [None, 'blah', 1, 543.4532,
['foo'], ('bar',), {'blah': 'blah'},
old_class(), new_class()]
t = time()
for i in xrange(num_times):
Copy(L)
print 'Custom Copy:', time()-t
t = time()
for i in xrange(num_times):
Copy(L, use_deepcopy=False)
print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t
t = time()
for i in xrange(num_times):
copy.copy(L)
print 'copy.copy:', time()-t
t = time()
for i in xrange(num_times):
copy.deepcopy(L)
print 'copy.deepcopy:', time()-t
t = time()
for i in xrange(num_times):
L[:]
print 'list slicing [:]:', time()-t
t = time()
for i in xrange(num_times):
list(L)
print 'list(L):', time()-t
t = time()
for i in xrange(num_times):
[i for i in L]
print 'list expression(L):', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(L)
print 'list extend:', time()-t
t = time()
for i in xrange(num_times):
a = []
for y in L:
a.append(y)
print 'list append:', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(i for i in L)
print 'generator expression extend:', time()-t
EDIT: добавлены классы старого стиля и задает тесты, и сделал версию python намного быстрее и добавил еще несколько методов, включая выражения списков и extend()
.
«hello» - это строка, то есть массив символов. const char*
является указателем на этот массив, поэтому, когда вы разыгрываете этот указатель, вы получаете значение первого элемента.
Как будто у вас есть
int a[] = {1, 2, 3};
int *b = a;
cout << *b << endl;
, вы просто напечатайте 1
.
Оператор <<
на std::cout
перегружен. Его поведение зависит от типа правильного операнда. (Это фактически несколько разных функций, все названы operator<<
, компилятор решает, какой из них вызывать.)
Если вы дадите ему char*
или const char*
, он обрабатывает операнд как указатель на (первый символ) строки C-стиля и печатает содержимое этой строки:
const char * terry = "hello";
cout << terry; // prints "hello"
Если вы даете ему значение char
, оно печатает это значение как символ:
cout << *terry; // prints "h"
cout << terry[0]; // the same
Если вы указали ему указатель типа void*
, он печатает это значение указателя (в определенном порядке реализации, обычно шестнадцатеричном):
cout << static_cast<const void*>(terry); // prints something like 0x4008e4
Обработка char*
или const char*
как указатель на строку C-стиля - это особый случай, и единственное, что я могу придумать, которое вызывает operator<<
для печати чего-то другого, кроме значения операнда. Причина этого восходит к корням C ++ в C, который не имеет типа «string» и манипулирует строками с помощью указателей char*
.
Существует множество других перегрузок для operator<<
, для различных целочисленные и числовые типы с плавающей запятой, для std::string
и т. д.
Причиной этого является то, что std::cout
будет обрабатывать char *
как указатель на (первый символ) строки стиля C и печатать его как таковой. Если вы хотите использовать адрес , вы можете просто передать его указателю, который не был обработан таким образом, например:
cout << (void *) terry;
(или используйте бросок const void *
, если вы беспокоитесь о том, чтобы отбросить созвездие, что-то, что не является проблемой в данном конкретном случае).
Если вы скорее пурист, чем прагматик, вы также можете использовать C ++ static_cast
по строкам:
cout << static_cast <const void *> (terry);
, хотя в этом конкретном случае это необязательно, приведение к void *
будет работать нормально. Следующий пример кода показывает все эти параметры в действии:
#include <iostream>
int main (void) {
const char *terry = "hello";
std::cout << terry << '\n';
std::cout << (void *) terry << '\n';
std::cout << (const void *) terry << '\n';
std::cout << static_cast<const void *> (terry) << '\n';
return 0;
}
вывод (адрес может быть другим в вашей среде):
hello
0x8048870
0x8048870
0x8048870
Обратите внимание, что при использовании кнопки static_cast
, вы должны убедиться, что вы не пытаетесь отбросить константу с помощью static_cast <void *>
(это для const_cast
). Это одна из проверок, выполненных более новыми C ++-переходами, и старинный стиль не имеет этого ограничения.
char*
как строку стиля C; он рассматривает его как указатель i> для (первого символа) строки стиля C.
– Keith Thompson
23 July 2013 в 15:47
cout перегружен, так что, когда вы даете ему char *, он будет печататься как указатель на строку стиля C. Таким образом, он печатает символы до тех пор, пока не ударит нулевой завершающий символ.
Если вы использовали printf вместо cout, вы увидите адрес. Вы также можете направить указатель на другой тип, скажем (void *), и вы также получите адрес.
printf
сам не решает, как он печатает, вам все равно придется использовать правильный спецификатор формата, так же, как вы должны использовать тот же тип в C ++. Например, printf
с %s
будет иметь ту же проблему, что и cout
с char *
. Чтобы получить указатель, вы должны использовать спецификатор формата %p
.
– paxdiablo
4 July 2015 в 04:52
Вы должны изменить свой код на это:
cout << static_cast<const void*>(terry);
Проблема в том, что оператор <<
перегружен для указателей на строки C-стиля для печати содержимого строки. Если вы вместо этого нарисуете его на необработанный указатель, вы будете иметь поведение по умолчанию для указателя печати, используя iostreams, как вы хотите.
ostream <<
перегружен для указателей на символы для печати строк. – Ivan Smirnov 23 July 2013 в 15:48