Fluent Python: Clear, Concise, and Effective Programming
Rate it:
Open Preview
37%
Flag icon
Attributes with a single _ prefix are called “protected” in some corners of the Python documentation.
37%
Flag icon
if you define a class attribute named __slots__ holding a sequence of attribute names, Python uses an alternative storage model for the instance attributes: the attributes named in __slots__ are stored in a hidden array or references that use less memory than a dict.
38%
Flag icon
If you declare __slots__ = () (an empty tuple), then the instances of the subclass will have no __dict__ and will only accept the attributes named in the __slots__ of the base class.
38%
Flag icon
Careless optimization is worse than premature optimization: you add complexity but may not get any benefit.
38%
Flag icon
An object should be as simple as the requirements dictate—and not a parade of language features. If the code is for an application, then it should focus on what is needed to support the end users, not more. If the code is for a library for other programmers to use, then it’s reasonable to implement special methods supporting behaviors that Pythonistas expect. For example, __eq__ may not be necessary to support a business requirement, but it makes the class easier to test.
38%
Flag icon
String/bytes representation methods: __repr__, __str__, __format__, and __bytes__
38%
Flag icon
Methods for reducing an object to a number: __abs__, __bool__, and __hash__
38%
Flag icon
The __eq__ operator, to support testing and hashing (al...
This highlight has been truncated due to consecutive passage length restrictions.
39%
Flag icon
N-dimensional vectors (with large values of N) are widely used in information retrieval, where documents and text queries are represented as vectors, with one dimension per word. This is called the Vector space model. In this model, a key relevance metric is the cosine similarity (i.e., the cosine of the angle between the vector representing the query and the vector representing the document). As the angle decreases, the cosine approaches the maximum value of 1, and so does the relevance of the document to the query.
39%
Flag icon
In the context of object-oriented programming, a protocol is an informal interface, defined only in documentation and not in code. For example, the sequence protocol in Python entails just the __len__ and __getitem__ methods.
39%
Flag icon
In other words, indices exposes the tricky logic that’s implemented in the built-in sequences to gracefully handle missing or negative indices and slices that are longer than the original sequence. This method produces “normalized” tuples of nonnegative start, stop, and stride integers tailored to a sequence of the given length.
40%
Flag icon
The key idea is to reduce a series of values to a single value. The first argument to reduce() is a two-argument function, and the second argument is an iterable. Let’s say we have a two-argument function fn and a list lst. When you call reduce(fn, lst), fn will be applied to the first pair of elements—fn(lst[0], lst[1])—producing a first result, r1. Then fn is applied to r1 and the next element—fn(r1, lst[2])—producing a second result, r2. Now fn(r2, lst[3]) is called to produce r3 … and so on until the last element, when a single result, rN, is returned.
40%
Flag icon
When using reduce, it’s good practice to provide the third argument, reduce(function, iterable, initializer), to prevent this exception: TypeError: reduce() of empty sequence with no initial value (excellent message: explains the problem and how to fix it). The initializer is the value returned if the sequence is empty and is used as the first argument in the reducing loop, so it should be the identity value of the operation. As examples, for +, |, ^ the initializer should be 0, but for *, & it should be 1.
40%
Flag icon
The mapping step produces one hash for each component, and the reduce step aggregates all hashes with the xor operator.
40%
Flag icon
The solution with map would be less efficient in Python 2, where the map function builds a new list with the results. But in Python 3, map is lazy: it creates a generator that yields the results on demand, thus saving memory—just
41%
Flag icon
The zip function is named after the zipper fastener because the physical device works by interlocking pairs of teeth taken from both zipper sides, a good visual analogy for what zip(left, right) does.
41%
Flag icon
One of them is the zip built-in, which makes it easy to iterate in parallel over two or more iterables by returning tuples that you can unpack into variables, one for each item in the parallel inputs.
42%
Flag icon
That’s why I believe “informal interface” is a reasonable short explanation for “protocol”
42%
Flag icon
When implementing a class that emulates any built-in type, it is important that the emulation only be implemented to the degree that it makes sense for the object being modeled. For example, some sequences may work well with retrieval of individual elements, but extracting a slice may not make sense.
42%
Flag icon
One thing I know: “idiomatic” does not mean using the most obscure language features.
42%
Flag icon
If you want the sum of a list of items, you should write it in a way that looks like “the sum of a list of items,” not in a way that looks like “loop over these items, maintain another variable t, perform a sequence of additions.” Why do we have high-level languages if not to express our intentions at a higher level and let the language worry about what low-level operations are needed to implement it?
42%
Flag icon
Program to an interface, not an implementation.
42%
Flag icon
The best approach to understanding a type in Python is knowing the methods it provides—its interface—as
42%
Flag icon
Duck typing Python’s default approach to typing from the beginning.
42%
Flag icon
Goose typing The approach supported by abstract base classes (ABCs) since Python 2.6, which relies on runtime checks of objects against ABCs.
42%
Flag icon
Static typing The traditional approach of statically-typed languages like C and Java; supported since Python 3.5 by the typing module, and enforced by external type checkers compliant with PEP 484—Type Hints.
42%
Flag icon
Static duck typing An approach made popular by the Go language; supported by subclasses of typing.Protocol—new in Python 3.8—also enforced by external type checkers.
42%
Flag icon
object protocol specifies methods which an object must provide to fulfill a role.
42%
Flag icon
Dynamic protocol The informal protocols Python always had. Dynamic protocols are implicit, defined by convention, and described in the documentation. Python’s most important dynamic protocols are supported by the interpreter itself, and are documented in the “Data Model” chapter of The Python Language Reference.
42%
Flag icon
An object may implement only part of a dynamic protocol and still be useful; but to fulfill a static protocol, the object must provide every method declared in the protocol class, even if your program doesn’t need them all.
42%
Flag icon
Static protocols can be verified by static type checkers, but dynamic protocols can’t.
42%
Flag icon
The philosophy of the Python Data Model is to cooperate with essential dynamic protocols as much as possible.
42%
Flag icon
Most ABCs in the collections.abc module exist to formalize interfaces that are implemented by built-in objects and are implicitly supported by the interpreter—both of which predate the ABCs themselves. The ABCs are useful as starting points for new classes, and to support explicit type checking at runtime (a.k.a. goose typing) as well as type hints for static type checkers.
42%
Flag icon
In summary, given the importance of sequence-like data structures, Python manages to make iteration and the in operator work by invoking __getitem__ when __iter__ and __contains__ are unavailable.
43%
Flag icon
Monkey patching is dynamically changing a module, class, or function at runtime, to add features or fix bugs.
43%
Flag icon
When you follow established protocols, you improve your chances of leveraging existing standard library and third-party code, thanks to duck typing.
43%
Flag icon
Many bugs cannot be caught except at runtime—even in mainstream statically typed languages.3 In a dynamically typed language, “fail fast” is excellent advice for safer and easier-to-maintain programs. Failing fast means raising runtime errors as soon as possible, for example, rejecting invalid arguments right a the beginning of a function body.
43%
Flag icon
An abstract class represents an interface. Bjarne Stroustrup,
43%
Flag icon
Python doesn’t have an interface keyword. We use abstract base classes (ABCs) to define interfaces for explicit type checking at runtime—also supported by static type checkers.
43%
Flag icon
Abstract base classes complement duck typing by providing a way to define interfaces when other techniques like hasattr() would be clumsy or subtly wrong (for example, with magic methods). ABCs introduce virtual subclasses, which are classes that don’t inherit from a class but are still recognized by isinstance() and issubclass();
43%
Flag icon
What goose typing means is: isinstance(obj, cls) is now just fine…as long as cls is an abstract base class—in other words, cls’s metaclass is abc.ABCMeta.
43%
Flag icon
And, don’t define custom ABCs (or metaclasses) in production code. If you feel the urge to do so, I’d bet it’s likely to be a case of the “all problems look like a nail”–syndrome for somebody who just got a shiny new hammer—you (and future maintainers of your code) will be much happier sticking with straightforward and simple code,
43%
Flag icon
goose typing entails: Subclassing from ABCs to make it explict that you are implementing a previously defined interface. Runtime type checking using ABCs instead of concrete classes as the second argument for isinstance and issubclass.
43%
Flag icon
even with ABCs, you should beware that excessive use of isinstance checks may be a code smell—a symptom of bad OO design.
43%
Flag icon
It’s usually not OK to have a chain of if/elif/elif with isinstance checks performing different actions depending on the type of object: you should be using polymorphism for that—i.e., design your classes so that the interpreter dispatches calls to the proper methods, instead of you hardcoding the dispatch logic in if/elif/elif blocks.
43%
Flag icon
On the other hand, it’s OK to perform an isinstance check against an ABC if you must enforce an API contract: “Dude, you have to im...
This highlight has been truncated due to consecutive passage length restrictions.
43%
Flag icon
ABCs are meant to encapsulate very general concepts, abstractions, introduced by a framework—things like “a sequence” and “an exact number.” [Readers] most likely don’t need to write any new ABCs, just use existing ones correctly, to get 99.9% of the benefits without serious risk of misdesign.
43%
Flag icon
Python does not check for the implementation of the abstract methods at import time (when the frenchdeck2.py module is loaded and compiled), but only at runtime when we actually try to instantiate FrenchDeck2.
44%
Flag icon
Iterable, Container, Sized Every collection should either inherit from these ABCs or implement compatible protocols. Iterable supports iteration with __iter__, Container supports the in operator with __contains__, and Sized supports len() with __len__.
44%
Flag icon
Collection This ABC has no methods of its own, but was added in Python 3.6 to make it easier to subclass from Iterable, Container, and Sized.
1 8 12