# +bytearray and str speed

    

index d4a2791..5274f60 100644
@@ -74,6 +74,9 @@ More:
1. ./lru-cache.md
1. ./functools-cache.md
1. ./tau.md
+1. ./str-append.md
+1. ./str-concat.md
+1. ./bytearray.md

Out of order:

@@ -85,10 +88,8 @@ Out of order:
Json indent
Turtle
-Bytearray
Subprocess and env vars
Subprocess pipe
-Fnmatch?
Unicode module
String.Template
String module consts
diff --git a/pythonetc/bytearray.md b/pythonetc/bytearray.md
new file mode 100644
index 0000000..0cef313
--- /dev/null
+++ b/pythonetc/bytearray.md
@@ -0,0 +1,20 @@
+Types str and bytes are immutable. As we learned in previous posts, + is optimized for str but sometimes you need a fairly mutable type. For such cases, there is bytearray type. It is a "hybrid" of bytes and list:
+
+python
+b = bytearray(b'hello, ')
+b.extend(b'@pythonetc')
+b
+# bytearray(b'hello, @pythonetc')
+
+b.upper()
+# bytearray(b'HELLO, @PYTHONETC')
+
+
+The type bytearray has all methods of both bytes and list except method sort:
+
+python
+set(dir(bytearray)) ^ (set(dir(bytes)) | set(dir(list)))
+# {'__alloc__', '__class_getitem__', '__getnewargs__', '__reversed__', 'sort'}
+
+
+If you're looking for reasons why there is no bytearray.sort, there is the only answer we found: [stackoverflow.com/a/22783330/8704691](https://stackoverflow.com/a/22783330/8704691).
diff --git a/pythonetc/str-append.md b/pythonetc/str-append.md
new file mode 100644
index 0000000..a1d4ed0
--- /dev/null
+++ b/pythonetc/str-append.md
@@ -0,0 +1,46 @@
+What is the fastest way to build a string from many substrings in a loop? In other words, how to concatenate fast when we don't know in advance how much strings we have? There are many discussions about it, and the common advice is that strings are immutable, so it's better to use a list and then str.join it. Let's not trust anyone and just check it.
+
+The straightforward solution:
+
+python
+%%timeit
+s = ''
+for _ in range(10*8):
+  s += 'a'
+# 4.04 µs ± 256 ns per loop
+
+
+Using lists:
+
+python
+%%timeit
+a = []
+for _ in range(10*8):
+  a.append('a')
+''.join(a)
+# 4.06 µs ± 144 ns per loop
+
+
+So, it's about the same. But we can go deeper. What about generator expressions?
+
+python
+%%timeit
+''.join('a' for _ in range(10*8))
+# 3.56 µs ± 95.9 ns per loop
+
+
+A bit faster. What if we use list comprehensions instead?
+
+python
+%%timeit
+''.join(['a' for _ in range(10*8)])
+# 2.52 µs ± 42.1 ns per loop
+
+
+Wow, this is 1.6x faster than what we had before. Can you make it faster?
+
+And there should be disclamer:
+
+1. Avoid [premature optimization](http://wiki.c2.com/?PrematureOptimization), value readability over performance when using a bit slower operation is tolerable.
+
+2. If you think that something is slow, prove it first. It can be different in your case.
diff --git a/pythonetc/str-concat.md b/pythonetc/str-concat.md
new file mode 100644
index 0000000..b3424bb
--- /dev/null
+++ b/pythonetc/str-concat.md
@@ -0,0 +1,67 @@
+Let's learn a bit more about strings performance. What if instead of unknown amount of strings we have only a few known variables?
+
+python
+s1 = 'hello, '
+s2 = '@pythonetc'
+
+%timeit s1+s2
+# 56.7 ns ± 6.17 ns per loop
+
+%timeit ''.join([s1, s2])
+# 110 ns ± 6.09 ns per loop
+
+%timeit '{}{}'.format(s1, s2)
+# 63.3 ns ± 6.69 ns per loop
+
+%timeit f'{s1}{s2}'
+# 57 ns ± 5.43 ns per loop
+
+
+No surprises here, + and f-strings are equaly good, str.format is quite close. But what if we have numbers instead?
+
+python
+n1 = 123
+n2 = 456
+%timeit str(n1)+str(n2)
+# 374 ns ± 7.09 ns per loop
+
+%timeit '{}{}'.format(n1, n2)
+# 249 ns ± 4.73 ns per loop
+
+%timeit f'{n1}{n2}'
+# 208 ns ± 3.49 ns per loop
+
+
+In this case, formatting is faster because it doesn't create intermediate strings. However, there is something else about f-strings. Let's measure how long it takes just to convert an int into a str:
+
+python
+%timeit str(n1)
+# 138 ns ± 4.86 ns per loop
+
+%timeit '{}'.format(n1)
+# 148 ns ± 3.49 ns per loop
+
+%timeit format(n1, '')
+# 91.8 ns ± 6.12 ns per loop
+
+%timeit f'{n1}'
+# 63.8 ns ± 6.13 ns per loop
+
+
+Wow, f-strings are twice faster than just str! This is because f-strings are part of the grammar but str is just a function that requires function-lookup machinery:
+
+python
+import dis
+dis.dis("f'{n1}'")
+  1           0 LOAD_NAME                0 (n1)
+              2 FORMAT_VALUE             0
+              4 RETURN_VALUE
+
+dis.dis("str(n1)")
+  1           0 LOAD_NAME                0 (str)
+