diff --git a/pythonetc/README.md b/pythonetc/README.md
index 0118d67..6148afa 100644
--- a/pythonetc/README.md
+++ b/pythonetc/README.md
@@ -12,16 +12,6 @@ Reasons to read posts from the cannel rather than here:
You don't need telegram to read the channel using the link above. If neither of it stops you, sure, go ahead, read it here.
-## To publish
-
-+ union
-+ lookup-error
-+ is
-+ del
-+ del2
-+ gc_is_finalized
-+ warnings
-
## To write
These are ideas for future posts. Let me know if you want to write a guest post on any of these topics.
diff --git a/pythonetc/del.md b/pythonetc/del.md
index 908180f..9286063 100644
--- a/pythonetc/del.md
+++ b/pythonetc/del.md
@@ -1,5 +1,7 @@
# del
+Published: 2022-08-23.
+
The `del` statement is used to delete things. It has a few distinct behaviors, depending on what is the specified target.
If a variable specified, it will be removed from the scope in which it is defined:
diff --git a/pythonetc/del2.md b/pythonetc/del2.md
index 8207560..6fb06d2 100644
--- a/pythonetc/del2.md
+++ b/pythonetc/del2.md
@@ -1,6 +1,8 @@
# `__del__`
-The method `__del__` is called on the object by the grabage collector when the last reference to the object is removed:
+Published: 2022-08-30.
+
+The method `__del__` is called on the object by the garbage collector when the last reference to the object is removed:
```python
class A:
@@ -19,7 +21,7 @@ f()
# destroying
```
-The method is used by python file object to close the descriptor when you don't need it anymore:
+The method is used by Python's `file` object to close the descriptor when you don't need it anymore:
```python
def f():
@@ -27,9 +29,9 @@ def f():
...
```
-However, you cannot safely rely on that the destructor (this is how it's called in other languages, like C) will be ever called. For instance, it can be not true in PyPy, MicroPython, or just if tthe garbage collector is disabled using `gc.disable()`.
+However, you cannot safely rely on that the destructor (this is how it's called in other languages, like C) will be ever called. For instance, it can be not true in PyPy, MicroPython, or just if the garbage collector is disabled using `gc.disable()`.
-The thumb up rule is to use the destructor for unimportant things. For example, `aiohttp.ClientSession` uses `__del__` to warn about an unclosed session:
+The thumb-up rule is to use the destructor only for unimportant things. For example, `aiohttp.ClientSession` uses `__del__` to warn about an unclosed session:
```python
def __del__(self) -> None:
diff --git a/pythonetc/gc-is-finalized.md b/pythonetc/gc-is-finalized.md
index 2e18ee5..ef27a5d 100644
--- a/pythonetc/gc-is-finalized.md
+++ b/pythonetc/gc-is-finalized.md
@@ -1,6 +1,8 @@
# gc.is_finalized
-By using `__del__` and global variables it is possible to leave a reference to the object after it was "destroyed":
+Published: 2022-09-06.
+
+By using `__del__` and global variables, it is possible to leave a reference to the object after it was "destroyed":
```python
runner = None
@@ -19,7 +21,7 @@ print(runner)
# <__main__.Lazarus object at 0x7f853df0a790>
```
-In the example above, `runner` points to exactly the same object as `lazarus` did and it's not destroyed. If you remove this reference, the object will stay in the memory forever because it's not tracked by the garbage collector anymore:
+In the example above, `runner` points to the same object as `lazarus` did and it's not destroyed. If you remove this reference, the object will stay in the memory forever because it's not tracked by the garbage collector anymore:
```python
del runner # it will NOT produce "destroying" message
@@ -27,7 +29,7 @@ del runner # it will NOT produce "destroying" message
This can lead to a strange situation when you have an object that escapes the tracking and will be never collected.
-In python 3.9, the function `gc.is_finalized` was introduced that tells you if the given object is a such runner:
+In Python 3.9, the function [gc.is_finalized](https://docs.python.org/3/library/gc.html#gc.is_finalized) was introduced that tells you if the given object is a such runner:
```python
import gc
@@ -37,4 +39,4 @@ del lazarus
gc.is_finalized(runner) # True
```
-It's hard to imagine situation when you'll actually need it, though. The main conclusion you can make out of it is that you can break things with a destructor, so don't overuse it.
+It's hard to imagine a situation when you'll need it, though. The main conclusion you can make out of it is that you can break things with a destructor, so don't overuse it.
diff --git a/pythonetc/is.md b/pythonetc/is.md
index 558309a..8c8bd9a 100644
--- a/pythonetc/is.md
+++ b/pythonetc/is.md
@@ -1,5 +1,7 @@
# is
+Published: 2022-08-16.
+
The operator `is` checks if the two given objects are the same object in the memory:
```python
@@ -25,15 +27,9 @@ type(1) == int # True
So, when to use `is` and when to use `==`? There are some best practices:
+ Use `is` to compare with `None`: `var is None`.
-
-+ Use `is` to compare with `True` and `False`. However, don't explicitly check for `True` and `False` in conditions, prefer just `if user.admin` instead of `if user.admin is True`. However, the latter can be useful in tests: `assert actual is True`.
-
-+ Use `isinstance` to compare types: `if isinstance(user, LoggedInUser)`. The big difference is that it allows subclasses. So if you have a class `Admin` which is subclass of `LoggedInUser`, it will pass this check.
-
++ Use `is` to compare with `True` and `False`. However, don't explicitly check for `True` and `False` in conditions, prefer just `if user.admin` instead of `if user.admin is True`. Still, the latter can be useful in tests: `assert actual is True`.
++ Use `isinstance` to compare types: `if isinstance(user, LoggedInUser)`. The big difference is that it allows subclasses. So if you have a class `Admin` which is subclass of `LoggedInUser`, it will pass `isinstance` check.
+ Use `is` in some rare cases when you explicitly want to allow only the given type without subclasses: `type(user) is Admin`. Keep in mind, that `mypy` will refine the type only for `isinstance` but not for `type is`.
-
+ Use `is` to compare [enum](https://docs.python.org/3/library/enum.html) members: `color is Color.RED`.
-
+ Use `==` in ORMs and query builders like [sqlalchemy](https://www.sqlalchemy.org/): `session.query(User).filter(User.admin == True)`. The reason is that `is` behavior cannot be redefined using magic methods but `==` can (using `__eq__`).
-
+ Use `==` in all other cases. In particular, always use `==` to compare values: `answer == 42`.
diff --git a/pythonetc/lookup-error.md b/pythonetc/lookup-error.md
index bb61838..08d9745 100644
--- a/pythonetc/lookup-error.md
+++ b/pythonetc/lookup-error.md
@@ -1,10 +1,16 @@
# LookupError
+Published: 2022-08-09
+
`LookupError` is a base class for `IndexError` and `KeyError`:
```python
+LookupError.__subclasses__()
+# [IndexError, KeyError, encodings.CodecRegistryError]
+
KeyError.mro()
# [KeyError, LookupError, Exception, BaseException, object]
+
IndexError.mro()
# [IndexError, LookupError, Exception, BaseException, object]
```
diff --git a/pythonetc/union.md b/pythonetc/union.md
index 56688e0..40cd4d7 100644
--- a/pythonetc/union.md
+++ b/pythonetc/union.md
@@ -1,8 +1,8 @@
# Union alias (PEP-604)
-Published: 28 December 2021, 18:00.
+Published: 2022-08-02.
-[PEP-604](https://www.python.org/dev/peps/pep-0604/) (landed in Python 3.10) introduced a new short syntax for `typing.Union` ([as we predicted](https://t.me/pythonetc/569)):
+[PEP-604](https://www.python.org/dev/peps/pep-0604/) (landed in Python 3.10) introduced a new short syntax for `typing.Union` ([as I predicted](https://t.me/pythonetc/569), but I messed up union with intersection, shame on me):
```python
def greet(name: str) -> str | None:
@@ -11,4 +11,4 @@ def greet(name: str) -> str | None:
return f"Hello, {name}"
```
-You already can use it in older Python versions by adding described in the previous post `from __future__ import annotations`, [mypy](http://mypy-lang.org/) will understand you.
+You already can use it in older Python versions by adding `from __future__ import annotations`, type checkers will understand you.
diff --git a/pythonetc/warnings.md b/pythonetc/warnings.md
index 79a78a3..ae0e6bb 100644
--- a/pythonetc/warnings.md
+++ b/pythonetc/warnings.md
@@ -1,6 +1,6 @@
# warnings
-The module [warnings](https://docs.python.org/3/library/warnings.html) allows to print, well, warnings. Most often, it is used to warn users of a library that the module, function, or argument they use is deprecated.
+The module [warnings](https://docs.python.org/3/library/warnings.html) allows to print, you've guessed it, warnings. Most often, it is used to warn users of a library that the module, function, or argument they use is deprecated.
```python
import warnings
@@ -21,11 +21,12 @@ f()
The output:
```python
-example.py:7: DeprecationWarning: function f is deprecated, use g instead
+example.py:7: DeprecationWarning:
+function f is deprecated, use g instead
warnings.warn(
```
-Note that `DeprecationWarning`, as well as [other warning categories](https://docs.python.org/3/library/warnings.html#warning-categories), is a built-in and doesn't need to be imported from anywhere.
+Note that `DeprecationWarning`, as well as [other warning categories](https://docs.python.org/3/library/warnings.html#warning-categories), is built-in and doesn't need to be imported from anywhere.
When running tests, pytest will collect all warnings and report them at the end. If you want to get the full traceback to the warning or enter there with a debugger, the easiest way to do so is to turn all warnings into exceptions:
@@ -33,7 +34,7 @@ When running tests, pytest will collect all warnings and report them at the end.
warnings.filterwarnings("error")
```
-On the production, you can suppress warnings. Or, better, turn them into proper log records, so it will collected wherever you collect logs:
+On the production, you can suppress warnings. Or, better, turn them into proper log records, so they will be collected wherever you collect logs:
```python
import logging