Skip to content

Commit 89c3343

Browse files
committed
add issue#33
1 parent db09608 commit 89c3343

2 files changed

Lines changed: 204 additions & 7 deletions

File tree

issues/33.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# pycobytes[33] := What even is a function?
2+
<!-- #SQUARK live!
3+
| dest = issues/(issue)/33
4+
| title = What even is a function?
5+
| head = What even is a function?
6+
| index = 33
7+
| tags = technical
8+
| date = 2025 June 20
9+
-->
10+
11+
> *Perfection is achieved not when there is nothing more to add, but when there is nothing more to take away.*
12+
13+
Hey pips!
14+
15+
Python is, famously, an **object-oriented** programming language. I’ll assume you already know how to create your own `class`es and instantiate objects – they’re usually the endpoint of Python courses, and are better covered by a video tutorial than any written one.
16+
17+
> [!Note]
18+
> I originally planned an entire sequence of issues on objects, `__dunder__` methods, `__slots__`, the whole rabbit-hole, butttt we’re outta time, so I’d rather not rush or condense those.
19+
20+
Once you fall into the object-oriented paradigm, it kinda becomes hard to see how a programming language could be anything else, because objects just *make sense*.
21+
22+
Here’s how it works: **Everything is an object.**
23+
24+
Yeah, literally.
25+
26+
Ok, not quite *everything* everything, but linguistic syntax aside, all of programming in Python is just dealing with objects. Defining them, creating them, mutatng them, passing them around, interacting with them, all that.
27+
28+
There’s no good angle of attack for this, so I’ll just throw us straight in the deep end here. Functions? Yeah, those are objects. (In Python, at least.)
29+
30+
```py
31+
def hallucinate(): # <—- this is an object!!
32+
print("huh")
33+
```
34+
35+
Seems sus? Well, have you never wondered what typing a function without the parentheses does?
36+
37+
```py
38+
>>> hallucinate # look ma, no brackets
39+
<function_object>
40+
```
41+
42+
👀
43+
44+
That’s an object right there. Notice we didn’t call the function, cuz no `huh` was printed – you’d need `()` for that. We’re just referencing the function, the function *object*.
45+
46+
Like any object, you can assign functions to variables, pass them into other functions, and store them in containers.
47+
48+
```py
49+
my_var = hallucinate
50+
51+
my_func(hallucinate)
52+
53+
my_stuff = [hallucinate, hallucinate, hallucinate]
54+
```
55+
56+
Really, functions are just a special kind of object that you can do `this_object()` on – i.e. they can be called with `()`. This property just happens to be so fundamental in programming that we give these types of objects an individual name.
57+
58+
> [!Note]
59+
> If looking at `__dunder__` methods, any object that defines a `__call__()` method is callable... and so could be called a function. But then if you wonder how `__call__()` can be a function, since it would needs its own `__call__()` (it doesn’t, it’ll be implemented in C), it just becomes a rabbit hole down to the lands of Assembly.
60+
>
61+
> The ground truth is that some features of the language are atomic in Python, like how (to our current physical understanding) quarks can’t be broken down further.
62+
63+
One quick detour before we continue. When you learn how to code, you’re introduced to “variables”. I don’t really like this term, because it’s rather misleading. In the example above, what’s `hallucinate`? Would you call it a variable? It certainly looks like one, but I thought it’s also a function? Can you ‘call’ a variable like `this()`? Are functions and variables the same?
64+
65+
I find **identifier** is a much more robust and non-arbitrary term. `hallucinate` is the identifier – i.e. the literal text you type – to refer to the function *object* that it represents. Like here, `sup` is a way of referring to the object `2`:
66+
67+
```py
68+
sup = 2
69+
```
70+
71+
And if we assign `sup` to another identifier `soup`:
72+
73+
```py
74+
>>> soup = sup
75+
```
76+
77+
Then `soup` is now also an identifier for the same object `2`.
78+
79+
```py
80+
>>> soup is sup
81+
True
82+
```
83+
84+
Importantly, `soup` does *not* store the ‘variable’ `sup` at all. The two identifiers are unrelated. They just store the same *object*, the number `2`.
85+
86+
So back to functions. When we define a function, the `def` syntax binds it to an identifier:
87+
88+
```py
89+
def roll():
90+
print("yooooooooo")
91+
```
92+
93+
And when we call that identifier, we call the function.
94+
95+
```py
96+
>>> roll()
97+
yooooooooo
98+
```
99+
100+
We can give the function a new identifier by assigning it to... that new identifier!
101+
102+
```py
103+
>>> roll_faster = roll
104+
>>> roll_faster()
105+
yooooooooo
106+
107+
# another one
108+
>>> roll_harder = roll
109+
>>> roll_harder()
110+
yooooooooo
111+
```
112+
113+
This doesn’t ‘rename’ the function or anything. All it’s doing is assigning the function object to more than 1 identifier.
114+
115+
```py
116+
# these now all refer to the same function
117+
>>> roll()
118+
yooooooooo
119+
>>> roll_faster()
120+
yooooooooo
121+
>>> roll_harder()
122+
yooooooooo
123+
```
124+
125+
Where might this be relevant? Well, maybe your function isn’t defined already, but is *returned* by another function...
126+
127+
```py
128+
def mob_spawner():
129+
def output_func():
130+
print("AHHHHHHHHH")
131+
132+
# returns the function object
133+
return output_func
134+
```
135+
136+
Oh yes, if functions are objects, then there’s nothing stopping functions from returning other functions >:) So now, we can assign the output to an identifier (variable), and then call it:
137+
138+
```py
139+
>>> spawn = mob_spawner()
140+
>>> spawn()
141+
AHHHHHHHHH
142+
```
143+
144+
Weird much, eh? And yes, this does mean if you wanted to immediately call the output, you’d do this...
145+
146+
```py
147+
>>> mob_spawner()()
148+
AHHHHHHHHH
149+
```
150+
151+
Don’t worry, it’ll get even weirder when we look at decorators. Functions returning functions that take in functions to return decorated functions. Don’t we love objects.
152+
153+
Of course, I think it’s still totally fine to refer to variables as, well, variables. This is the expected terminology. However, I think it’s worth appreciating that you can store *any* object in a variable – this includes functions, classes, modules, and more – and in this sense, thinking of them as “identifiers” can help break any misconceptions you might hold.
154+
155+
156+
<br>
157+
158+
159+
---
160+
161+
<div align="center">
162+
163+
[![The Codeless Code, Case 31](../assets/issues/33-codeless.png)](http://thecodelesscode.com/case/31)
164+
165+
[*The Codeless Code*, Case 31](http://thecodelesscode.com/case/31)
166+
167+
</div>

site/src/data/site.json

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"meta": {
3-
"exported": "2025-06-13",
4-
"file_count": 37,
5-
"page_count": 36
3+
"exported": "2025-06-20",
4+
"file_count": 38,
5+
"page_count": 37
66
},
77
"index": {
88
"01": {
@@ -197,6 +197,12 @@
197197
"issues/32.md"
198198
]
199199
},
200+
"33": {
201+
"route": null,
202+
"pages": [
203+
"issues/33.md"
204+
]
205+
},
200206
"404": {
201207
"route": null,
202208
"pages": [
@@ -272,7 +278,8 @@
272278
"technical": [
273279
"issues/07.md",
274280
"issues/09.md",
275-
"issues/11.md"
281+
"issues/11.md",
282+
"issues/33.md"
276283
],
277284
"functions": [
278285
"issues/10.md",
@@ -1103,7 +1110,7 @@
11031110
},
11041111
"issues/32.md": {
11051112
"path": "issues/32.md",
1106-
"last_deploy": "2025-06-13 15:35:24 +0100",
1113+
"last_deploy": "2025-06-13 15:45:05 +0100",
11071114
"slocs": 200,
11081115
"chars": 5791,
11091116
"isIndex": false,
@@ -1121,8 +1128,31 @@
11211128
"tags": [
11221129
"syntax"
11231130
],
1124-
"date": "2025-06-12",
1125-
"date_display": "2025 June 12"
1131+
"date": "2025-06-13",
1132+
"date_display": "2025 June 13"
1133+
},
1134+
"issues/33.md": {
1135+
"path": "issues/33.md",
1136+
"last_deploy": "2025-06-20 12:04:41 +0100",
1137+
"slocs": 167,
1138+
"chars": 5919,
1139+
"isIndex": false,
1140+
"flags": [
1141+
"live"
1142+
],
1143+
"dest": "issues/(issue)/33",
1144+
"title": "What even is a function?",
1145+
"head": "What even is a function?",
1146+
"capt": null,
1147+
"desc": null,
1148+
"index": [
1149+
"33"
1150+
],
1151+
"tags": [
1152+
"technical"
1153+
],
1154+
"date": "2025-06-20",
1155+
"date_display": "2025 June 20"
11261156
},
11271157
"issues/404.md": {
11281158
"path": "issues/404.md",

0 commit comments

Comments
 (0)