Pull to refresh

Comments 40

По 37. Не понимаю пример (вроде и так понятно, что объекты разные). Можете назвать пример языков, где бы с похожим формированием строк у двух объектов ссылки бы шли на одну область памяти?
Если записывать как a = a + b, то очевидно. А если a += 1, то уже может быть не так очевидно
>>> a = 'dog'
>>> b = 'dog'
>>> a is b # id(a) == id(b)
True
>>> a += ' cat'
>>> a
'dog cat'
>>> b
'dog'
>>> a is b
False


Кстати, немного удивил этот способ экономии памяти на одинаковых строках. Но уверен у разработчиков python есть аргументы почему это сделано так.

string interning, реализовано во многих языках

Да, но в python это распространяется на все неизменяемые объекты


>>> import sys
>>> sys.getrefcount(1)
815
>>> sys.getrefcount(0)
1215
>>> sys.getrefcount('')
455
>>> sys.getrefcount(())
8771
На самом деле нет.
Даже для чисел это работает только для небольших:
>>> a=123
>>> b=a+1
>>> c=b-1
>>> id(a),id(c)
(140730597696992, 140730597696992)
>>> a=12345
>>> b=a+1
>>> c=b-1
>>> id(a),id(c)
(2568231156208, 2568231156400)

В Java точно так же. Строки неизменяемые, и литералы хранятся в специальной области хипа (heap), называемой String Pool.
В момент присвоения строкового литерала компилятор ищет такую же строку в String Pool и возвращает ссылку на существующий объект либо создаёт новый. Это называется "интернирование" (interning).
Следует, однако, различать литералы и строки, созданные с использованием оператора new. Во втором случае всегда создаётся новый объект в куче (не в String Pool). К тому же у строк есть метод intern(), но детали здесь не буду приводить.

По 37. Чего-то пример вообще не в тему.
ИМХО, правильней проверка так:


proverb = 'Rise each day before the sun'
id(proverb) # -> 5691328
proverb += 'b'
id(proverb) # -> 7467712
16. Переворот строки
Намного изящней смотрится способ с переворотом строки срезом:
print("hello world"[::-1])  # dlrow olleh
Я бы добавил еще иллюстрацию задачи с определением набора уникальных символов в строке, пересечения и объединения таких наборов из нескольких строк.
Задачу удобно решать перейдя от строки к множествам
first_str = 'aabbcdef'
second_str = "cdefghhh"

first_set = set(first_str)    # символы без повторов
second_set = set(second_str)  # символы без повторов
print(first_set, second_set)
# {'c', 'a', 'd', 'e', 'f', 'b'} {'c', 'g', 'd', 'e', 'h', 'f'}

# Определеим пересечение и объединение
intersection_set = first_set & second_set   # пересечение
union_set = first_set | second_set          # объединение
print(intersection_set, union_set)
# {'c', 'd', 'e', 'f'} {'c', 'a', 'd', 'g', 'e', 'h', 'f', 'b'}

# вернемся к сортированным строкам
intersection_str = ''.join(sorted(intersection_set))
union_str = ''.join(sorted(union_set))
print(intersection_str, union_str)  # cdef abcdefgh

Еще распространенная задача — выделение из текста отдельных слов.
Вот пример решения регулярным выражением — stackoverflow.com/questions/6181763/converting-a-string-to-a-list-of-words

В 23 пункт по срезам добавьте, что step может быть отрицательным, и тогда перебор идет в обратном порядке, от конца к началу — это иногда очень удобно, например как в моем примере выше с переворотом строки.
Вместо {sign for sign in first_str} достаточно set(first_str)
Действительно, ступил, исправил выше.
Спасибо за дополнение!
40. Я бы использовал regex, компактней и быстрее работает:
>>> import re
>>> string = 'Hello 1 World 2'
>>> re.sub(r'[aeiou]', '', string)
'Hll 1 Wrld 2'

12. Как разделить строку по заданному символу?
Ещё есть интересный метод — rsplit(разбивает строку справа налево). Буквально на днях понадобилось мне разбить строки вида «1:2:3:4:5:data» по последнему разделителю. Сначала пробовал так «str.split(':',-1)» — не получилось. Погуглил — нашел rsplit. Да, это есть в офф. документации. Но в процессе гугления понял, что много народа об этом не знают.
Можно было и через split, но -1 нужно было в индекс среза ставить:
mystr = '1:2:3:4:5:data'
print(mystr.split(':')[-1])  # data
Но на длинных строках это будет не оптимально, rsplit() с ограничением 1 будет лучше:
print(mystr.rsplit(':', 1)[-1])  # data

«Разбить по последнему двоеточию» — это не то же самое, что «взять текст после последнего двоеточия».

41 тривиальный ответ на бестолковые вопросы о том о сём.
Вы бы уж до 42 дотянули, что ли…
Мне кажется вопросов действительно о строках тут мало. Тут многое про множества, парадигмы протоколов… но как-то неявно, неглубоко.
К примеру, интересно было бы упомянуть про различие между isdigit, isnumeric и isdecimal хотя бы в виде ссылки. Это может оказаться любопытным.
Также часто новички путаются со строковыми литералами в коде.


