I’m running , a Telegram channel about and in general. Here are the best posts of August 2018. @pythonetc Python programming Factory method If you create new objects inside your , it may be better to pass them as arguments and have a factory method instead. It separates business logic from technical details on how objects are created. __init__ In this example accepts and to construct a database connection: __init__ host port class Query: def __init__(self, host, port): self._connection = Connection(host, port) The possible refactoring is: class Query: def __init__(self, connection): self._connection = connection @classmethod def create(cls, host, port): return cls(Connection(host, port)) This approach has at least these advantages: It makes dependency injection easy. You can do in your tests. Query(FakeConnection()) The class can have as many factory methods as needed; the connection may be constructed not only by and but also by cloning another connection, reading a config file or object, using the default, etc. host port Such factory methods can be turned into asynchronous functions; this is completely impossible for . __init__ super VS next The function allows referring to the base class. This can be extremely helpful in cases when a derived class wants to something to the method implementation instead of overriding it completely: super() add class BaseTestCase(TestCase): def setUp(self): self._db = create_db() class UserTestCase(BaseTestCase): def setUp(self): super().setUp() self._user = create_user() The function’s name doesn’t mean or . The word implies in this context (like in ). Despite what I said earlier, doesn't always refer to the base class, it can easily return a sibling. The proper name could be since the next class according to MRO is returned. excellent very good super above superintendent super() next() class Top: def foo(self): return 'top' class Left(Top): def foo(self): return super().foo() class Right(Top): def foo(self): return 'right' class Bottom(Left, Right): pass # prints 'right'print(Bottom().foo()) Mind that may produce different results since they depend on the MRO of the original call. super() >>> Bottom().foo()'right'>>> Left().foo()'top' Custom namespace for class creation The creation of a class consists of two big steps. First, the class body is evaluated, just like any function body. Second, the resulted namespace (the one that is returned by ) is used by a metaclass ( by default) to construct an actual class object. locals() type class Meta(type): def __new__(meta, name, bases, ns): print(ns) return super().__new__( meta, name, bases, ns ) class Foo(metaclass=Meta): B = 2 The above code prints . {'__module__': '__main__', '__qualname__': 'Foo', 'B': 3} Obviously, if you do something like , then the metaclass only knows about , since only that value is in . This limitation is based on the fact, that a metaclass works the body evaluation. B = 2; B = 3 B = 3 ns after However, you can interfere in the evaluation by providing . By default, a simple dictionary is used but you can provide a custom dictionary-like object using the metaclass method. custom namespace __prepare__ class CustomNamespace(dict): def __setitem__(self, key, value): print(f'{key} -> {value}') return super().__setitem__(key, value) class Meta(type): def __new__(meta, name, bases, ns): return super().__new__( meta, name, bases, ns ) @classmethod def __prepare__(metacls, cls, bases): return CustomNamespace() class Foo(metaclass=Meta): B = 2 B = 3 The output is the following: __module__ -> __main____qualname__ -> FooB -> 2B -> 3 And this is how is . enum.Enum protected from duplicates matplotlib is a complex and flexible Python plotting library. It's supported by a wide range of products, Jupyter and Pycharm including. matplotlib This is how you draw a simple fractal figure with : , see the image at the beginning of the article. matplotlib https://repl.it/@VadimPushtaev/myplotlib timezones support Python provides the powerful library to work with date and time: . The interesting part is, objects have the special interface for timezone support (namely the attribute), but this module only has limited support of its interface, leaving the rest of the job to different modules. datetime datetime tzinfo The most popular module for this job is . The tricky part is, doesn't fully satisfy interface. The documentation states this at one of the first lines: “This library differs from the documented Python API for tzinfo implementations.” pytz pytz tzinfo pytz You can’t use timezone objects as the attribute. If you try, you may get the absolute insane results: pytz tzinfo In : paris = pytz.timezone('Europe/Paris')In : str(datetime(2017, 1, 1, tzinfo=paris))Out: '2017-01-01 00:00:00+00:09' Look at that offset. The proper use of is following: +00:09 pytz In : str(paris.localize(datetime(2017, 1, 1)))Out: '2017-01-01 00:00:00+01:00' Also, after any arithmetic operations, you should your datetime object in case of offset changes (on the edge of the DST period for instance). normalize In : new_time = time + timedelta(days=2)In : str(new_time)Out: '2018-03-27 00:00:00+01:00'In : str(paris.normalize(new_time))Out: '2018-03-27 01:00:00+02:00' Since Python 3.6, it’s recommended to use instead of . It's fully compatible with , can be passed as an attribute, doesn't require , though works a bit slower. dateutil.tz pytz tzinfo normalize If you are interested why doesn't support API, or you wish to see more examples, consider reading the decent on the topic. pytz datetime article StopIteration magic Every call to returns the new value from the iterator unless an exception is raised. If this is , it means the iterator is exhausted and can supply no more values. If a generator is iterated, it automatically raises upon the end of the body: next(x) x StopIteration StopIteration >>> def one_two():... yield 1... yield 2...>>> i = one_two()>>> next(i)1>>> next(i)2>>> next(i)Traceback (most recent call last): File "<stdin>", line 1, in <module>StopIteration is automatically handled by tools that calls for you: StopIteration next >>> list(one_two())[1, 2] The problem is, any unexpected that is raised within a generator causes it to stop silently instead of actually raising an exception: StopIteration def one_two(): yield 1 yield 2 def one_two_repeat(n): for _ in range(n): i = one_two() yield next(i) yield next(i) yield next(i) print(list(one_two_repeat(3))) The last here is a mistake: is raised and makes to stop the iteration. The result is , surprisingly. yield StopIteration list(...) [1, 2] However, that was changed in Python 3.7. Such foreign is now replaced with : StopIteration RuntimeError Traceback (most recent call last): File "test.py", line 10, in one_two_repeat yield next(i)StopIteration The above exception was the direct cause of the following exception: Traceback (most recent call last): File "test.py", line 12, in <module> print(list(one_two_repeat(3)))RuntimeError: generator raised StopIteration You can enable the same behavior since Python 3.5 by . from __future__ import generator_stop