Trey Hunner: Python built-ins worth learning

  • 时间: 2019-05-22 11:57:45

In every Intro to Python class I teach, there’s always at least one “how can we be expected to know all this” question.

It’s usually along the lines of either:

  1. Python has so many functions in it, what’s the best way to remember all these?
  2. What’s the best way to learn the functions we’ll need day-to-day like enumerateand range?
  3. How do you know about all the ways to solve problems in Python? Do you memorize them?

There are dozens of built-in functions and classes, hundreds of tools bundled in Python’s standard library, and thousands of third-party libraries on PyPI.There’s no way anyone could ever memorize all of these things.

I recommend triaging your knowledge:

  1. Things I should memorize such that I know them well
  2. Things I should know aboutso I can look them up more effectively later
  3. Things I shouldn’t bother with at all until/unless I need them one day

We’re going to look through the Built-in Functions pagein the Python documentation with this approach in mind.

This will be a very long article, so I’ve linked to 5 sub-sections and 20 specific built-in functions in the next section so you can jump ahead if you’re pressed for time or looking for one built-in in particular.

Which built-ins should you know about?

I estimate most Python developers will only ever need about 30 built-in functions, but which 30 depends on what you’re actually doing with Python.

We’re going to take a look at all 69 of Python’s built-in functions, in a birds eye view sort of way.

I’ll attempt to categorize these built-ins into five categories:

  1. : most newer Pythonistas get exposure to these built-ins pretty quickly out of necessity
  2. Overlooked by beginners : these functions are useful to know about, but they’re easy to overlook when you’re newer to Python
  3. : these built-ins are generally useful to know about, but you’ll find them when/if you need them
  4. Maybe learn it eventually : these can come in handy, but only in specific circumstances
  5. You likely don’t need these : you’re unlikely to need these unless you’re doing something fairly specialized

The built-in functions in categories 1 and 2 are the essential built-insthat nearly all Python programmers should eventually learn about.The built-ins in categories 3 and 4 are the specialized built-ins, which are often very useful but your need for them will vary based on your use for Python.And category 5 are arcane built-ins, which might be very handy when you need them but which many Python programmers are likely to never need.

Note for pedantic Pythonistas: I will be referring to all of these built-ins as functions, even though 27 of them aren’t actually functions(as discussed in my functions and callables article).

The commonly known built-in functions (which you likely already know about):

The built-in functions which are often overlooked by newer Python programmers:

There are also5 commonly overlooked built-inswhich I recommend knowing about solely because they make debugging easier: dir, var, breakpoint, type, help.

In addition to the 25 built-in functions above, we’ll also briefly see the other 44 built-ins in themaybe learn it eventuallyandyou likely don’t need thesesections.

10 Commonly known built-in functions

If you’ve been writing Python code, these built-ins are likely familiar already.


You already know the printfunction.Implementing hello worldrequires print.

You may not know about the variouskeyword arguments accepted by printthough:

>>> words = ["Welcome", "to", "Python"]>>> print(words)['Welcome', 'to', 'Python']>>> print(*words, end="!\n")Welcome to Python!>>> print(*words, sep="\n")WelcometoPython

You can look up printon your own.


In Python, we don’t write things like my_list.length()or my_string.length;instead we strangely (for new Pythonistas at least) say len(my_list)and len(my_string).

>>> words = ["Welcome", "to", "Python"]>>> len(words)3

Regardless of whether you like this operator-like lenfunction, you’re stuck with it so you’ll need to get used to it.


Unlike many other programming languages, you cannot concatenate strings and numbers in Python.

>>> version = 3>>> "Python " + versionTraceback (most recent call last):  File "<stdin>", line 1, in <module>TypeError: can only concatenate str (not "int") to str

Python refuses to coerce that 3integer to a string, so we need to manually do it ourselves, using the built-in strfunction (class technically, but as I said, I’ll be calling these all functions):

>>> version = 3>>> "Python " + str(version)'Python 3'


Do you have user input and need to convert it to a number?You need the intfunction!

