Another fundamental Python term for #TerminologyTuesday

callable: an object which can be called

The classical "callable" is a function, but in #Python classes are also callables.
In many programming languages (e.g. JS, PHP, C++) creating a new "instance" of a class (an object whose type is that class) involves the "new" keyword:

let eol = new Date(2020, 1, 1);

But in #Python to make a new class instance we just call the class:

eol = date(2020, 1, 1)
The fact that classes are callables means the distinction between a function and a class is often quite subtle. All of these "functions" are actually implemented as classes:

n = float("4.5")
m = int(n)
s = str(m)
b = bool(m)
t = tuple('abcd')
e = enumerate(t)
r = reversed(t)
When you call a function, you get the return value of that function.

When you call a class, you get back an "instance" of that class.

class Thing:
def __init__(self, name):
self.name = name

thing = Thing() # Thing instance
"Function" is a fuzzy term in the Python world because we often use it to refer to non-functions.

The phrases "the reversed function" or "the int function" might be technically incorrect but colloquially they're a-okay.

When teaching I sometimes use these terms:

- enumerate function
- type function
- reversed function
- map function

Those are *technically* incorrect terms but that's okay!

Whether those "functions" are defined using a function or a class is an implementation detail.
Python itself even uses the word "function" loosely: the docs for map and filter say they accept a function (but they mean "callable").

Also functools.partial claims to accept a function and return a function. But partial is a class, so it actually returns a class instance!
While the fuzziness of the term "function" is perfectly acceptable, it's sometimes useful to use a more generic term.

In @PythonMorsels exercises we often say "create a callable which..."

Thinking in callables reminds us that there are multiple ways to implement the same thing.
@PythonMorsels So why not say "function or class"? Well, there's a bit more to callability than that.

Any object with a __call__ method is a callable.

class Silly:
def __init__(self, m): self.m = m
def __call__(self): print(self.m)

Silly("Hi")()

Try it out: pym.dev/p/2y2kg/
@PythonMorsels Wait... but if callables are "callable objects", are classes and functions objects? 😮

They are!

You pass them around, just like any other object. Everything is an object in Python (except for variables, which just point to "things").

pym.dev/everything-is-…
@PythonMorsels For more on...

➡️ Variables as pointers to objects in Python: pym.dev/pointers/
➡️ Class instances: pythonmorsels.com/terms/#instance
➡️ Classes and functions being "callables" in python: pym.dev/class-function…

Follow me for more #Python tips 🌠

• • •

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

Keep Current with Trey Hunner (Python trainer)

Trey Hunner (Python trainer) 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 @treyhunner

Jun 1
Need to split up seconds into hours, minutes, & seconds in #Python?

This is one of the rare instances in which I might reach for Python's built-in divmod function. Though datetime.timedelta might work too, depending on your use case.

Let's compare int, //, divmod, & timedelta🧵
Given a number of seconds:

>>> duration = 4542

You might have thought to use division, modulo, and Python's int function 🤔

hours = int(duration/60 / 60)
minutes = int(duration/60 % 60)
seconds = duration % 60
But that int function is there because we're doing truncating division. Python has an operator just for that!

The // operator:

hours = duration // (60*60)
minutes = duration // 60 % 60
seconds = duration % 60

When x and y are ints, x//y is exactly the same as int(x/y).
Read 9 tweets
May 31
Python Quiz: what input will result in different behavior from the built-in int function and the math.floor function?

>>> int(x)
vs

>>> import math
>>> math.floor(x)

They're *usually* the same
Those replying negative numbers: you're absolutely right!

There's another input that has different behavior for math.floor and int in Python too. 🤔

Other guesses?
The two answers I've found are negative numbers and strings.

x = -3.3 # int returns -3 and floor returns -4

x = "3.3" # int returns 3 and floor raises TypeError

pym.dev/p/2tc43/
Read 4 tweets
May 26
Python's "for" loops are single-purposed: they can loop over an iterable item-by-item. That's it.

The "for" loop itself can't loop in reverse or loop over multiple iterables.

For this reason, looping helpers are a VERY big deal in #Python.

Let's talk about looping helpers. 🧵
Want to loop over an iterable in the reverse direction? If it's a reversible iterable (lists, tuples, dictionaries, etc), you can use the reversed helper:

>>> colors = ["pink", "blue", "green"]
>>> for color in reversed(colors):
... print(color)
...
green
blue
pink
Note that the "for" loop isn't reversing here: reversed is!

The built-in reversed function accepts an iterable and returns a lazy iterable that provides each item from the original iterable in the reverse order.

>>> r = reversed(colors)
>>> next(r)
'green'
>>> next(r)
'blue'
Read 12 tweets
May 25
I recommend against using the file readlines method in #Python.

Many folks assume that readlines returns a lazy iterable (an iterator) of lines. But the readlines method returns a list, not an iterator!

These are equivalent:

lines = my_file.readlines()
lines = list(my_file)
If you need to lazily loop over lines in a file, you can loop over the file object itself to do that:

for line in my_file:
...

You can use a file like any other iterable. For example you can use it in a comprehension:

non_empty = [line for line in my_file if line.strip()]
When I need to make a list of all lines in a file, I use the list constructor:

lines = list(my_file)

I find that clearer than this:

lines = my_file.readlines()

☝ That second line can lead newer Pythonistas to assume this is okay:

for line in my_file.readlines():
...
Read 5 tweets
May 24
Ever wondered "what's a float"?

floating point number (a.k.a. float): an object used for representing real numbers using a fairly accurate approximation

Let's talk about floats work in #Python!

#TerminologyTuesday
Floating point numbers are an approximation of their decimal equivalents.

They're super useful for most uses, but they can't be relied on for exact precision.

You can't assume that an exact equality comparison with floating point numbers will work:

>>> 0.1 + 0.02 == 0.12
False
Adding 0.1 and 0.02 results in a number that is VERY slightly different from the 0.12 number that we'd expect:

>>> 0.1 + 0.02
0.12000000000000001

This might seem like a huge problem, but it's usually not! This imprecision typically only causes trouble with strict equality.
Read 11 tweets
May 19
I love Python's pathlib module. 💖🐍🗃

Whenever I need to ask a question about a file path in #Python, I default to using pathlib.

Let's talk about some of my most common uses for pathlib and compare them to their non-pathlib alternatives. 🧵
Assume all the below examples include the "filename" and "path" variables defined like this:

>>> from pathlib import Path
>>> filename = "my_file.txt"
>>> path = Path(filename)

Also assume that we've imported os, glob, and os.path as needed:

>>> import glob, os, os.path
Get an absolute path (from a path that may be relative or may already be absolute).

💾 Old approach:

>>> filename = os.path.abspath(filename)

✨ pathlib approach:

>>> path = path.resolve()
Read 12 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

Don't want to be a Premium member but still want to support us?

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!

:(