Tue Aug 02 2022
I’m in holidays so I allow myself to skip a week of learning (sorry week 29!) ^^.
There was a subtle change in how Python 3.10 produces bytecode. This can lead to normal behaviors when you expect a strange one (yes, this sentence is fucked up). I was trying to reproduce a common Python problem with threads and race conditions and I couldn’t.
Before 3.10, this code was leading to an unexpected result, different from 1000000
:
import threading
a = 0
threads = []
def x():
global a
for i in range(1_000_000):
a += 1
for _ in range(10):
thread = threading.Thread(target=x)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
print(a) # The number was off here
Starting from 3.10, it does print 1000000.
Replacing a += 1
with a += int(1)
brings back the unexpected behavior.
The async/await
syntax is independent from the asyncio
module. Actually you can use different event loop than asyncio
like uvloop (which seems faster). (Thanks to my friend Olivier for the explanation!)
SQLite keeps a journal to keep the integrity of the database which makes it much slower. You can tweak this behavior if you think it’s not worth it (like on your local machine for development). You can learn more about it on Olivier’s blog.
EdgeDB is a database working with PostgreSQL under the hood. It allows you to work with objects instead of tables directly in the database. You can then use EdgeQL (instead of SQL) to query it. It also handles migrations and pretends to overcome the use of ORMs. Honestly, it sounds promising. I’m just a bit skeptical about the tooling and clients so far. The Python client looks quite rudimentary (no official client for PHP yet) and I wonder you map the database objects to your models and how you easily update an existing one. Anyway, I’ll keep an eye on this. (Thanks again to Olivier for this discovery!)
Weirdly, the Python range
function only accepts integers.
range(0, 10) # Ok
# TypeError: 'float' object cannot be interpreted as an integer
range(0.0, 10.0)
On the other hand, you can omit the first argument of range
. In this case it starts at 0
.
list(range(0, 10))
# is equivalent to
list(range(10))
Good to know: the limit of the Python range
is exclusive. (range(0, 10)
goes to 9
) where as the PHP one is inclusive (range(0, 10);
goes to 10
).
The range
function not only accepts integers but also floats and strings.
/*
[
"a",
"b",
...
"y",
"z",
]
*/
range('a', 'z');
/*
[
"A",
"B",
...
"Y",
"Z",
]
*/
range('A', 'Z');
This can be quite useful. On the other hand, range('a', 'Z')
doesn’t work as expected.
/*
[
"a",
"`",
"_",
"^",
"]",
"\",
"[",
"Z",
] ?
*/
range('a', 'Z');
To get the full a-Z range, use array_merge
(and not +
since +
is not case sensitive).
/*
[
"a",
"b",
...
"y",
"z",
]
*/
range('a', 'z') + range('A', 'Z'); // The first array is not overriden
/*
[
"a",
"b",
...
"Y",
"Z",
]
*/
array_merge(range('a', 'z'), range('A', 'Z'));
This can be quite useful. But still less elegant than the Python counterparts.
PHP:
// "ab...yz"
implode('', range('a', 'z'));
// "ab...YZ"
implode('', range('A', 'Z'));
// "ab...YZ"
implode('', array_merge(range('a', 'z'), range('A', 'Z')));
Python:
import string
string.ascii_lowercase # 'ab...yz'
string.ascii_uppercase # 'AB...YZ'
string.ascii_letters # 'ab...YZ'
If you want to generate a range of floats, use the third argument to determine the step.
/*
[
0.0,
0.1,
...
1.9,
2.0,
]
*/
range(0.0, 2.0, 0.1);
There is no native range iterator in PHP (as the native Python range
function in 3.x and the xrange
function in 2.x). Seems like you have to build your own.
Weird that it’s still not in the standard lib.
function xrange($start, $end, $step = 1) {
for ($i = $start; $i <= $end; $i += $step) {
yield $i;
}
}
foreach (xrange(0, 1000000) as $x) {
}
In PHP and Python you can use the yield from
expression if your iterator wants to send the values of another iterator directly.
PHP
function xrange($start, $end, $step = 1) {
for ($i = $start; $i <= $end; $i += $step) {
yield $i;
}
}
function my_iterator() {
/*
This is equivalent to
foreach (xrange(0, 10) as $x) {
yield $x;
}
*/
yield from xrange(0, 10);
}
/* [0, 1, ... 9, 10] */
iterator_to_array(my_iterator());
Python
def my_iterator():
# Equivalent to
# for x in xrange(0, 10):
# yield x
yield from range(0, 10)
# [0, 1, ... 8, 9]
list(my_iterator())