The intfunction can convert strings to integers:

>>> program_name = "Python 3">>> version_number = program_name.split()[-1]>>> int(version_number)3

You can also use intto truncate a floating point number to an integer:

>>> from math import sqrt>>> sqrt(28)5.291502622129181>>> int(sqrt(28))5

Note that if you need to truncate while dividing, the //operator is likely more appropriate (though this works differently with negative numbers): int(3 / 2) == 3 // 2.


Is the string you’re converting to a number not actually an integer?Then you’ll want to use floatinstead of intfor this conversion.

>>> program_name = "Python 3">>> version_number = program_name.split()[-1]>>> float(version_number)3.0>>> pi_digits = '3.141592653589793238462643383279502884197169399375'>>> len(pi_digits)50>>> float(pi_digits)3.141592653589793

You can also use floatto convert integers to floating point numbers.

In Python 2, we used to use floatto convert integers to floating point numbers to force float division instead of integer division.“Integer division” isn’t a thing anymore in Python 3 (unless you’re specifically using the //operator), so we don’t need floatfor that purpose anymore.So if you ever see float(x) / yin your Python 3 code, you can change that to just x / y.


Want to make a list out of some other iterable?

The listfunction does that:

>>> numbers = [2, 1, 3, 5, 8]>>> squares = (n**2 for n in numbers)>>> squares<generator object <genexpr> at 0x7fd52dbd5930>>>> list_of_squares = list(squares)>>> list_of_squares[4, 1, 9, 25, 64]

If you know you’re working with a list, you could use the copymethod to make a new copy of a list:

>>> copy_of_squares = list_of_squares.copy()

But if you don’t know what the iterable you’re working with is, the listfunction is the more general way to loop over an iterable and copy it:

>>> copy_of_squares = list(list_of_squares)

You could also use a list comprehension for this, but I wouldn’t recommend it.

Note that when you want to make an empty list, using the list literal syntax(those []brackets) is recommended:

>>> my_list = list()  # Don't do this>>> my_list = []  # Do this instead

Using []is considered more idiomatic since those square brackets ( []) actually looklike a Python list.


The tuplefunction is pretty much just like the listfunction, except it makes tuples instead:

>>> numbers = [2, 1, 3, 4, 7]>>> tuple(numbers)(2, 1, 3, 4, 7)

If you need a tuple instead of a list, because you’re trying to make a hashablecollection for use in a dictionary key for example, you’ll want to reach for tupleover list.


The dictfunction makes a new dictionary.

Similar to like listand tuple, the dictfunction is equivalent to looping over an iterable of key-value pairs and making a dictionary from them.

Given a list of two-item tuples:

>>> color_counts = [('red', 2), ('green', 1), ('blue', 3), ('purple', 5)]


>>> colors = {}>>> for color, n in color_counts:...     colors[color] = n...>>> colors{'red': 2, 'green': 1, 'blue' 3, 'purple': 5}

Can instead be done with the dictfunction:

>>> colors = dict(color_counts)>>> colors{'red': 2, 'green': 1, 'blue' 3, 'purple': 5}

The dictfunction accepts two types of arguments:

  1. another dictionary( mappingis the generic term), in which case that dictionary will be copied
  2. a list of key-value tuples(more correctly, an iterable of two-item iterables), in which case a new dictionary will be constructed from these

So this works as well:

>>> colors{'red': 2, 'green': 1, 'blue' 3, 'purple': 5}>>> new_dictionary = dict(colors)>>> new_dictionary{'red': 2, 'green': 1, 'blue' 3, 'purple': 5}

The dictfunction can also accept keyword arguments to make a dictionary with string-based keys:

>>> person = dict(name='Trey Hunner', profession='Python Trainer')>>> person{'name': 'Trey Hunner', 'profession': 'Python Trainer'}

But I very much prefer to use a dictionary literal instead:

>>> person = {'name': 'Trey Hunner', 'profession': 'Python Trainer'}>>> person{'name': 'Trey Hunner', 'profession': 'Python Trainer'}

The dictionary literal syntax is more flexible and a bit fasterbut most importantly I find that it more clearly conveys the fact that we are creating a dictionary.

Like with listand tuple, an empty dictionary should be made using the literal syntax as well:

>>> my_list = dict()  # Don't do this>>> my_list = {}  # Do this instead

Using {}is slightly more CPU efficient, but more importantly it’s more idiomatic: it’s common to see curly braces ( {}) used for making dictionaries but dictis seen much less frequently.


The setfunction makes a new set.It takes an iterable of hashablevalues (strings, numbers, or other immutable types) and returns a set:

>>> numbers = [1, 1, 2, 3, 5, 8]>>> set(numbers){1, 2, 3, 5, 8}

There’s no way to make an empty set with the {}set literal syntax (plain {}makes a dictionary), so the setfunction is the only way to make an empty set:

>>> numbers = set()>>> numbersset()

Actually that’s a lie because we have this:

>>> {*()}  # This makes an empty setset()

But that syntax is confusing (it relies on a lesser-used feature of the *operator ), so I don’t recommend it.


The rangefunction gives us a rangeobject, which represents a range of numbers:

>>> range(10_000)range(0, 10000)>>> range(-1_000_000_000, 1_000_000_000)range(-1000000000, 1000000000)

The resulting range of numbers includes the start number but excludes the stop number ( range(0, 10)does not include 10).

The rangefunction is useful when you’d like to loop over numbers.

>>> for n in range(0, 50, 10):...     print(n)...010203040

A common use case is to do an operation ntimes (that’s alist comprehension by the way):

first_five = [get_things() for _ in range(5)]

Python 2’s rangefunction returned a list, which means the expressions above would make very very large lists.Python 3’s rangeworks like Python 2’s xrange(though they’rea bit different) in that numbers are computed lazilyas we loop over these rangeobjects.

Built-ins overlooked by new Pythonistas

If you’ve been programming Python for a bit or if you just taken an introduction to Python class, you probably already knew about the built-in functions above.

I’d now like to show off 15 built-in functions that are very handy to know about, but are more frequently overlooked by new Pythonistas.

The first 10 of these functions you’ll find floating around in Python code, but the last 5 you’ll most often use while debugging.


The boolfunction checks the truthinessof a Python object.

For numbers, truthiness is a question of non-zeroness:

>>> bool(5)True>>> bool(-1)True>>> bool(0)False

For collections, truthiness is usually a question of non-emptiness (whether the collection has a length greater than 0):

>>> bool('hello')True>>> bool('')False>>> bool(['a'])True>>> bool([])False>>> bool({})False>>> bool({1: 1, 2: 4, 3: 9})True>>> bool(range(5))True>>> bool(range(0))False>>> bool(None)False

Truthiness (called truth value testingin the docs) is kind of a big deal in Python.

Instead of asking questions about the length of a container, many Pythonistas ask questions about truthiness instead:

# Instead of doing thisif len(numbers) == 0:    print("The numbers list is empty")# Many of us do thisif not numbers:    print("The numbers list is empty")

You likely won’t see boolused often, but on the occasion that you need to coerce a value to a boolean to ask about its truthiness, you’ll want to know about bool.


Whenever you need to count upward, one number at a time, while looping over an iterable at the same time, the enumeratefunction will come in handy.

That might seem like a very niche task, but it comes up quite often.

For example we might want to keep track of the line number in a file:

>>> with open('hello.txt', mode='rt') as my_file:...     for n, line in enumerate(my_file, start=1):...         print(f"{n:03}", line)...001 This is the first line of the file002 This is the second line003 This is the last line of the file

The enumeratefunction is also very commonly used to keep track of the indexof items in a sequence.

def palindromic(sequence):    """Return True if the sequence is the same thing in reverse."""    for i, item in enumerate(sequence):        if item != sequence[-(i+1)]:            return False    return True

Note that you may see newer Pythonistas use range(len(sequence))in Python.If you ever see code with range(len(...)), you’ll almost always want to use enumerateinstead.

def palindromic(sequence):    """Return True if the sequence is the same thing in reverse."""    for i in range(len(sequence)):        if sequence[i] != sequence[-(i+1)]:            return False    return True

If enumerateis news to you (or if you often use range(len(...))), see my article on looping with indexes in Python.


The zipfunction is even more specialized than enumerate.

The zipfunction is used for looping over multiple iterables at the same time.We actually used it above in the explanations of listand dict.

>>> one_iterable = [2, 1, 3, 4, 7, 11]>>> another_iterable = ['P', 'y', 't', 'h', 'o', 'n']>>> for n, letter in zip(one_iterable, another_iterable):...     print(letter, n)...P 2y 1t 3h 4o 7n 11

If you ever have to loop over two lists (or any other iterables) at the same time, zipis preferred over enumerate.The enumeratefunction is handy when you need indexes while looping, but zipis great when we care specifically about looping over two iterables at once.

If you’re new to zip, I also talk about it in mylooping with indexes article.

Both enumerateand zipreturn iterators to us.Iterators are the lazy iterables that power forloops .I have a whole talk on iteratorsas well as a somewhat advanced article on how to make your own iterators.

By the way, if you need to use zipon iterables of different lengths, you may want to look up itertools.zip_longestin the Python standard library.


The reversedfunction, like enumerateand zip, returns aniterator.

>>> numbers = [2, 1, 3, 4, 7]>>> reversed(numbers)<list_reverseiterator object at 0x7f3d4452f8d0>

The only thing we can do with this iterator is loop over it (but only once):

>>> reversed_numbers = reversed(numbers)>>> list(reversed_numbers)[7, 4, 3, 1, 2]>>> list(reversed_numbers)[]

Like enumerateand zip, reversedis a sort of looping helper function.You’ll pretty much see reversedused exclusively in the forpart of a forloop:

>>> for n in reversed(numbers):...     print(n)...74312

There are some other ways to reverse Python lists besides the reversedfunction:

# Slicing syntaxfor n in numbers[::-1]:    print(n)# In-place reverse methodnumbers.reverse()for n in numbers:    print(n)

But the reversedfunction is usually the best way to reverse any iterablein Python.

Unlike the list reversemethod (e.g. numbers.reverse()), reverseddoesn’t mutate the list (it returns an iterator of the reversed items instead).

Unlike the numbers[::-1]slice syntax, reversed(numbers)doesn’t build up a whole new list: the lazy iterator it returns retrieves the next item in reverse as we loop.Also reversed(numbers)is a lot more readable than numbers[::-1](which just looks weird if you’ve never seen that particular use of slicing before).

If we combine the non-copying nature of the reversedand zipfunctions, we can rewrite the palindromicfunction (fromabove) without taking any extra memory (no copying of lists is done here):

def palindromic(sequence):    """Return True if the sequence is the same thing in reverse."""    for n, m in zip(sequence, reversed(sequence)):        if n != m:            return False    return True


The sumfunction takes an iterable of numbers and returns the sum of those numbers.

>>> sum([2, 1, 3, 4, 7])17

There’s not much more to it than that.

Python has lots of helper functions that do the looping for you, partly because they pair nicely with generator expressions:

>>> numbers = [2, 1, 3, 4, 7, 11, 18]>>> sum(n**2 for n in numbers)524

If you’re curious about generator expressions, I discuss them in my Comprehensible Comprehensionstalk (and my 3 hour tutorial on comprehensions and generator expressions).

min and max

The minand maxfunctions do what you’d expect: they give you the minimum and maximum items in an iterable.

>>> numbers = [2, 1, 3, 4, 7, 11, 18]>>> min(numbers)1>>> max(numbers)18

The minand maxfunctions compare the items given to them by using the <operator.So all values need to be orderable and comparable to each other (fortunately many objects are orderable in Python).

The minand maxfunctions also accept a keyfunction to allow customizing what “minimum” and “maximum” really mean for specific objects.


The sortedfunction takes any iterable and returns a new list of all the values in that iterable in sorted order.

>>> numbers = [1, 8, 2, 13, 5, 3, 1]>>> words = ["python", "is", "lovely"]>>> sorted(words)['is', 'lovely', 'python']>>> sorted(numbers, reverse=True)[13, 8, 5, 3, 2, 1, 1]

The sortedfunction, like minand max, compares the items given to it by using the <operator, so all values given to it need so to be orderable.

The sortedfunction also allows customization of its sorting via a keyfunction (just like minand max).

By the way, if you’re curious about sortedversus the list.sortmethod, Florian Dahlitz wrote an article comparing the two.

any and all

The anyand allfunctions can be paired with a generator expression to determine whether anyor allitems in an iterable match a given condition.

Our palindromicfunction from earlier checked whether allitems were equal to their corresponding item in the reversed sequence (is the first value equal to the last, second to the second from last, etc.).

We could rewrite palindromicusing alllike this:

def palindromic(sequence):    """Return True if the sequence is the same thing in reverse."""    return all(        n == m        for n, m in zip(sequence, reversed(sequence))    )

Negating the condition and the return value from allwould allow us to use anyequivalently (though this is more confusing in this example):

def palindromic(sequence):    """Return True if the sequence is the same thing in reverse."""    return not any(        n != m        for n, m in zip(sequence, reversed(sequence))    )

If the anyand allfunctions are new to you, you may want to read my article on them: Checking Whether All Items Match a Condition in Python.

The 5 debugging functions

The following 5 functions will be useful for debugging and troubleshooting code.


Need to pause the execution of your code and drop into a Python command prompt?You need breakpoint!

Calling the breakpointfunction will drop you into pdb, the Python debugger.There are many tutorials and talks out there on PDB: here’s a short oneand here’s a long one.

This built-in function was added in Python 3.7, but if you’re on older versions of Python you can get the same behavior with import pdb ; pdb.set_trace().


The dirfunction can be used for two things:

  1. Seeing a list of all your local variables
  2. Seeing a list of all attributes on a particular object

Here we can see that our local variables, right after starting a new Python shell and then after creating a new variable x:

>>> dir()['__annotations__', '__doc__', '__name__', '__package__']>>> x = [1, 2, 3, 4]>>> dir()['__annotations__', '__doc__', '__name__', '__package__', 'x']

If we pass that xlist into dirwe can see all the attributes it has:

>>> dir(x)['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

We can see the typical list methods, append, pop, remove, and more as well as many dunder methods for operator overloading.


The varsfunction is sort of a mashup of two related things: checking locals()and testing the __dict__attribute of objects.

When varsis called with no arguments, it’s equivalent to calling the locals()built-in function (which shows a dictionary of all local variables and their values).

>>> vars(){'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}

When it’s called with an argument, it accesses the __dict__attribute on that object (which on many objects represents a dictionary of all instance attributes).

>>> from itertools import chain>>> vars(chain)mappingproxy({'__getattribute__': <slot wrapper '__getattribute__' of 'itertools.chain' objects>, '__iter__': <slot wrapper '__iter__' of 'itertools.chain' objects>, '__next__': <slot wrapper '__next__' of 'itertools.chain' objects>, '__new__': <built-in method __new__ of type object at 0x5611ee76fac0>, 'from_iterable': <method 'from_iterable' of 'itertools.chain' objects>, '__reduce__': <method '__reduce__' of 'itertools.chain' objects>, '__setstate__': <method '__setstate__' of 'itertools.chain' objects>, '__doc__': 'chain(*iterables) --> chain object\n\nReturn a chain object whose .__next__() method returns elements from the\nfirst iterable until it is exhausted, then elements from the next\niterable, until all of the iterables are exhausted.'})

If you ever try to use my_object.__dict__, you can use varsinstead.

I usually reach for dirjust before using vars.


The typefunction will tell you the type of the object you pass to it.

The type of a class instance is the class itself:

>>> x = [1, 2, 3]>>> type(x)<class 'list'>

The type of a class is its metaclass, which is usually type:

>>> type(list)<class 'type'>>>> type(type(x))<class 'type'>

If you ever see someone reach for __class__, know that they could reach for the higher-level typefunction instead:

>>> x.__class__<class 'list'>>>> type(x)<class 'list'>

The typefunction is sometimes helpful in actual code (especially object-oriented code with inheritance and custom string representations), but it’s also useful when debugging.

Note that when type checking, the isinstancefunction is usually used instead of type(also note that we tend not to type check in Python because we prefer to practice duck typing).


If you’re in an interactive Python shell (the Python REPLas I usually call it), maybe debugging code using breakpoint, and you’d like to know how a certain object, method, or attribute works, the helpfunction will come in handy.

Realistically, you’ll likely resort to getting help from your favorite search engine more often than using help.But if you’re already in a Python REPL, it’s quicker to call help(list.insert)than it would be to look up the list.insertmethod documentation in Google.

Learn it later

There are quite a few built-in functions you’ll likely want eventually, but you may not need right now.

I’m going to mention 14 more built-in functions which are handy to know about, but not worth learning until you actually need to use them.


Need to open a file in Python?You need the openfunction!

Don’t work with files directly?Then you likely don’t need the openfunction!

You might think it’s odd that I’ve put openin this section because working with files is so common.While most programmers will read or write to files using openat some point, some Python programmers, such as Django developers, may not use the openfunction very much (if at all).

Once you need to work with files, you’ll learn about open.Until then, don’t worry about it.

By the way, you might want tolook into pathlib (which is in the Python standard library) as an alternative to using open.I love the pathlibmodule so much I’ve considered teaching files in Python by mentioning pathlibfirst and the built-in openfunction later.


The inputfunction prompts the user for input, waits for them to hit the Enter key, and then returns the text they typed.

Reading from standard input(which is what the inputfunction does) is one way to get inputs into your Python program, but there are so many other ways too!You could accept command-line arguments, read from a configuration file, read from a database, and much more.

You’ll learn this once you need to prompt the user of a command-line program for input.Until then, you won’t need it.And if you’ve been writing Python for a while and don’t know about this function, you may simply never need it.


Need the programmer-readable representation of an object?You need the reprfunction!

For many objects, the strand reprrepresentations are the same:

>>> str(4), repr(4)('4', '4')>>> str([]), repr([])('[]', '[]')

But for some objects, they’re different:

>>> str('hello'), repr("hello")('hello', "'hello'")>>> from datetime import date>>> str(date(2020, 1, 1)), repr(date(2020, 1, 1))('2020-01-01', ', 1, 1)')

The string representation we see at the Python REPL uses repr, while the printfunction relies on str:

>>> date(2020, 1, 1), 1, 1)>>> "hello!"'hello!'>>> print(date(2020, 1, 1))2020-01-01>>> print("hello!")hello!

You’ll see reprused when logging, handling exceptions, and implementing dunder methods.


If you create classes in Python, you’ll likely need to use super.The superfunction is pretty much essential whenever you’re inheriting from another Python class.

Many Python users rarely create classes.Creating classes isn’t an essentialpart of Python, though many types of programming require it.For example, you can’t really use the Djangoweb framework without creating classes.

If you don’t already know about super, you’ll end up learning this if and when you need it.


The propertyfunction is a decoratorand a descriptor(only click those weird terms if you’re extra curious) and it’ll likely seem somewhat magical when you first learn about it.

This decorator allows us to create an attribute which will always seem to contain the return value of a particular function call.It’s easiest to understand with an example.

Here’s a class that uses property:

class Circle:    def __init__(self, radius=1):        self.radius = radius    @property    def diameter(self):        return self.radius * 2

Here’s an access of that diameterattribute on a Circleobject:

>>> circle = Circle()>>> circle.diameter2>>> circle.radius = 5>>> circle.diameter10

If you’re doing object-oriented Python programming (you’re making classes a whole bunch), you’ll likely want to learn about propertyat some point.Unlike other object-orient programming languages, we use properties instead of getter methods and setter methods.

issubclass and isinstance

The issubclassfunction checks whether a class is a subclass of one or more other classes.

>>> issubclass(int, bool)False>>> issubclass(bool, int)True>>> issubclass(bool, object)True

The isinstancefunction checks whether an object is an instance of one or more classes.

>>> isinstance(True, str)False>>> isinstance(True, bool)True>>> isinstance(True, int)True>>> isinstance(True, object)True

You can think of isinstanceas delegating to issubclass:

>>> issubclass(type(True), str)False>>> issubclass(type(True), bool)True>>> issubclass(type(True), int)True>>> issubclass(type(True), object)True

If you’re overloading operators(e.g. customizing what the +operator does on your class) you might need to use isinstance, but in general we try to avoid strong type checking in Python so we don’t see these much.

In Python we usually prefer duck typing over type checking.These functions actually do a bit more than the strong type checking I noted above ( the behavior of both can be customized) so it’s actually possible to practice a sort of isinstance-powered duck typing with abstract base classes like this isn’t seen much either (partly because we tend to practice exception-handling and EAFPa bit more than condition-checking and LBYLin Python).

The last two paragraphs were filled with confusing jargon that I may explain more thoroughly in a future serious of articles if there’s enough interest.

hasattr, getattr, setattr, and delattr

Need to work with an attribute on an object but the attribute name is dynamic?You need hasattr, getattr, setattr, and delattr.

Say we have some thingobject we want to check for a particular value on:

>>> class Thing: pass...>>> thing = Thing()

The hasattrfunction allows us to check whether the object hasa certain attribute:

>>> hasattr(thing, 'x')False>>> thing.x = 4>>> hasattr(thing, 'x')True

The getattrfunction allows us to retrieve the value of that attribute:

>>> getattr(thing, 'x')4

The setattrfunction allows for setting the value:

>>> setattr(thing, 'x', 5)>>> thing.x5

And delattrdeletes the attribute:

>>> delattr(thing, 'x')>>> thing.xTraceback (most recent call last):  File "<stdin>", line 1, in <module>AttributeError: 'Thing' object has no attribute 'x'

These functions allow for a specific flavor of metaprogrammingand you likely won’t see them often.

classmethod and staticmethod

The classmethodand staticmethoddecorators are somewhat magical in the same way the propertydecorator is somewhat magical.

If you have a method that should be callable on either an instance or a class, you want the classmethoddecorator.Factory methods (alternative constructors) are a common use case for this:

class RomanNumeral:    """A Roman numeral, represented as a string and numerically."""    def __init__(self, number):        self.value = number    @classmethod    def from_string(cls, string):        return cls(roman_to_int(string))  # function doesn't exist yet

It’s a bit harder to come up with a good use for staticmethod, since you can pretty much always use a module-level function instead of a static method.

class RomanNumeral:    """A Roman numeral, represented as a string and numerically."""    SYMBOLS = {'M': 1000, 'D': 500, 'C': 100, 'L': 50, 'X': 10, 'V': 5, 'I': 1}    def __init__(self, number):        self.value = number    @classmethod    def from_string(cls, string):        return cls(cls.roman_to_int(string))    @staticmethod    def roman_to_int(numeral):        total = 0        for symbol, next_symbol in zip_longest(numeral, numeral[1:]):            value = RomanNumeral.SYMBOLS[symbol]            next_value = RomanNumeral.SYMBOLS.get(next_symbol, 0)            if value < next_value:                value = -value            total += value        return total

The above roman_to_intfunction doesn’t require access to the instance orthe class, so it doesn’t even need to be a @classmethod.There’s no actual need to make this function a staticmethod(instead of a classmethod): staticmethodis just more restrictive to signal the fact that we’re not reliant on the class our function lives on.

I find that learning these causes folks to thinkthey need them when they often don’t.You can go looking for these if you really need them eventually.


The nextfunction returns the nextitem in an iterator.

I’ve written about iterators before (how for loops work and how to make an iterator) but a very quick summary of iterators you’ll likely run into includes:


You can think of nextas a way to manually loop over an iterator to get a single item and then break.

>>> numbers = [2, 1, 3, 4, 7, 11]>>> squares = (n**2 for n in numbers)>>> next(squares)4>>> for n in squares:...     break...>>> n1>>> next(squares)9

Maybe learn it eventually

We’ve already covered nearly half of the built-in functions.

The rest of Python’s built-in functions definitely aren’t useless, but they’re a bit more special-purposed.

The 15 built-ins I’m mentioning in this section are things you may eventually need to learn, but it’s also very possible you’ll never reach for these in your own code.

  • iter : get an iterator from an iterable: this function powers forloops and it can be very useful when you’re making helper functions for looping lazily
  • callable : return Trueif the argument is a callable (I talked about this a bit in my article functions and callables)
  • filter and map : as I discuss in my article on overusing lambda functions, I recommend using generator expressions over the built-in mapand filterfunctions
  • id , locals , and globals : these are great tools for teaching Python and you may have already seen them, but you won’t see these much in real Python code
  • round : you’ll look this up if you need to round a number
  • divmod : this function does a floor division ( //) and a modulo operation ( %) at the same time
  • bin , oct , and hex : if you need to display a number as a string in binary, octal, or hexadecimal form, you’ll want these functions
  • abs : when you need the absolute value of a number, you’ll look this up
  • hash : dictionaries and sets rely on the hashfunction to test for hashability, but you likely won’t need it unless you’re implementing a clever de-duplication algorithm
  • object : this function (yes it’s a class) is useful for making unique default values and sentinel values, if you ever need those

You’re unlikely to need all the above built-ins, but if you write Python code for long enough you’re likely to see nearly all of them.

You likely don’t need these

You’re unlikely to need these built-ins.There are sometimes really appropriate uses for a few of these, but you’ll likely be able to get away with never learning about these.

  • ord and chr : these are fun for teaching ASCII tables and unicode code points, but I’ve never really found a use for them in my own code
  • exec and eval : for evaluating a string as if it was code
  • compile : this is related to execand eval
  • slice : if you’re implementing __getitem__to make a custom sequence, you may need this (some Python Morselsexercises require this actually), but unless you make your own custom sequence you’ll likely never see slice
  • bytes , bytearray , and memoryview : if you’re working with bytes often, you’ll reach for some of these (just ignore them until then)
  • ascii : like reprbut returns an ASCII-only representation of an object; I haven’t needed this in my code yet
  • frozenset : like set, but it’s immutable; neat but not something I’ve reached for in my own code
  • __import__ : this function isn’t really meant to be used by you, use importlibinstead
  • format : this calls the __format__method, which is used for string formatting ( f-stringsand str.format); you usually don’t need to call this function directly
  • pow : the exponentiation operator ( **) usually supplants this… unless you’re doing modulo-math (maybe you’re implementing RSA encryptionfrom scratch…?)
  • complex : if you didn’t know that 4j+3is valid Python code, you likely don’t need the complexfunction

There’s always more to learn

There are 69 built-in functions in Python (technically only 42 of them are actually functions).

When you’re newer in your Python journey, I recommend focusing on only 20 of these built-in functions in your own code (the10 commonly known built-insand the10 built-ins that are often overlooked), in addition to the5 debugging functions.

After that there are14 more built-ins which you’ll probably learn later(depending on the style of programming you do).

Then comethe 15 built-ins which you may or may not ever end up needing in your own code.Some people love these built-ins and some people never use them: as you get more specific in your coding needs, you’ll likely find yourself reaching for considerably more niche tools.

After that I mentionedthe last 17 built-ins which you’ll likely never need(again, very much depending on how you use Python).

You don’t need to learn all the Python built-in functions today.Take it slow: focus on those first 20 important built-ins and then work your way into learning about others if and when you eventually need them.