Skip to content

Latest commit

 

History

History
650 lines (618 loc) · 91.6 KB

python.md

File metadata and controls

650 lines (618 loc) · 91.6 KB

  • Ordering of python lists is persistent. src
  • Pycharm hinting:
"""
Exploit the workers by hanging on to outdated imperialist dogma which
perpetuates the economic and social differences in our society.

@type peasant: Person
@param peasant: Person to oppress.
                http://grammarist.com/usage/oppress-repress-suppress/
"""
def foo(a: 'what is a', b: 5 + 6, c: list) -> max(2, 9):
    # foo accepts a (commented), b (11), c (any kind of list), and returns 9
  • Under normal circumstances, register.simple_tag is all you need for your django templating needs.
  • To pretty-format a JSON file, do cat ugly.json | python -m json.tool > pretty.json.
  • re.VERBOSE, aka re.X, will ignore all whitespaces in a regex. Will Also ignore everything after a #.
  • Python does not raise a rounding exception when a large number is used. The typical check is n + 1 == n.
  • To speed up a read-only query, try adding .values_list(fields...) to a QuerySet, which returns simple tuples.
  • It is absolutely possible that django loaddata is a douchebag. Therefore, to import all objects without referential errors, use python manage.py loaddata init_dev.json, which provides all references before inserting.
  • Multiple args: calling a function(a, b, **kwargs) where kwargs contains a=4 or b=[] will raise an Exception.
  • dict(a=4,b=5) == {'a': 4, 'b': 5}
  • There is such thing as a for-else condition, where the else part doesn't execute only if the for loop is breaked from within.
  • for-else also runs else if the loop is never run (e.g. has 0 items).
  • There is also a while-else loop that runs when the variable changes to False.
  • Django creates the project for you.
  • Variables can be accessed from an inner scope, but the outer value of the same variable will not be changed. Use nonlocal to change the outer value.
  • The difference between global and nonlocal is nonlocal is used by an inner function to access a variable outside of it, while global is used by a top-level function to access a variable outside of it. nonlocal cannot be used in a top-level function.
  • *args is of type tuple, not list.
  • Use the for-else loop to avoid setting "flag variables", e.g. found = False .... Faster than flags in Python.
  • dict(a dict) clones the dict (for one level).
  • list(a list) clones the list (for one level). list(a) is not a.
  • These three are successively better than the former.
for k in d:
    print k, d[k]

for k, v in d.items():
    print k, v

for k, v in d.iteritems():  # Not python3
    print k, v

