RSSAmplifier

Blog

Python Does What?!?

Kind of like "hey guys, check it out you can just duct tape down the dead-man's switch on this power tool and use it one handed". In Python.

pythondoeswhat.comRSS feed ↗25 posts

Latest posts

Enums make good singletons

It's simple and common to allocate a marker object to represent missing or null data. MISSING = object() There's a slightly more verbose construct with some advantages: import enum class MissingType(enum.Enum): MISSING = "MISSING" MISSING = MissingEnum.MISSING Type checkers understand that MISSING is the only possible value of MissingType; so you can use is checks: def or_1(val: float |…

Wisdom for the ages

>>>type(type) is type True

sequence unpack a dict

>>> a, b = {"a": 1, "b": 2} >>> a 'a'

Annotation Inheritance

Let's talk about annotations . Type annotations in Python are mostly a static declaration to a type-checker like mypy or pyright about the expected types. However, they are also a dynamic data structure which a growing number of libraries such as the original attrs and dataclasses in the standard library, and even sqlalchemy use at runtime. >>> from dataclasses import dataclass >>> >>> @dataclass…

Mock Everything

A mock object is meant to simulate any API for the purposes of testing. The python standard library includes MagicMock . >>> from unittest.mock import MagicMock >>> mock = MagicMock() >>> mock.a <MagicMock name='mock.a' id='281473174436496'> >>> mock[0] <MagicMock name='mock.__getitem__()' id='281473165975360'> >>> mock + 1 <MagicMock name='mock.__add__()' id='281473165479264'> However, there is…

Are they equal?

>>> a = []; a.append(a); a [[...]] >>> b = []; b.append(b); b [[...]] >>> a == b Traceback (most recent call last): File "<stdin>", line 1, in <module> RecursionError: maximum recursion depth exceeded in comparison

Not counting zeros

We all have our favorite way of intentionally raising an exception in Python. Some like referencing an undefined variable to get a simple NameError , others might import a module that doesn't exist for a bold ImportError . But the tasteful exceptioneer knows to reach for that classic computer-confounding conundrum: 1/0 for a satisfyingly descriptive DivisionByZero . So, when does dividing by 0 not…

Welcome to the float zone...

Consider a REPL with tw o tuples, a and b. >>> type(a), type(b) (<type 'tuple'>, <type 'tuple'>) >>> a == b True So far, so good. But let's dig deeper... >>> a[0] == b[0] False The tuples are equal, but their contents is not. >>> a is b True In fact, there was only ever one tuple. What is this madness? >>> a (nan,) Welcome to the float zone. Many parts of python assume that a is b implies a == b,…

They say a python tuple can&#39;t contain itself...

... but here at PDW we abhor that kind of defeatism! >>> import ctypes >>> tup = (None,) >>> ctypes.pythonapi.PyTuple_SetItem.argtypes = ctypes.c_void_p, ctypes.c_int, ctypes.c_void_p >>> ctypes.pythonapi.PyTuple_SetItem(id(tup), 0, id(tup)) 0 Showing the tuple itself is a little problematic >>> tup # ... hundreds of lines of parens ...…

So a list and a tuple walk into a sum()

As a direct side effect of glom 's 19.1.0 release , the authors here at PDW got to re-experience one of the more surprising behaviors of three of Python's most basic constructs: list() tuple() sum() Most experienced developers know the quickest way to combine a short list of short lists: list_of_lists = [[1], [2], [3, 4]] sum(list_of_lists, []) # [1, 2, 3, 4] Ah, nice and flat, much better. But…

kids these days think data structures grow on trees

Args and kwargs are great features of Python. There is a measurable (though highly variable) cost of them however: >>> timeit.timeit(lambda: (lambda a, b: None)(1, b=2)) 0.16460260000000204 >>> timeit.timeit(lambda: (lambda *a, **kw: None)(1, b=2)) 0.21245309999999762 >>> timeit.timeit(lambda: (lambda *a, **kw: None)(1, b=2)) - timeit.timeit(lambda: (lambda a, b: None)(1, b=2)) 0.14699769999992895…

python needs a frozenlist

>>> set() == frozenset() True >>> [] == () False

when no-ops attack VII: assignment&#39;s revenge

Let's define a very simple class: >>> class F(object): ... @staticmethod ... def f(): return "I'm such a simple function, nothing could go wrong" ... >>> F.f() "I'm such a simple function, nothing could go wrong" Now, let's do a trivial no-op to this class: >>> F.f = F.f Surely nothing changed, right? >>> F.f() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError:…

(i)t(er)able for one

When you expect that a sequence will only have one item, and are only interested in the first it is common to grab the zeroth element. This will fail if the sequence is unexpectedly empty, but you might unintentionally silently throw away extra elements: >>> a = 'a'[0] >>> a = ''[0] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: string index out of range >>> a =…

Captain, the python grammar can&#39;t take anymore!

The expressions are going to tear themselves to pieces! >>> 'a' .strip ( ) [ 0 ] 'a'

DISappearing and

Python has a very rich set of operators that can be overloaded. From __get__ to __getattr__ , __repr__ to __format__ , and __complex__ to __iadd__ you can modify almost every behavior of your type. Conspicuously absent however, are the boolean operators. This is why Django ORM and SQLAlchemy use bitwise & and | to represent SQL and / or. Let's take a closer look at how the Python compiler treats…

The Zen of Empty Lists

"There should be one-- and preferably only one --obvious way to do it" . One of the many philosophies that has earned Python its acclaim. But while the Zen of Python limits on the number of obvious ways, the Zen of Python says nothing about the boundless freedom of unobvious ways. Let's empty a list named bucket . The most obvious way is to simply not . 99 times out of 100, you want to assign a…

None on the left

A natural default, None is probably the most commonly assigned value in Python. But what happens if you move it to the left side of that equation? In Python 2: >>> None = 2 File "<stdin>", line 1 SyntaxError: cannot assign to None This is similar to what happens when you assign to a literal: >>> 1 = 2 File "<stdin>", line 1 SyntaxError: can't assign to literal In Python 3 this walk on the wild…

python3 set literals in 3, 2, 1....

>>> {1,2}.add(3) >>> {1}.add(2) >>> {}.add(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'dict' object has no attribute 'add' why no empty set literal: https://mail.python.org/pipermail/python-3000/2006-April/001286.html https://mail.python.org/pipermail/python-3000/2006-May/001666.html

a __main__ by any other __name__

$ cat <<EOF > what_is_happening.py if __name__ == "__main__": import what_is_happening else: print("what is happening?") EOF $ python what_is_happening.py what is happening? Ambiguous entrypoints can create a maze of state in your program. In case the above example doesn't seem so bad, lets make it worse. $ cat <<EOF > innocent_bystander.py import what_is_happening def func(): raise…

UnicodeDecode SyntaxError

When executing a bytecode for the '+' operation, an invalid byte will raise UnicodeDecodeError. However, when concatenating adjacent string and unicode constants, it will be a SyntaxError. (I guess because there is not byte-code executing this is happening at compile time.) >>> u'a' + '\xff' Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError : 'ascii' codec…

sqlite does what

>>> import sqlite3 >>> c = sqlite3.connect(':memory:') <sqlite3.Connection object at 0x10d25c9d0> >>> c.execute('select null and 1').fetchall() [(None,)] >>> c.execute('select null and 0').fetchall() [(0,)] >>> c.execute('select null or 1').fetchall() [(1,)] >>> c.execute('select null or 0').fetchall() [(None,)] SQlite's docs are fantastic: https://sqlite.org/nulls.html

a return to yield

I remember when, almost a decade ago, I was first discovering generators. It was a heady time, and I saw applications everywhere . def fib_gen(): x, y = 1, 1 while x < 100: x, y = y, x + y yield x return I also remember the first time I tried to mix a return value into my generator. def fib_gen(): x, y = 1, 1 while x < 100: x, y = y, x + y yield x return True Imagine my surprise, as I'm sure…

Bit by bit: CPU architecture

There are a variety of reasons you might want to know how many bits the architecture of the CPU running your Python program has. Maybe you're about to use some statically-compiled C, or maybe you're just taking a survey. Either way, you've got to know. One historical way way is: import sys IS_64BIT = sys.maxint > 2 ** 32 Except that sys.maxint is specific to Python 2. Being the crossover point…

When you can update locals()

There are two built-in functions, globals and locals. These return dicts of the contents of the global and local scope. Locals usually refers to the contents of a function, in which case it is a one-time copy. Updates to the dict do not change the local scope: >>> def local_fail(): ... a = 1 ... locals()['a'] = 2 ... print 'a is', a ... >>> local_fail() a is 1 However, in the body of a class…