Там много нюансов и их можно было осветить, это было бы действительно информативно.
a = 'это '\
'одна строка'
b = ('а кто '
f'{random.choice(["не ", ""])}угадает '
'что здесь присвоится?'
)

Про юникод-символы много всякого можно рассказать вроде такого:


'копе\N{combining acute accent}йка \N{RUBLE SIGN} бережет'

Вариант B использовал для длинных строковых литералов, чтобы влезть в максимальную ширину строки. Выглядит лучше чем A, по-моему.

В .format() тоже можно как в f-строках
difficulty = 'easy'
thing = 'exam'
'That {thingy} was {how_hard}!'.format(thingy=thing, how_hard=difficulty)
#=> 'That exam was easy!'
''.join([c for c in string if c not in vowels])

А зачем тут список делать, если достаточно просто итерируемого объекта? Просто generator expression будет достаточно: ''.join(c for c in string if c not in vowels)

как раз сейчас учу пайтон, спасибо, за суперинформативный для меня лично пост)

36. partition() не просто разбивает строку и возвращает результат в виде кортежа, partition возвращает кортеж ровно из трёх элементов — подстрока до первого вхождения разделителя, разделитель, подстрока после первого вхождения разделителя.
27 — тут будет точнее сказать, что вернется символ с минимальным кодом в utf-8 (Судя по f-строкам речь идет про python3). Как следствие можно то же самое применить и к символам, которых нет в ascii

Пункт 35. Как объединить две строки


'string one' + ' ' + 'string two'

Зачем делать действие в таком виде? А если нужно будет сложить десяток строк? Конкатенация для каждого из плюсов создаёт промежуточный объект и является самым медленным способом работы со строками.
В данном случае лучше использовать либо метод " ".join(), куда вставить список строк для объединения, либо использовать упомянутый в пункте 8 синтаксис f-строк: f"{} {}".

Зачем делать действие в таком виде?


Наглядно же. И требуется обьединить 2 строки, а не N.
По 16 пункту, ИМХО, намного проще заюзать отрицательный срез
s = "Test string"
print(s[::-1]) # gnirts tseT
Для того чтобы «перевернуть» строку, её можно разбить, представив в виде списка символов, «перевернуть» список, и, объединив его элементы, сформировать новую строку.

'hello world'[::-1]
Это конечно все прекрасно, но нельзя в виде спойлеров сделать решения?
А так спасибо автору, хотя с некоторыми примерами не согласен
Очень много светлого текста на светло фоне:
В части 37 пункта, мог бы добавить, что, если смотреть укороченную строку, равную другой строке с тем же содержанием, то id изменится.
11)
Есть 3 метода определения состоит ли строка лишь из цифр:
isnumeric(), isdigit(), isdecimal()
На символы неарабских цифр или дробей они дают разные ответы.
Если проверка именно на арабские цифры, то лучше использовать isdecimal()

vals = ("038", "੦੩੮", "038",
        "⁰³⁸", "⒊⒏", "⓪③⑧",
        "↉⅛⅘", "ⅠⅢⅧ", "⑩⑬㊿", "壹貳參",
        "38.0", "-38"
        )

for s in vals:
    print(s, s.isnumeric(), s.isdigit(), s.isdecimal())

Как раз арабских цифр в вашем примере и не хватает, добавьте "۰۳۸"
К сожалению отредактировать я не смогу.
038 — арабские цифры
۰۳۸ — арабские цифры
Справедливости ради, подставил второе значение и был слегка удивлен результатом, у всех методов результат True.
В #40 квадратные скобки, в принципе, не особо-то и нужны (generator тоже iterable)
''.join(c for c in string if c not in vowels)
Хм, полагаю, "-1" за то, что я проглядел в комментариях аналогичный ответ или есть какие-то другие причины?
(40) будет читабельнее через translate:
>>> string = 'Hello 1 World 2'
>>> mapping = str.maketrans("", "", "aeiou");
>>> string.translate(mapping)
'Hll 1 Wrld 2'
32. Как узнать о том, что строка включает в себя только пробелы?

Не пробелы, а пробельные символы (whitespace).
>>> '\r  \n'.isspace()
True


Для объединения строк можно воспользоваться оператором +.
'string one' + ' ' + 'string two'
#=> 'string one string two'

Пример неудачен, со строковыми литералами это делать бессмысленно, можно обойтись без плюсов:
>>> 'string one'  ' ' 'string two'
'string one string two'


Стоит добавить что в py3.9 у строк есть весьма полезные методы .removeprefix() и .removesuffix()
Упомянутые в конце новые методы в 3.9 могут некоторым показаться излишними, ведь есть lstrip, rstrip, однако не все знают (и я до некоторых пор был в числе незнающих), что lstrip и rstrip работают иначе. Например:
"foooofobar".lstrip('foo') # 'bar'
"foooofobar".removeprefix('foo') # 'oofobar'

Sign up to leave a comment.