- 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 break
ed 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
dict
s have a setdefault
method: avoids KeyError
s. 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 dict
s, 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.
yield
s 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 break
s.
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 Decimal
s. 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 PendingDeprecationWarning
s, 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)
- There's no formal guarantee about the stability of sets (or dicts, for that matter.) However, in the CPython implementation, as long as nothing changes the set, the items will be produced in the same order.
- Assigning attributes to a function doesn't raise
AttributeError
s. PEP 232 tries to justify it--the gist being, "it doesn't hurt."
isinstance()
accepts a tuple worth of types.
- Installing
python-examples
apparently gives access to reindent.py
, which obviously reindents python scripts.
- Splicing a
range
(which is xrange
) in python3 gives you another range
. The equivalent xrange
cannot be spliced in python2.
- By overriding the behaviour of
__lt__
, __gt__
, __eq__
, etc., things that often do comparisons (and therefore return bools) now return SQL "Expression" objects, like so:
>>> 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
WeakReference
s 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 1
s.
- 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
Exception
s 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 list
s, 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 raise
d 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
yield
s, 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 call
s. 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 Warning
s instead of Error
s.
- 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. dict
s 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 array
s 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 APIView
s (not generic), ViewSet
s (not generic), GenericViewSet
s (generic), ReadOnlyModelViewSet
s (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.
@dataclass
es 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.