Argh! Who thought Black should be automatically applied to lines in the IPython CLI?

The makes it less useful for education purposes, less useful for interactive math, and annoying when it rewrites your input across multiple lines.
In a #Python course, if you want to demonstrate that print('hello') and print("hello") are the same, then too bad. The CLI rewrites both to use double quotes and the students can't see what you were demonstrating.
When doing math, you improve readability by grouping your terms as shown in PEP 8:

3*x**2 - 5*x + 10

However, the new #Ipython CLI immediately expands it to:

3 * x ** 2 - 5 * x + 10
Black's quotation rewrites are especially distracting in a REPL where it clearly conflicts the language's internal preferences:

In [11]: {"x": 10}
Out[11]: {'x': 10}
For teaching purposes, it is especially annoying to have in-line comments smushed to two spaces after the code ends. And more so, when it splits your input lines.

if n == 0: return 0 # 1st known case
if n == 1: return 1 # 2nd known case
return n * fact(n-1) # Recurse
It's no longer possible to show students how to use the semicolon to separate statements:

>>> time.sleep(5); print("Done")

In #IPython, this gets rewritten to:

In [15]: sleep(5)
...: print("Done")
Done
Yes, this can be turned off, but you have to get a whole classroom of mixed Windows, Mac, and Linux users to monkey through the steps to get back to a normal environment where you can see what you typed into the computer rather than what it wanted you to type.
Even if you usually like how Black formats your scripts and modules, why would you ever do this line by line in a CLI?
It wasn't long ago that IDLE became unusable for teaching. And now IPython decides to rewrite my inputs so that students never see what I actually typed.

Argh!!!
Note that #SymPy does the right thing here:

>>> from sympy import var
>>> var('x')
x
>>> ((3*x + 5) * (2*x - 4)).expand()
6*x**2 - 2*x - 20
I'm not sure what to say to defuse this thread.

Black is good product. IPython is a good tool. The people involved are good developers.

Ideally, let's focus on the problem rather the people. The main thread identifies five specific usability problems. That's what we care about.
The original PR had 32 downvotes but was pushed despite opposition from those aware of the impending change. Unfortunately, they didn't give examples so it may have been easy to dismiss their concerns.

github.com/ipython/ipytho…

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Raymond Hettinger

Raymond Hettinger Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @raymondh

11 Nov 21
#Python's structural pattern matching is new, so the best practices aren't yet known.

Just added to my personal list: Add a comment or assertion noting when case ordering is important.

Otherwise, a future maintainer will be bitten by the illusion of case independence.

1 of 4
match x:
case bool():
...
case int():
assert not isinstance(x, bool)
...
case Counter():
...
case dict():
assert not isinstance(x, Counter)
case _:
raise TypeError

2 of 4
match sales_report:
case {'dept': dept, 'holiday': event}:
# Holiday case must precede other cases
...
case {'dept': 'shoes'}:
...
case {'dept': 'hats'}:
...

3 of 4
Read 4 tweets
9 Nov 21
#Python tip: Structural pattern matching works with abstract base classes such as: Contains, Hashable, Iterable, Iterator, Reversible, Generator, Sized, Callable, and Collection.

match obj:
case Hashable:
...
Matching a collection ABC is preferable to looking for the required methods directly.

The complication is that those methods may be present but could be set to None.

The ABCs listed above handle the None checks for you.
For more complex ABCs, such as Sequence and Mapping, the presence of the required methods is insufficient.

The object's class needs to either inherit from the ABC or be registered with the ABC.
Read 5 tweets
6 Apr 21
#Python factlet: The dict.popitem() method is guaranteed to remove key/value pairs in LIFO order.

>>> d = dict(red=1, green=2, blue=3)
>>> d.popitem()
('blue', 3)
>>> d.popitem()
('green', 2)
>>> d.popitem()
('red', 1)

1/
In contrast, OrderedDict.popitem() supports both FIFO and LIFO extraction of key/value pairs.

>>> from collections import OrderedDict
>>> d = OrderedDict(red=1, green=2, blue=3)

>>> d.popitem(last=False) # FIFO
('red', 1)

>>> d.popitem() # LIFO
('blue', 3)

2/
OrderedDict can efficiently move entries to either end without a hash table update.

>>> d = OrderedDict(red=1, green=2, blue=3)

>>> d.move_to_end('green')
>>> list(d)
['red', 'blue', 'green']

>>> d.move_to_end('green', last=False)
>>> list(d)
['green', 'red', 'blue']

3/
Read 4 tweets
3 Jan 21
#Python factlet: The len() function insists that the corresponding __len__() method return a value x such that:

0 ≤ x.__index__() ≤ sys.maxsize

* 3.0 and '3' don't have an __index__ method.
* -1 is too small.
* sys.maxsize+1 is too big.

1/
You could call __len__() successfully, but the len() function fails:

class A:
def __len__(self):
return -1

>>> a = A()

>>> a.__len__()
-1

>>> len(a)
...
ValueError: __len__() should return >= 0

2/
Classes written in C typically implement __len__() with the mp_length or sq_length slot. That constrains them to sys.maxsize limits:

>>> r = range(10**100)
>>> r.__len__()
Traceback (most recent call last):
...
OverflowError: Python int too large to convert to C ssize_t

3/
Read 4 tweets
2 Jan 21
@yera_ee Each way has its advantages.

With dataclasses, you get nice attribute access, error checking, a name for the aggregate data, and a more restrictive equality test. All good things.

Dicts are at the core of the language and are interoperable with many other tools: json, **kw, …
@yera_ee Dicts have a rich assortment of methods and operators.
People learn to use dicts on their first day.
Many existing tools accept or return dicts.
pprint() knows how to handle dicts.
Dicts are super fast.
JSON.
Dicts underlie many other tools.
@yera_ee Embrace dataclasses but don't develop an aversion to dicts.

Python is a very dict centric language.

Mentally rejecting dicts would be like developing an allergy to the language itself. It leads to fighting the language rather than working in harmony with it.
Read 4 tweets
27 Dec 20
1/ #Python tip: Override the signature for *args with the __text_signature__ attribute:

def randrange(*args):
'Choose a random value from range(start[, stop[, step]]).'
return random.choice(range(*args))

randrange.__text_signature__ = '(start, stop, step, /)'
2/ The attribute is accessed by the inspect module:

>>> inspect.signature(randrange)
<Signature (start, stop, step, /)>
3/ Tooltips and help() will now be more informative:

>>> help(randrange)
randrange(start, stop, step, /)
Choose a random value from range(start[, stop[, step]]).
Read 4 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us on Twitter!

:(