for k, v in six.iteritems(d):
    print k, v
  • dicts have a setdefault method: avoids KeyErrors. The method is equivalent to dic.get(k, default), except it will also set the default value given if dic[k] is missing.
  • Instead of updating dictionaries with another dictionary, there is a ChainMap in Python 3 that handles the common "defaults" use case.
  • Use full kwargs everywhere, except in loops
  • NamedTuple is a subclass of Tuple that lets you express what the tuple values actually are.
  • Built-in tuple unpacking (a, b = (1, 2)) is faster than loading them with indices.
  • Always concatenate strings with .join.
  • Python 3.4 can ignore all but some exceptions using with ignored(TypeError, ValueError, ...):. Actually, it might been renamed to contextlib.suppress.
  • Generator expressions, e.g. sum(i for i in list) is faster than sum([i for i in list]).
  • Django or nosetests runs any TestCase subclass in files with their names beginning with test when you run manage.py test.
  • django.http contains http error classes that handle the nitty gritty (e.g. allowed methods in 405)
  • json.dumps will never serialise integer keys to integer. If you have {1:1}, it gets converted to '{"1": 1}'. Integers are valid dict keys though.
  • If you are a jackass, you can write recursive lambdas.
  • Decorators can return functions that are already wrapped with decorators, by virtue that decorators can be wrapped in anything.
  • Every module is imported only once, but every import call will invoke a check to make sure the module is imported.
  • @functools.wraps(fn) is used to wrap a the wrapper function inside a decorator that helps preserve the original function's docstrings.
  • apply is a keyword. It is a bit like map.
  • "Almost every time you use reduce means you are doing something wrong", so reduce() was moved into functools.reduce() in Python3.
  • __contains__ controls the behaviour of a in obj.
  • Django smart_str along with smart_unicode probably solves all of Python 2's problems.
  • Python Enum Spoiler: 3.4+
  • The buffer type is used to create multiple "varied" reference to some parts of a large object in memory.
  • for creates a new scope. for foo in foo if foo is "bar" then it prints b, a, then r.
  • Keys can be pretty much anything, and they are not stringified: {None: 'b', 1: 5, <function __main__.<lambda>>: 4, '1': 6}
  • Taking that right back, lists cannot be dictionary keys.
  • "You don't mock out any part of our system, you mock out other people's code"
  • assertEquals is deprecated
  • If assertEqual receives two dicts, it automatically calls assertDictEqual.
  • itertools.cycle: for when you want to loop over something, over and over
  • Django's QueryDict can be converted to a dict by calling .dict().
  • StringIO.StringIO is not used for performance reasons. It is used to convert a string into a memory-bound file so functions that expect a file can work without writing the string to a file first.
  • There is a 3to2!
  • You can decorate functions with classes that have __call__!
  • Instance variables (class.foo == 'far') are class variables (class.foo == Class.foo) as long as the instance doesn't change its instance variable's value.
  • [:] (aka [None:None]) copies a list (Fast copy; Thanks Ford)
  • enumerate(): returns tuples with index as the first value
  • re.sub(pattern, repl, string) is technically re.sub(pattern, lambda repl: repl, string), which allows text munging.
  • yields are formally referred to as coroutines -- function with multiple entry/resume points.
  • The signal package has an alarm method that can timeout a long-running function.
  • Python3 exceptions are only accessible within the except block, for GC reasons. Interestingly, even if the same name existed outside the except block, Python3 will remove the variable of the same name from the outer scope.
  • Set generators are already available in python2.7.
  • The set's discard method makes stupid things like new_set = {x for x in old_set if x != 'foo'} a little bit redundant.
  • Lambda expressions can have parameter defaults, positional and keyword arguments!
  • Django Foreign keys default to None.
  • __future__ imports can only be done at the top of a file.
  • Override parse_start_url to diagnose Scrapy errors that occur on start urls.
  • You can and should use monads in your code in almost any programming language
  • a >> b can be overridden using the magic method __rshift__.
  • I don't know what the author was talking about, but python has something called the bidirectional generator which no one explained.
  • Override parse_start_url to diagnose Scrapy errors that occur on start urls.
  • In Django, admin.site.register(Model) doesn't need an admin (e.g. admin.site.register(Model, ModelAdmin)) if all you want is an automatic form.
  • \d isn't 0-9 -- it also contains digits from other locales.
  • Contrary to popular opinion, requirements.txt simply came from pip freeze > requirements.txt.
  • pip freeze also removes duplicate package requirements, so it helps you clean up the file in a way.
  • Generate random test urls using itertools.product: http://stackoverflow.com/questions/2535924/simple-way-to-create-possible-case/2535934#2535934
  • It is not necessary to urlunparse a url before generating a new url with parts changed. urlparse(url, scheme='http') changes the schema of that url to http. I lied. It only works for scheme.
  • unicode's translate is different from str's translate; their translation tables are not interchangeable (unicode strings require unicode tables)
  • Every single virtual environment directory (venv) has a bin/activate which you can ..
  • And, get this, your repository does not need to be cloned into the virtual environment directory.
  • Trick from the Internet: "To automatically unpack a list containing a single item, append a trailing comma to the variable name on the left of the assignment operation."
  • Tastypie allows only GET by default. authorization = Authorization() is required in the Meta class to allow insecure PATCHes.
  • An instance's class can be changed dynamically, restricted to user-defined classes only; it's unadvisable to do so regardless.
  • if statements do NOT have an else equivalent of for-else, i.e. if none of the branches are completely run, because if statements don't have breaks.
  • if statements do NOT have any kind of for-else-type block that is run whenever any one or more conditions above are run.
  • Python does not optimise tail calls.
  • def foo(a, (b, c), d) destructures the second tuple. (Thanks @sboparen) This is only a thing in python2.
  • Django TestCase has a @skip decorator that, if added to any def test_ methods, will disable the test. (from django.utils.unittest.case import skip)
  • Certain evidence points to recommend importing just a module (import module instead of from module import func1, func2) if a lot of things are used from that module. (Then again, how you can live with writing module.func1 and module.func2 all the time is beyond me.)
  • () is a thing, and (this,) is a thing. A trailing comma is required only if the tuple contains exactly one item.
  • setattr(a_django_object, ...) will silently update the object's __dict__. Doing the same setattr to an object will cause an AttributeError if the attribute was not defined in the class.
  • python -m webbrowser <url> opens... that url in your browser.
  • Python 3.0 ~ 3.2 don't have the u'unicode string literal' syntax, which would crash any python2 script that are otherwise the same as its python3 counterpart.
  • Apparently you can get easy_install from python-setuptools.
  • Apparently you can get pip from easy_install, too.
  • Python 2.7+ is the only python2 version that comes with the set notation ({1, 2, 3}).
  • PyLint expects all global variables to be constants, and be named in ALL_UPPERCASE
  • Want a monad for absolutely no work? Get PyMonad!
  • Marisa-trie consumes less memory than if you decide to build your own trie in python.
  • bytes(...): turn strings into sequences of anything from 0 to 255.
  • simplejson is subjectively better than json -- to use either, import simplejson as json.
  • It is an insanely stupid idea to have a folder that has the same name as one of the built-in libraries.
  • It wasn't possible to import (many things with brackets) until python 2.7.
  • range() can actually be faster in some cases - eg. if iterating over the same sequence multiple times. xrange() has to reconstruct the integer object every time, but range() will have real integer objects. (It will always perform worse in terms of memory however, and there is no such thing as Python2's range() in Python3.)
  • If you aren't being code reviewed or anything, you can subclass namedtuple like this:
class Foo(namedtuple('lol', 'a b c')): pass
  • namedtuple accepts pretty much anything for its second argument. These all work.
namedtuple('a', ['b', 'c'])
namedtuple('a', 'b, c')
namedtuple('a', 'b c')
namedtuple('a', """
b
c
""")
  • If a function is decorated with contextlib.contextmanager, then it can be used as a with statement. The function must contain exactly one yield, where things that happen before the yield works like __enter__, and what happens after the yield is treated like __exit__.
  • Eloborating on contextmanager, the yield must be run only once; the statement cannot be in a loop.
  • contextlib.suppress(BaseException) is basically the never_fail decorator. And oops, it is only for Python 3.
  • random.seed() is better than random.seed(0), because the parameter default is the system time.
  • hash(-2) is the same as hash(-1).
  • Objects that have an overridden eq cannot be hashed, unless their hash are also defined.
  • Python2 does float multiplications internally to compute results of integer multiplications, presumably to find out of two numbers multiplying each other will cause an overflow.
  • It is possible to __import__('python-module-with-dashes-in-the-filename', but if you create a file such as this, you deserve to be shot.
  • os.getenv('HOME') works, only because $HOME is populated by the shell.
  • You can compare tuples! (1,2) is less than (3, 4).
  • You can assign to spliced arrays: arr[:4] = [9,9] replaces the first 4 items of the array with [9,9].
  • round() doesn't work on Decimals. To round a Decimal to certain digits, do: Decimal(123.456789).quantize(Decimal("0.001")) # 3 decimal points
  • Decimal.quantize is called that because it also makes up more decimal points if you ask it to: Decimal(1234.56789).quantize(Decimal("0.000000000000000001")) # Decimal('1234.567890000000033979')
  • You can def foo(bar=NamedTupleAsDefaultValue()), but would you...?
  • arrow.replace() accepts singluar nouns like hour that replaces the component, or plural forms like hours that shifts the value relatively, instead.
  • Guido doesn't like merged_dict = dict(some_dict, **another_dict), and nor do you. (it only handles string keys)
  • In Python3, arguments can be forced named: with def foo(a, * must_use_kwargs_for_this_arg).
  • One-liner if clauses are executed before the assignment, so b = a.foo if a else 2 will not raise AttributeError even if a = None.
  • "Never (create, change, or delete models) directly" - Tom Christie
  • bool is a subclass of int, and cannot be subclassed further.
  • "Either or" is bool(a) != bool(b), or just operator.xor. This is different from nand, which is false when both are false, and not nor, which is true when both are true.
  • As much as tuples are immutable, its contents are:
>>> a = ([], [])
>>> a[0].append(1)
>>> a
([1], [])
  • logging.debug("{}".format(123)) builds strings unnecessarily when logging level is set to above debug. To combat this, use logging.debug(u"%s", 123) instead, where the arguments must be positional. For internal reference, the Gerrit ID is 626.
  • Strings can also be formatted traditionally with a keywords: 'Today is %(month)s %(day)s.') % {'month': m, 'day': d}
  • python -W all prints all PendingDeprecationWarnings, and is the preferred way to run python locally.
  • j is the only notation for complex numbers.
>>> abs(1+12i)
  File "<stdin>", line 1
    abs(1+12i)
            ^
SyntaxError: invalid syntax
>>> abs(1+12j)
12.041594578792296
  • The abs() of a complex number is the dot product of its real-imaginary plane. If this is not intended, use math.fabs() instead, which raises on imaginary numbers.
  • Unit test self.assert*s take a last parameter that is the failure message: self.assertIn(0, [1,2,3], "0 not found in list")
  • (str).casefold() is meant to normalise all variants of the same string, such as ['False', 'false', 'FALSE'] into something you can put into a switch-case block. Then again, there isn't switch-case in Python, only dict keys.
  • The try-finally block has no except, so it runs the finally block (which typically rolls back something), then raises the exception.
  • Although there are no docstring type-hinting standards, this one by PyCharm will do: :param parameter_name: x.y.ParameterClass | None
  • sum() takes a second parameter, start. It really means sum() + start.
  • history is always a variable in ipython.
  • Booleans are inherited from int, so you can add them together.
  • "Tim Peters also snuck some subtle jokes into the Zen itself (notice the dashes on the TOOWTDI line do it two different ways?"
  • Multiple assignments (e.g. a = b = []) assigns the same reference to each variable, even if the value is primitive (e.g. 5).
  • When called with three arguments, type acts like a constructor, so you can create new types in an inline fashion.
  • There's a whole package for the process.pid thing.
  • Sending gzip requests through the requests library is completely manual. You really have to construct a gzip stream and modify the headers.
  • As an asider, Transfer-Encoding: gzip is a better header than Content-Encoding: gzip because the latter does not imply the final content type of .gz.
  • In Python 3, unbound methods don't exist. There is unbound_method() in six that achieves a similar goal.
  • django-rest-swagger documents the API.
  • max(None, 0) is 0. max(0, None) is also 0. min(None, 0) is None. Therefore, None < 0. In fact, None < float('-inf').
  • UnicodeEncodeError and UnicodeDecodeError in a nutshell:
>>> "{}".format('Café')                  # str to str
'Caf\xc3\xa9'                            # ok
>>> u"{}".format(u'Café')                # utf8 to utf8
u'Caf\xe9'                               # ok
>>> u"{}".format('Café'.decode('utf8'))  # utf8 to utf8
u'Caf\xe9'                               # ok
>>> "{}".format(u'Café')                 # utf8 to str
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe9' in position 3: ordinal not in range(128)
>>> u"{}".format('Café')                 # str to utf8
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 3: ordinal not in range(128)
>>> str(db.Column('a') > db.Column('b'))
'a > b'  # look ma, not a bool
  • An Enum's class attributes have itself as its own class. isinstance(Color.green, Color) is True. Color.green == 1 is False.
  • But with every Enum having every attribute in its own class, they don't have access to other attributes: Color.red.blue # AttributeError
  • Depending on version, Python2 and 3 raise different errors when an object() is asked if it is equal to another object().
  • Exploiting the tuple syntax can make multidimentional "arrays" very easy to work with:
>>> a = {(1,2): 4}  # This can be a subclass of `dict` with list indexing
>>> a[1,2]
4
  • If you use python2 to run a script with a #!/... python3 shebang in it, it runs with python2, man. Duh.
  • UnicodeError is the superclass of UnicodeDecodeError, UnicodeEncodeError, and the lesser-known UnicodeTranslateError.
  • The exceptions library contains all built-in exceptions. All files have an implicit from exceptions import *.
  • mock.patch needs a direct reference to the function where it is called. To patch from a import b running in module c, patch c.b, not a.b.
  • Whatever you think -0.0 is, it exists... and it is equal to 0.0.
  • pwd.getpwall(), misleadingly, does not return a list of all passwords. They are usually * or x, due to the use of a shadow password system, explained in the link.
  • The implementation of keyword.iskeyword() is a real misfortune.
  • Python2 has WeakReferences too!
  • basestring is just str in python3.
  • Python3's type hinting enforces nothing. For the same reason, they called it annotations. For really enforcing these rules, consider mypy.
  • set().update(...) can handle lists as well, not just sets.
  • Splicing indices don't have to be integers... at least not now. [1,2,3][:None] returns a copy of [1,2,3], just as [1,2,3][:] would.
  • Python's foo = set() has an update(bar), too. It just adds what's in bar into foo.
  • Comparing any integer outside [-5, 256] with is is incorrect: "The current implementation keeps an array of integer objects for all integers between -5 and 256, when you create an int in that range you actually just get back a reference to the existing object."
  • However, 500 is 500 is always true. a = 500; b = 500; a is b is usually false.
  • Returning inside a try or an except block will still run the finally block, if one exists.
>>> def foo():
    try:
        print 'foo'
        raise Exception(4)
        return 5
    except:
        print 'baz'
        return 6
    finally:
        print 'bar'

>>> print foo()
foo
baz
bar
6
  • As far as SQLAlchemy is concerned, there is no difference between == true() and .is_(True). Howveer, pep8 and co. will complain about the former, so you should use the latter.
  • __all__ only concerns import * statements. It carries no weight anywhere else.
  • {} is definitely faster than dict(). This is also why you should always use literals where possible.
  • Django's TransactionTestCase is different from its TestCase in that while TestCase uses a transaction to roll back the database after each test, and--get this--TransactionTestCase does not use transactions. It just truncates all the tables.
  • list is a type.
  • You can test if a function was called with anything using mock.assert_called_once_with('foo', bar=ANY)
  • Welcome to unicode, where e < f < é:
>>> words = ['cafeteria', 'caffeine', 'café']
>>> words.sort()
>>> words
['cafeteria', 'caffeine', 'café']
  • There is no .none() in SQLAlchemy; only .filter(sqlalchemy.sql.false()). The latter still incurs one query.
  • ModelA.query.join(ModelB) does a JOIN on whichever db.relationship(ModelB) ModelA defines. Don't ask what happens if there are multiple relationships right now.
  • The entry_points thing in setup.py installs scripts inside your (venv path)/bin/ directory.
  • SQLAlchemy's equivalent of .values_list('id', flat=True) is .options(load_only('id')). I have not tested this.
  • SQLAlchemy's insert statement is really insert(table_model).values(**kwargs), mapping one-to-one to a query.
  • Putting code in the try-else block is meant to avoid catching the same exception in the else block, while still running a finally if the else block fails; basically, syntactic sugar for two try blocks.
  • sys.modules contains an import, e.g. datetime, only after you import it.
  • You can ''.join([u'a', u'\u3000', 'bunch', 'of', u'unicode', 'strings']), but not '{}'.format(u'a unicode \u3000 string'), because reasons. (python2)
  • dict() unzips iterables of iterables. dict( (('a', 'b'), ('c', 'd')) ) == {'a': 'b', 'c': 'd'} (and if there are key conflicts, keys with a higher list index prevails)
  • Providing the same kwargs to a partial()ed function overrides the default:
>>> import functools
>>> def foo(**kwargs):
...     print kwargs
...
>>> foo2 = functools.partial(foo, a=2)
>>> foo2()
{'a': 2}
>>> foo2(a=4)
{'a': 4}
  • Regex flags can be directly put inside the match string: like re.findall("/foo/s", "foo").
  • PEP 318 rejected the def foo @decorator (bar, baz): syntax on the basis that it no longer allows def foo( to be grepped. THANK YOU.
  • PuDB exists as a concept; it is a graphical pdb.
  • os.tmpnam() makes a temp path up for you, but the thing is vulnerable for some reason related to symlinks, so now you need to use os.tmpfile(), which opens the file for you as well.
  • textwrap.dedent is a standard library function.
  • When generating reports/exports of any sort, remember to also generate a metadata file that records how the data was generated at the time, so you can check the validity of the data later on.
  • pip has the ncu equivalent built in: pip list -o
  • Values in Enum cannot be compared with those in IntEnum, even when both values are exactly integer 1s.
  • PEP 440, which rings a bell because of CHEM 440, describes python's SemVer. The rc in X.Y.ZrcN is Release Candidate, not "RideCo", the vapourware company.
  • Of all the spacing requirements in python, the space between the n and [ in for i in[1,2,3,4] : is not necessary. Nor does the redundant space between ] and : matter. Your life is a lie.
  • numpy's array is not an instance of list.
  • numpy's odd way of telling if an array contains only 1 or 0 is ((arr == 0) | (arr == 1)).all(), or ~((arr != 0) & (arr != 1)).any().
  • "Celery" is python's way of saying "I will make a small mistake of choosing Celery now, to avoid a bigger mistake later on".
  • You can specify requirements for each platform and python version in requirements, like this: atomac==1.1.0; sys_platform == 'darwin'
  • Backticking a variable x is equivalent to repr(x), but since it is only for python2, it is better if you never learned it.
  • Doing from builtins import dict (provided by the future package) in a file automatically makes any dict()'s .values() an iterable, saving memory in python2 and 3 without .itervalues(). This does not apply to dict literals.
  • **kwargs do not need to contain variable name-only keys. You can call foo(**{' ': None}) if you want.
  • nosetests (Python?) accepts a -a foo parameter, that only runs tests decorated with @attr('foo').
  • ast.literal_eval('123 # comments') actually returns 123. It still throws ValueError for things like function calls, however.
  • Simon Pirschel, creator of udatetime, says that we should use udatetime because it is faster.
  • .format() can do many things. Useful examples include {:d} (as an integer), {:>10} (leftpad a string), {!r} (repr an object), and {foo.bar} (getattr).
  • numpy.split(array, 3) splits into 3 arrays. numpy.array_split(array, 3) splits into arrays of length 3.
  • Click is a far more intuitive version of optparse/argparse/whatever.
  • If you say (in python2 anyway) [b for b in c], but c happens to have no elements, then b is never defined.
  • The cPickle module in PyPy is written in pure python. Actually, the whole PyPy project might have been written in python, called Retricted Python.
  • a_string.replace('foo', '') can obviously still contain foo, if 'ffoooo'.replace('foo', '')
  • Thus spake the Lord: Thou shalt indent with four spaces. No more, no less. Four shall be the number of spaces thou shalt indent, and the number of thy indenting shall be four. Eight shalt thou not indent, nor either indent thou two, excepting that thou then proceed to four. Tabs are right out. -- Georg Brandl
  • The imports you write assume you run these scripts from the top level of the project. Imports don't magically work simply because there is an __init__.py in the directory.
  • The backspace character (chr(8)) is a caret shifting mechanism. One backspace moves the caret one character to the left, and the next character replaces the character that is already in that position. For example, print 'A' + chr(8) + 'B' prints just B (because the B replaced the A), and 'A' + chr(8) prints just A (because nothing replaced the A yet). print 'A' + 'B' + chr(8) + chr(8) + 'C' prints CB, because the caret is moved two characters back, and the C replaces the A.
  • The a, *_, b = [...] unpacking thing raises a ValueError if the list is fewer than two elements long. a, b = foo[0], foo[-1] does not do that.
  • type('', (), {})() will create an object that can have arbitrary attributes. 1, Up until python 3.7, it was impossible to have a function with more than 255 parameters, but a function name of more than 255 parameters is ok (you tested 100,000 characters).
  • A statement is a complete line of code that performs some action, while an expression is any section of the code that evaluates to a value. Expressions can be combined "horizontally" into larger expressions using operators, while statements can only be combined "vertically" by writing one after another, or with block constructs.
  • sets.Set is deprecated (removed in 3, even); set is not.
  • json.dumps(float('inf')) should fail because Infinity is not valid JSON. Yet, using simplejson, it succeeds. So if your python code generates any JSON that contains an Infinity in it, your JS will get rekt.
  • Too many items in your celery 3 queue? celery worker -Q queuename --purge
  • Avoiding attribute access in loops can have a measurable improvement in loop speed, and not only when the attributes are magic.
  • python -m runs that module as if the module's contents were __main__. There is little difference between python that.py and python -m 'that'.
  • You cannot monkey patch python's list. Well, you can, but literals won't use your subclass, and outside of a PoC, that won't be a smart thing to do.
  • The call object is supposed to be used by unpacking: args, kwargs = mock_func.call_args
  • simplejson.loads() has a for_json=False argument that can be turned True if you want any object with a for_json(self) method to return their own representation instead.
  • You can have exit(0) anywhere, in globals, in a function or in a list comprehension, and the script will exit with 0. In a generator, exit(0) takes effect whenever that generator outputs its first item.
  • Python3 has the raise from syntax, where given an exception (e.g. except ValueError as e), you can re-raise a different exception while noting what the original cause was, i.e. raise TypeError(...) from e. Default is to show the previous errors anyway. To supress it, raise ... from None (no context).
  • Sometimes %.0f rounds up. Sometimes %.0f rounds down. Try 10.5 (becomes 10) and 1.5 (becomes 2).
  • The set literal happily accepts repeated items, like {1,1,1}. It just comes out as {1}.
  • Given [1,2,3,4,5,6,7], bisect.bisect_left(that array, 4) will give you the index of 4, to the left of 4, and bisect.bisect_right(that array, 4) will give you the index of 5, to the right of 4.
  • Destructured additions cannot be done. That is, (a, b) += 1 ("add 1 to each of a and b") and (a, b) += (3, 4) ("add 3 to a and add 4 to b") will not work. You can still do a, b = a + 3, b + 4, though.
  • inspect.getfile(obj) works only on a class, so inspect.getfile(obj.__class__).
  • Almost everything in python has a __module__ attribute that tells you which module it came from. Primitives don't have it. Literals don't have it (because only primitives have literals). If you make a function or class in a REPL, then the module is __main__. The module for type is __builtin__, as is the case for other builtins, like min and even function. The module for built-in exceptions are exceptions, though, because that is where they are located. And, of course, if you attempt to inspect the builtin stuff, like inspect.getfile(type(None)), then you get a big fat TypeError: <module '__builtin__' (built-in)> is a built-in class.
  • Assuming because python wants only one (obvious) way to do something, John Roth once recommanded removing the / operator altogether, presumably replaced with the multiplying inverse. The community didn't like that.
  • Gunicorn is a WSGI server. You will still need Nginx.
  • If you don't pickle anything or parse any XML, python 3.6 isn't that slow compared to python 2.7.
  • You can multiply timedelta by a scalar.
  • You can conditionally define methods in a class by wrapping it in an if statement.
  • Lambda bodies are executed every run, even if they are one line, like a = lambda: datetime.now() would always give you a new time.
  • That one time the creator of Rest Framework said, hey, you should make your project compatible with the Rest Framework
  • SQLAlchemy lets you choose between different kinds of lazy loading for foreign key relations.
  • __new__(cls, ...) is a special method that takes the class as the first argument, but is not a @staticmethod or @classmethod ("special-cased so you need not declare it as such").
  • Even in python2.7, if you prefix any class attribute with __ (i.e. self.__foo = 1), trying to read that attribute from anything except self will raise an AttributeError. Instead, the interpreter does a little obfuscation such that the attribute is under a different key, usually (but not if subclassed) in the form of _ClassName__foo. Use dir(the instance) to view.
  • Keras specifically implements neural networks. It does not implement other kinds of machine learning.
  • It is completely possible for pip and pip3 to install something into .local/pip and have absolutely no effect, other than to make it impossible to install the package as root. First pip uninstall the-thing, and then reinstall it with sudo.
  • Just use sys.version_info >= (3, 0) to check if you are running python3, but some basestring NameError business.
  • Unlike JS, python does not have "dict unpacking", i.e. {foo, bar} = {'foo': 1, 'bar': 2}. You can write foo, bar = {'foo': 1, 'bar': 2}, but the result is random from an unsorted dict.
  • Running synchronous tasks in celery is not recommended (i.e. .get() in a @task)
  • Alembic uses the env.py that you generated with init to detect models. This file must import all the models that you want to manage.
  • Django ORM is considered "active record" (i.e. each row is an object), whereas SQLAlchemy is a "data mapper" (i.e. objects and rows don't necessarily map one to one). This forces many things to be manually configured in SQLAlchemy, for better or for worse.
  • In a declaration like parent = relationship("Parent", back_populates="child"), there needs to be a matching class Parent and an attribute called child. "When the backref keyword is used on a single relationship, it's exactly the same as if the above two relationships were created individually using back_populates on each."
  • In a SQLAlchemy column definition, there is no difference between an Integer and an Integer() instance.
  • Every return value of float(a: float) is just a, the same float object.
  • You cannot partial a class'es method from inside the class. At least you cannot do that without a stub, or until python 3.4's partialmethod() is introduced.
  • Number range filters like df[10 < df.column < 20] does not work in pandas. You need to do a double condition like df[(10 < df.column) & (df.column < 20)].
  • To pick multiple columns off a dataframe, you can't do df['a', 'b', 'c'] because that's intuitive and pythonic. You need to do df[['a', 'b', 'c']] instead...
  • Importing matplotlib.pyplot as plt is a standard convention.
  • Celery beat is a process that just puts tasks into queues in regular intervals. You still need a separate worker to listen to that queue.
  • Alembic stamp is the SQLAlchemy equivalent of faking a migration. Example: stamp fc34a1fc6e7d. You might need to get dirty anyway, as there is no unstamping.
  • .get(something) is just .filter(primary key == something).first().
  • On celery workers: "pre-fork for CPU instensive, eventlet/gevent for IO bound work ya prefork would block the workers while making long HTTP requests, preventing other work from being done. Async lets IO things happen more concurrently" - a guy who types "ya" instead of "yeah"
  • Alembic is worse than Django migrations in various ways. First, it does not auto detect table OR column renames. Second, it does not detect changes in contraints. Third, I'll make something up later.
  • mailbox is a standard library. It manipulates mailbox files (like .mbox).
  • Comparing with None using < or > in python3 raises a TypeError. None was previously just "less than everything".
  • You give Arrow an absurd date, like arrow.get(year=0, month=0, day=0), and it will give you the current time. Sure. But you do something completely reasonable, like arrow.get(year=1918, month=11, day=11), it will still give you the current time. "Yeah but that's before the epoch," you say? Nope. You're just calling it wrong. arrow.get() doesn't take year/month/day as arguments.
  • Requests' sessions are not just for making code cleaner; it also allows the library to share urllib3 connection pools, so the code makes fewer unnecessary connections to the target server.
  • For simple queries, if you don't like SQLAlchemyModel.query.filter(SQLAlchemyModel.field == thing), maybe you can use filter_by instead: SQLAlchemyModel.query.filter_by(field=thing).
  • You can implement custom states in celery, if for some reason you want to do that, by subclassing celery.states.state, which is a subclass of str.
  • Celery's revoked tasks will stay in memory until automatically discarded. There is no manual option. Apart from shutting the broker down and purging the queue there (sudo rabbitmqctl purge_queue 'queue_name'), there is no good way to purge revoked tasks from celery.
  • // is the floor division operator, which for 3.0 // 6 gives you 0.0 in either version, and still returns a float if either number is not an integer. It doesn't turn every result into integers.
  • Since tuples are immutable, defaulting a parameter to a tuple is uncommon, but fine.
  • A dict's .keys(), .values(), and .items() .viewkeys(), .viewvalues(), and .viewitems() have an official name called dictionary views. If the dict changes, so do the views.
  • Python3's super() need not specify the class and instance. In the event that the class has multiple parents, and you do something like super().foo(), it decides for you whichever class has the method foo first, which is the same behaviour as if you specify super(this class, this instance).foo().
  • You can't name a file with a period and import it normally.
  • A (function or compatible object)'s __dict__ (if you do stupid things like that) becomes populated with {'foo': 'bar'} if you choose to assign, say, a_function.foo = 'bar'.
  • You can override __instancecheck__(i) and __subclasscheck__(c) for a free pink slip.
  • a << b is "a shifted left by b zeros".
  • re.match will look for your pattern at the beginning of your string. re.search looks for your pattern anywhere in the string.
  • if not (): is a valid statement because () is a falsy tuple.
  • Python3 Exceptions do not have .message anymore.
  • The range() is not a generator because you can't call next() on it. And you can't call next() on it because you want some nice properties like 1 in range(5), which generators cannot offer, and index access range(5)[1], which generators also cannot offer.
  • Perhaps contradictory to the previous point, all generators are iterators so you should be able to iterate through any generator.
  • If you give a function a __call__, it does nothing with it.
  • Django's django.utils.six is said to be a bit different from the real six, under the section ### Additional customizations for Django ###.
  • The built-in cmp() was left in python 3.0.0 by mistake.
  • Function defaults are just in func.__defaults__.
  • "str.encode() always returns bytes, and bytes.decode() always returns str."
  • jupyter notebooks are a thing because people want to inline markdown with code. I am guessing you can do a lot of creative things from there.
  • ctypes does not just offer C types; it also allows external library functions to be called.
  • 2 is an available PyPI package name because you can't import 2. Still, 1 is taken for no reason.
  • EnvironmentError, IOError, and WindowsError are all aliases for OSError in python3.
  • The only free version of python supported on Google App Engine is 2.7.
  • isoweekday is 1-indexed, with 7 being Sunday, because, I don't know.
  • time.time is a function. datetime.time is a data type.
  • PEP 3109 explicitly says that "[the EXCEPTION] in raise EXCEPTION ... may be an exception class or an instance of an exception class".
  • Unlike what this page suggests, there are no namedtuple literals like color = (red=255, green=0, blue=0). Not in 2, not in 3.
  • VS code (when used for python) lacks "find usages" and "import this thing", but people like it.
  • async can go with the with statement as well (i.e. async with). See here for other concurrency-related examples.
  • There is a handy contextlib.closing(some_connection()) as connection thing that you can use to make sure a thing closes when the block exits.
  • A return statement in the finally block will return before a return statement in your try block returns.
  • PEP 515 describes underscores in numerals. 1_000_000 is really a million.
  • PEP 526 introduces the first syntax that is not an expression. Variable type annotation variable: int, bearing in mind that doesn't assign anything to the variable, is not an expression.
  • Guido and friend actually tried to distance their project from actual snakes, because the entire thing was supposed to be a Monty Python joke instead of a zoo, but finally gave up when O'Reilly printed a snake in front of their first python book.
  • A finally clause could not contain a continue until python3.8.
  • To get your query string from an SQLAlchemy expression, do str(the_expression.statement.compile()).
  • There is no non-literal one-liner (i.e. list(1, 2, 3)) for making a list. But there is for a dict: dict(a=1, b=2).
  • Through the act baz = foo + bar, where all of these are lists, will create an entirely new list for baz. If foo were [1,2,3] and you modify baz[0] = 'haha', foo will remain [1,2,3].
  • license() (with an S) is a built-in function. It shows python's story and history in addition to the actual licence. Making a function called license() is usually harmless, except if you use pylint: Redefining built-in 'license'
  • ngxtop is a pip package.
  • Comparing tuples with tuples, like (1, 0) < (3, 0) works how you think it would, but comparing tuples with lists that look about the same will not: (1, 0) < [3, 0] is false because the two types cannot be compared together.
  • On pathlib: you can os.path.join a PosixPath, you can Path('/') / 'home' / 'bob', but you can't Path('/') + 'home/bob', because that'd be "unintuitive".
  • Re machine learning: you should probably just go with tensorflow, if it installs.
  • The exception message for doing max(0, None) is different for python 3.5 (TypeError: unorderable types: NoneType() > int()) and 3.6 (TypeError: '>' not supported between instances of 'NoneType' and 'int').
  • Saying raise, without an exception to reraise in the context, will get you a RuntimeError.
  • A python3 class method annotation that needs to specify itself (e.g. a Time class whose method returns a Time) needs to be annotated with a string (e.g. 'Time'). This is because of the evaluation order... Time is not defined until the class is entirely parsed (or something). This is resolved in Python 3.7 (with a future import) and 4.0 (just works).
  • Function annotations (PEP-3107) is Python 3.0+, and does not specify what the annotations needs to do. Type hints (PEP-483, PEP-484) define how these annotations can be used for type checking. Variable annotations (PEP-526, e.g. foo: int = 1) is Python 3.6+.
  • While Dict is preferred over dict when writing type hints, typing.Boolean is not a thing, as are other "primitives" such as int.
  • typing.Tuple[float, float] means a tuple exactly 2 elements long, both of which being floats.
  • .pyi files are syntactically valid python files that are type stubs. By having a different extension, you cannot run pyi files directly (or import them?), and you can put the type stubs right beside your actuaal python file.
  • __slots__ might lower memory usage by 40% to 50%.
  • GVR had already mentioned that PEPs are not laws. PEPs are not intended to be laws. PEPs are "merely intended to guide humans, not to require them to follow it every time."
  • () does not equal (,) because the latter is a syntax error.
  • Raymond's twitter pro tip: Generally, lists are for looping; tuples for structs. Lists are homogeneous; tuples heterogeneous. Lists for variable length.
  • If you want your coworker to kill you, use the "Additional Unpacking Generalizations" (PEP 448) to write your tuple: *(x for x in range(10)),. In the same PEP: you can now unpack multiple things, multiple times, in the same function call. You can also first unpack some *args, and then add more after it to overwrite the stuff in args. Guido accepted this PEP.
  • A / inside documentation like sin(x, /) means "all arguments are positional-only", and to be fair, not that many people like it, or know what it is.
  • Child test classes that are tagged with @attr(...) also inherit that tag.
  • BaseException still exists in python 3. All things raised must be a subclass of BaseException.
  • pydocstyle contains mutually exclusive rules, D212 ("Multi-line docstring summary should start at the first line") and D213 ("Multi-line docstring summary should start at the second line"). You don't enable both at the same time
  • Tox is a meta test runner that manipulates the virtualenv. If you have a project that never changes virtualenv (read: supports only one python version), Tox is not the tool of choice.
  • In a list comprehension (formally PEP 202) in the form [... for x... for y...], the last index varies fastest, just like nested for loops.
  • If you need a reason not to use list comprehensions for looping, here it is, from Claudiu Popa, a member of the Python Code Quality Authority: "(...) you are creating a transient list that just gets thrown away after you're done with the iteration. It's more efficient to just use the for loop here, and it goes without saying that it helps with the readability of the code as well."
  • "Returns anything with superclass T" can supposedly be written as -> Type[T].
  • Using super(self.__class__, self) in subclass of the class that contains that line will not call the correct superclass method. To prevent that happening in your project, use flake8-super-call.
  • NumPy has its own PEP-like things, called NEPs ("NumPy Enhancement Proposals").
  • Disable a named logger: logging.getLogger('some name').propagate = False
  • If a function yields, the function returns a generator, and any function that returns the return of that function also returns the same generator.
  • Optional is NOT used when the argument is optional. Optional is used when None is an allowed value, whether or not the None may be omitted. It is a shorthand (saves 3 characters) compared to Union[..., None], and is supposedly well-known within the functional programming community.
  • A naive datetime object does not care about its time zone. An "aware" datetime object, however, does.
  • The 1.0 release of html5lib (you know, the first one after 0.9999999...) was a botched release.
  • Raymond, your role model, got burned at least once by a Dropbox employee.
  • Alembic is called Alembic (a distillation apparatus) because it works with SQLAlchemy.
  • Imports are done at most once per module. If you put a print statement inside a module, it is going to print just once, no matter how you import or from... import it again.
  • typing.NoReturn (a function that never returns, i.e. always raises) was new in python 3.5.4. Ubuntu ships python 3.5.2 though, because you're a joke. As an aside, NoReturn is not used when a function returns None.
  • According to some kind of type theory, it is preferred to annotate arguments with a abstract type, e.g. Sequence, Iterable, but annotate return values with a concrete type, e.g. List.
  • Each item in a mock function's call_args_list is a list of calls. Each call can be unpacked with args, kwargs = call. Then, as expected, args is a tuple and kwargs is a dict.
  • glob.glob() is not sorted. You have to sort it yourself.
  • To specify a version of python that pyenv will use for a project, put 2.5.0 inside a .python-version file at the project root. Then, python will map to whichever one pyenv thinks you want.
  • raise AnError() from None disables the "During handling of the above exception, another exception occurred" traceback.
  • This here tells you to: name something audio.Controller rather than audio.AudioController. It also tells you to import a.module rather than from a.module import something to prevent circular imports (no valid citation).
  • NotImplemented (not NotImplementedError) is returned exclusively by magic methods like __eq__(), __lt__(), __add__(), and __rsub__() to indicate that the operation is not implemented for the other type.
  • dict is a "subclass" of MutableMapping.
  • Runtime complexity for dicts/lists/deque are published. Notably, lists are surprisingly faster than dicts in getting an item by index/key (O(1) vs O(n)) in the worst case.
  • TestCase.addCleanup (noting the up is lower case, unlike that in setUp, because peps sucked 20 years ago amirite) is an instance-only method. Class-level exceptions cannot be cleaned up like this.
  • A method in a class can be called by a line inside the class without receiving self. See example. It's not going to pass PEP8, but it sure runs.
  • There is an assertIs in addition to assertEqual, but using is for numbers can potentially be incorrect when the number is outside [-5, 256]... among other strange situations where the compiler could not optimise the code ahead of time.
  • Like they said, breakpoint() is purely a convenience function.
  • PEP 420: It is no longer necessarily the case that a folder needs an __init__.py (making it a package) for files to be imported, but the rules are still confusing enough that you will want to continue having these files.
  • According to this guy, exception classes should not end with Exception because we don't write normal classes ending with Class or variables ending with _variable either. As for what exceptions are not errors, examples include SystemExit, KeyboardInterrupt, and exceptions that are called Warnings instead of Errors.
  • You have never used F strings because they are python 3.6 and up, but you're stuck on 3.5.
  • The self-debugging = in f'{strings=}' is only available from 3.8 onwards.
  • If a class declares __slots__, all of its subclasses need to declare __slots__ individually, but only attributes introduced by that particular subclass.
  • Only python3 classes with __slots__ defined will raise AttributeError when something not inside __slots__ is assigned to it. It does not do that in python2. See also: source
  • set1.isdisjoint(set2) is a very verbose way to check if the two sets have no common items, aka not (set1 & set2). The only difference is short-circuiting. And yes, a set is disjoint with an empty set.
  • In python 2, range() a function. In python3, it is a class. Its instance type is range.
  • An iterable is an object that can return its members one at a time. A "sequence" is an iterable that supports indexing. If you need to remember one thing, remember: the list is the built-in sequence. dicts are iterables but not sequences.
  • A generator that outputs nothing can be truthy. There is no good way to tell if a generator is empty.
  • random.choice cannot choose from an empty list.
  • Docstrings cannot be assigned literally. If you have a foo = """string""", and a class Bar:\nfoo, the class does not have a docstring. You can assign it to __doc__ though.
  • Arrow is not an instance of datetime. (relearnt in 2019)
  • pydocstyle has a rule, D401, that says examples from PEP 257 are invalid. All docstrings need to start with a verb in imperative mood, even for functions that return a boolean.
  • To run a script in a virtualenv, you just need to run it with that python (usually ~/virtualenvs/blah/bin/python). You can even put it in the script's shebang if it doesn't need to be portable.
  • Adding Counter() to another Counter() removes all zeros and negative counts.
  • json raises ValueError but simplejson raises JSONDecodeError, which is a subclass of ValueError. To be compatible with both (if that's your goal) you can only catch ValueError.
  • To make an ordered counter (a blend of Counter() and OrderedDict()), you really make class OrderedCounter(Counter, OrderedDict).
  • The G in Gunicorn stands for Green. It uses a pre-fork worker model. "pre-fork" means the worker is forked before a request comes in, and "worker" means the master process spins up workers, but doesn't know what the workers are doing.
  • max([]) would complain about being an empty sequence, but max([], default=5) will not.
  • In 2018, a PEP that allows an expression to also assign shit (i.e. y0 = (y1 := f(x))) was accepted. GVR rage quit. He left because people hated him for the decision he makes in his language. He left because he's tired [of having to fight to have his project the way to wants it].
  • The contents of a lambda is never called on initialisation, even if it looks like it will, like a = lambda: foo(). In this case, foo is not called until the lambda is.
  • Yes, you can redefine the print() function in python3.
  • "abcd".split() will only split it to ["abcd"], which is useless. "abcd".split('') will complain about "empty separator" instead, which is also useless. To get ['a', 'b', 'c', 'd'], do list("abcd").
  • IronPython (python on Mono) doesn't have an global interpreter lock (GIL).
  • pip install --user is usable only if you include ~/.local/bin in your path.
  • Python's float is actually usually C's double.
  • Perhaps the main flaw of Python's async implementation is the fact that you can accidentally call synchronous functions from asynchronous contexts - and they'll happily work fine and block the entire event loop until they're finished.
  • Variable scoping is full of shit. Nested functions can access variables outside it, but not if it is redefined anywhere in the function, including behind the line of access.
  • XML parsing can lead to files automatically fetched from the internet. etree, DOM, and xmlrpc are all wide open to these types of attacks. The official response is yes that's right.
  • Celery's .delay() is just .apply_async() with fewer options. Always prefer .apply_async.
  • If you have a celery task that depends on input from another task, chain them up. That way you wait for one task instead of two.
  • If you define a celery config's task_queues, you also need to define its task_routes (which tasks go to which queue). Use '*' to say all tasks go to one queue.
  • Unless you have an old project that goes by some convention, gevent is typically better than eventlet for reliability and ease of use.
  • If you use Django just for the ORM, then Peewee might be a better choice. It does have a migration extension, but you will slowly realise you will need to write your own raw DDL anyway.
  • Notice ayncio's name: it's for waiting for IO. It is not for you to write parallel code. It is not multiprocessing. It is not multithreading. It is how you write coroutines (async def). It is a way you (a)wait on stuff. Use asyncio when you can. Use threading if you must.
  • __len__ must return an int, even if you override it to return 1.5 or something. It must also return >= 0. But you can subclass an int, override its (__lt__, __eq__, etc), and return it instead. Then you return a sequence that can do whatever you want.
  • int() takes a base, i.e. int('0b10000', 2).
  • You cannot await anything inside a non-async function.
  • "A lot of things are implicit in python. Like variable declarations. Referring to PEP20 isn't an argument, and blindly making everything explicit would be stupid." - Rawing7
  • In SQLAlchemy, to define a column with a python-side "default", use the keyword default. To define a column that the database server knows is the default, use database_default.
  • It looks like you shouldn't do str(some_bytes) and str(some_bytearray). python3 -b tells you that's not a good thing.
  • Use pipdeptree to a. find out your dependencies as a tree, and find out why you have a package installed (as which packages' dependency).
  • The trailing comma in def foo(a,b,) is valid in python3.5, but in def foo(*,a,b,), it is not... at least not until 3.6.
  • The difference between str(a) and a.__str__() is the former calls type(a).__str__(a)... in case you deliberately monkey patch a's __str__.
  • py.test is the old pytest. You should not use it anywhere.
  • If your function says it takes in an Enum, then (according to mypy) no matter what the value is, you need to supply it from an Enum.
  • Strings' .zfill(pad), which pads your strings with zeros on the left until you get a length of (pad), is basically a coding contest method for when you need to generate a fixed-length binary string from bin().
  • You can inline try and except, i.e. try: print(1); print(1/0), but there is no C-style syntax to turn that into a multi-line statemnet, e.g. try: (print(1); \n print(1/0)) (considered a semicolon-separated tuple), try: {print(1); \n print(1/0)} (considered a semicolon-separated set), try: (print(1), \n print(1/0)) (it's a valid tuple, but you can't ever have a statement in it).
  • Custom class attributes prefixed with __ are private. It is not possible to read it. However, you can still assign something to it from the outside, and any __attributes that was not declared in the class are actually public. The instance cannot read the value you assigned though (because it has its own hashed key for that attribute). What does it mean for you? Nothing. Use it how you like.
  • set_a or set_b gives you the first set that is not empty. Use set_a | set_b (OR) or set_a ^ set_b (XOR).
  • Gareth Dwyer, author of the book Flask by Example, said that Flask might be better than Django. In that post, he wrote two hello-world examples.
  • Because '%s' % 1 + 2 raises TypeError instead of giving you 3, you can see % has higher precedence than +.
  • Stackoverflow says PEP 263 # coding=utf-8 lines are not necessary in python3 if all the files in the same project are in UTF-8, and your editor knows how to deal with it.
  • mypy does not care about whether your List annotation includes its subtypes. If subtypes are omitted, it assumes you return a list.
  • For ConfigParser, interpolation cannot be False; it must be None.
  • not 3 < 2 (it's True) demonstrates that < has higher precedence than not.
  • ** is the only right-to-left operator in python. a ** b ** c is evaluated as a ** (b ** c). The two are not the same: 3 ** (1 ** 2) is 3, but (3 ** 1) ** 2 is 9.
  • callable() is a built-in! You don't need to reinvent it with hasattr(blah, '__call__').
  • pytz offsets are not a fixed number of minutes. Telling it to make you a timezone called 'America/Chicago' will yield a practically meaningless value, unless when used in conjunction with a date and time.
  • Guido van Rossum's van is capitalised only if the last name Van Rossum is mentioned on its own.
  • pip vs python -m pip basically all boil down to "it lets you specify which python to install for". Using python -m pip in a virtualenv is a best practice that changes nothing.
  • Only alphanumeric strings are interned (have the same internal ID when multiple objects exist). wtf is interned, but wtf! is not.
  • dict keys are hashed. Assigning a_dict[5] and a_dict[5.0] mean the same thing because hash(5) == hash(5.0).
  • The x in for x in y can be any assignment target, so for i, some_dict[i] in enumerate(string) will assign each character to the dict by index.
  • Python3 class methods are automatically static if you don't have a self. The @staticmethod decorator helps the class to call Foo.bar(), and the ability to call these methods as a_foo.bar().
  • Did you know (after like 10 years programming in python) that you can't change a string by index?
  • Itertools is written in C. Many standard libraries are.
  • To settle whether python is more interpreted or compiled (no one denies bytecode exists), man python says it is python - an interpreted, interactive, object-oriented programming language.
  • You can specify types in a @dataclass all you want; they will not raise a TypeError if you give fields a value of the wrong type.
  • That walrus thing (:=), the assignment expression, cannot be used in an assignment statement. i.e. (a := 5) is valid, but a := 5 is not.
  • Given how high-priority the walrus operator is, (a := 6, 9) is equivalent to ((a := 6), 9), and (a, b := 16, 19) is equivalent to (a, (b := 16), 19).
  • a = not True is fine (makes a false), but a == not True is suddenly a SyntaxError. The fact that == takes higher precedence screws parsing over, which reads (a == not) True.
  • "In a generator expression, the in clause is evaluated at declaration time, but the conditional clause is evaluated at runtime." This means if you do (x for x in array if array), the two arrays can be completely different objects if you do a array = after that line.
  • String concatenation can be done in a single line. print('hello' 'world') prints helloworld.
  • In the strictest sense, python came from the Netherlands, even though the name is from an English show and GVR worked for Dropbox.
  • The Type[Foo] syntax is really implemented with __getitem__. See GenericMeta.__getitem__.
  • A "strict module", as defined by instagram engineering, just means "importing this module has no side effects, even on first load". Subsequent import statements are already skipped, even for "non-strict" modules.
  • Variable names cannot start with $.
  • Keyword argument names must be strings. bytestring will work in python2, but bytes will not work in python3.
  • The difference between random.randint(a, b) and random.uniform(a, b) is that the latter does not return int (it returns a float instead).
  • You can trigger func() got multiple values for argument 'arg' by first giving your positional arguments a value, and then repeating the same arguments as keywords. For example: (lambda x, **kwargs: None)(5, x=5).
  • assertNumQueries(n) expects the number of queries you make inside that block to be exactly that, not fewer.
  • cumtime is cumulative time.
  • The ReStructuredText docstring format appears to require colons on both sides of the keyword, i.e. :param foo: bar, :returns: foo, and :raises: Foo are "more correct" than :param foo bar, :returns foo, and :raises Foo. Also, if you were to provide type information in the docstring instead of PEP 484, then the type comes first, i.e. :param str sender:, not :param sender str:.
  • Datetimes cannot be falsy.
  • Metaclasses are classes whose instance methods accept cls instead of self. If you have a class Foo(metaclass=Bar), then Bar's __repr__(cls) will run when you try to print Foo, even if you never officially made a function call.
  • python -O does only two things: remove assertions, and remove if __debug__ blocks (which is True by default). python -OO does only one extra thing: remove docstrings.
  • Uses of operators in a multi-line situation are mandated by pep8 to be in front of the line because, in their example, it looks nicer. Find issues with \(.+\s[+\-*/]\s?$.
  • To focus on another vertical tab group in pycharm, it's called "Goto Next Splitter".
  • To annotate the fact that you return a defaultdict (a subclass of dict) rather than a dict, typing.DefaultDict is preferred over typing.Dict even though the two may technically be true.
  • Prevent your class from being subclassed by assigning a metaclass that checks if one of the bases is itself. This works because the exact class that has this metaclass attached, does not have bases.
  • Mock(spec=...) allows that mock to pass isinstance checks as that type or instance's type.
  • MagicMock is just Mock with defaults.
  • Abstract base classes are useful when you never want the class instantiated.
  • You should always --no-site-packages on a virtualenv that supports it. It isolates whatever else you have installed globally from your virtual env, which is mostly the point of a virtualenv.
  • Slice assignment: a_list[1:3] = [4, 5] replaces a_list[1] with 4, and a_list[2] with 5.
  • self is not a keyword; it "has absolutely no special meaning to Python". You can easily make a class self, inside which you have self = None, and get self.self == None.
  • In python3, dividing an int by an int returns a float. This is the only change in behaviour. Dividing a float or Decimal by an int still returns that type.
  • attrgetter resolves chains. attrgetter('foo.bar') returns a function that returns your_object.foo.bar. Also, attrgetter accepts multiple positional arguments, which will give you a tuple of keys instead (e.g. attrgetter('foo', 'bar', 'baz')).
  • Yes, attrgetter still raises AttributeError if the attributte does not exist. There is no default option.
  • sys.executable gives you the full path of the python that is running your script.
  • A function that runs sys.exit() inside a finally will still run the finally block before the process exits.
  • Relative import (from ..foo import bar) can have any number of dots. from ...foo import bar would import from the grandparent directory. Four dots, three directories up.
  • Relative imports are still ok by python3. Implicit relative imports (e.g. import bar when bar.py is in the same dir) are no longer impossible.
  • f STRINGS ARE CODE. It is impossible to determine the type of an f-string until it is fully interpolated into an actual str.
  • The third-party dateutil has a relativedelta that is similar to timedelta, but with more parameters, like leapdays.
  • A subTest decorator can be used whether or not you are inside a loop. The first parameter is a message. The message can be anything that lets you tell the difference between the failure and other tests, not just a loop counter.
  • A deadbeat way to force your library to work only above 3.6 is to have a random line with 1_2 in it. PEP 515 makes 3.6 understand that as 12, and for anything below 3.6, a syntax error.
  • Returning True in a __exit__ tells python you have handled the error.
  • return _decorator(func) if func else _decorator ensures a def decorator(func=None) will always return a decorator, whether it is used as @decorator or @decorator().
  • __file__ is the symlink's name if you symlinked to a script.
  • If adding more than four floating points together, doing (a + b) + (c + d) has less rounding error than just a + b + c + d... somehow. I haven't found a single example that showed a significant difference.
  • [:-1] means "everything except the last item".
  • The rest framework has generic API views... which are just the APIView plus mixins for HTTP verbs. There are APIViews (not generic), ViewSets (not generic), GenericViewSets (generic), ReadOnlyModelViewSets (generic)... just pick the one that has the combination of attributes and methods that you need. The docs say you should prefer the generic classes over the regular ones.
  • Running gunicorn -w 4 myapp:app runs a web server with 4 workers using the file myapp.py and the function def app inside it.
  • Pipenv devs are very noob-friendly: they call noobs "newcomers", and there is a section in the docs where it helps them figure out why typing python into the python REPL gives them a NameError.
  • If you deploy on Windows, uWSGI and Gunicorn don't work there, so use mod_wsgi instead.
  • Context managers are objects, so you can keep a reference to it before you use it in a with statement: an_instance = Foo(); with an_instance:
  • Well don't use numpy.matrix because it does nothing more than what numpy.array does, and must be two-dimensional.
  • Two multiply two numpy matrices, do array(m x n) * array(m x n) = array(m x n). By "multiply", it means each new cell contains the dot product of the old values at the same location.
  • To get the dot product of two matrices instead, use array(m x n).dot( array(n x m) ) = array(m x m).
  • numpy.reshape turns your matrix into a giant one-dimensional list, and then fills in a new matrix to your specifications. For example, if you reshape a [1, 2, 3, 4, 5, 6] with .reshape(2, 3), you get [[1, 2, 3], [4, 5, 6]].
  • Whether or not you raise an_exception from another_exception, python is still going to show another_exception, just not as a "direct cause".
  • There are no magic methods for is, and and or. No particular reason. Raymond also said it would be catastrophic but not as a reason why it's not possible.
  • 1e25 is a float and comes to 10000000000000000905969664. You literally can't trust it. Use 1 * 10**25 instead. If you are hard pressed to use e, the highest exponent it can go without fucking up (for 1.0) is 22.
  • Guido's stance on Black is: "Black is overrated unless your team argues over style a lot." (2020)
  • Printing out a KeyError does not print newlines. It works for other exceptions.
  • Having def foo(self) follows the "explicit is better than implicit" idiom. thing.foo() without the self, does not.
  • The borg pattern uses self.__dict__ in __init__ to simulate a singleton with multiple copies of the "same" object. It is unclear why anyone would do that over metaclass-produced singletons.
  • Python has a GIL because it chose to be compatible with C libraries, but C libraries are not threadsafe. It was also fine at the time because computers were single-core back then.
  • If you implement __getattr__ that never raises an AttributeError, hasattr() is going to tell you that every attribute exists.
  • There are quite a few things that python decides to leave implicit. Examples: variable types (by default), and the very fact that the language descended from a more explicit one, with the goal being to replace its complicated parts.
  • You can set() a string and it will become a set of all the characters in it.
  • Formula for sorting items using custom behaviour: sorted(..., key=lambda x: ...)
  • 1 < 3 in [2, 3] evaluates to true. Notice that 1 < True is false and True in [2, 3] is false as well. Due to elemental fuckups (non-transitive operators), 1 < 3 in [2, 3] expands to 1 < 3 and 3 in [2, 3], which is true. The behaviour stems from a < b < c expanding to a < b and b < c.
  • json.dumps(float('inf')) gets you the string 'Infinity'. You need json.dumps(float('inf'), allow_nan=False) to be compliant with the JSON standard.
  • vars() is the same as locals() if no argument is given, and the same as foo.__dict__ if called as vars(foo).
  • The heapq package has only a min heap but no max heap. To get a max heap, store the negated version of each number. There is also heapq._heapify_max(some_list) that you may try.
  • There is an arrays standard library. It is meant to save memory when storing numbers and bytes.
  • People dislike python for many things, like (other than indentation, which they all talk about): "implicit" "string" "concatentation" causing bugs when you miss a comma, bar = 1 creating a new variable even when the name is a typo, and too, many, commas, creating a list of incorrect length, or worse... from something, to a tuple.
  • Timsort, somewhere between insertion sort and merge sort, was made by Tim Peters, the same man who wrote PEP 20.
  • You can return *iterable, *another_iterable because of the implicit tuple return. If you have a single iterable, normally it would have needed to be return (*iterable,).
  • @typing.no_type_check tells mypy to go away for a single function.
  • @dataclasses can declare fields like so: quantity: int = 0, where int is the type, and 0 is the default, in the generated __init__(self, quantity: int = 0). However, since these fields are declared as class attributes, you don't want to have a list there, e.g. things: List[Any] = [], because that would generate __init__(self, things: List[Any] = []), and you know how terrible that is. Instead, apparently you need to use field, so things: List[Any] = field(default_factory=list). A blunder of an API unless you are Dutch.