Some things I don't like about the Python programming language and libraries.
+=
semantics differing from assignmentThe +=
operator can be overridden. For the built-in
lists, it's overridden to actually mutate instead of reassigning:
>>> a = []
>>> b = a
>>> b += [0]
>>> print(a)
[0]
Compare it with the assignment operator:
>>> a = []
>>> b = a
>>> b = b + [0]
>>> print(a)
[]
readline
monkey patches raw_input
Importing the readline
module changes the behavior of
the raw_input
function.
>>> import readline
>>> foo = raw_input()
Now you can use readline features (history etc) from the prompt. This causes action at a distance among two seemingly completely unrelated modules and can cause issues that are very hard to debug.
email.mime.text.MIMEText
actually appends themIf you treat MIMEMessage
as a dictionary and assign
header values to its string indexes, the headers are actually appended
instead of replaced.
>>> from email.mime.text import MIMEText
>>> msg = MIMEText("")
>>> msg["To"] = "foo@example.com"
>>> msg["To"] = "bar@example.com"
>>> msg.as_string()
'Content-Type: text/plain; charset="us-ascii"\nMIME-Version: 1.0\nContent-Transfer-Encoding: 7bit\n
To: foo@example.com\nTo: bar@example.com\n\n'
This poses a serious privacy risk if the program assigns other customers' emails to the
To
field before picking the final one.
sounddevice
The library sounddevice
has a way to denote the number of channels either combined
for input and output, or for input and output separately. The way this is done is by
passing either a single value or a tuple to the relevant function or constructor.
stream = sounddevice.Stream(channels=2) # two channels for input and (or?) output
stream = sounddevice.Stream(channels=(1,2)) # one channel for input, two for output
Because the value passed is a tuple, and there's no universal convention whether input or output comes first, the API user doesn't know which tuple element is input and which is output. The documentation doesn't explicitly state it either, so it's a guessing game.
You can define default parameters for functions like this:
>>> def function(param="default"):
>>> print("Got param:", param)
>>> function()
Got param: default
>>> function("something else")
Got param: something else
The problem arises when you define a mutable default parameter:
>>> def function(param=[]):
>>> param.append("item")
>>> for item in param:
>>> print(item)
>>> function()
item
>>> function()
item
item
>>> function()
item
item
item
The default parameter is evaluated only once, during function definition,
and is shared among all calls to the function. The usual solution is to
instead use an immutable value (eg. None
) as the default parameter, and
replace it during function execution.
>>> def function(param=None):
>>> if param is None:
>>> param = []
>>> param.append("item")
>>> for item in param:
>>> print(item)
>>> function()
item
>>> function()
item
>>> function()
item