Share
Embed
What does = do? (Talk from Euro Python 2025)
We use assignment all the time in Python. But what really happens when we use an = in our code? The answer is: It depends. In this talk, I'll explore what happens when we assign a value to a variable, when we mutate an existing value, and when we assign to an attribute. Along the way, we'll explore variable scopes, byte codes, and descriptors. By the end of this talk, you'll appreciate all the hard work that the little = sign is doing, and the remarkable stuff that happens behind the scenes when you use it.
Reuven M. Lerner
July 18, 2025
Transcript
79 slides
-
What does = do? Reuven M. Lerner • EuroPython 2025
https://LernerPython.com 1 -
What does = do? Reuven M. Lerner • https://LernerPython.com I
teach Python and Pandas 2 In business since 1995 2 -
What does = do? Reuven M. Lerner • https://LernerPython.com 3
Courses • Exercises • Of f ice hours • Discord • Projects 3 -
What does = do? Reuven M. Lerner • https://LernerPython.com 4
BetterDevelopersWeekly.com 4 -
What does = do? Reuven M. Lerner • https://LernerPython.com 5
BambooWeekly.com 5 -
What does = do? Reuven M. Lerner • https://LernerPython.com x
= 100 What happens when we assign? 9 9 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
We use = to assign • Not the same as the mathematical = • Rather, it means: • Evaluate the right side • Assign the value you get to the variable on the left The assignment operator 10 10 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
We always evaluate the right side f irst! • The result of that evaluation is assigned Right before left! 11 x = 75 + 25 x = 100 11 -
What does = do? Reuven M. Lerner • https://LernerPython.com Here’s
what is not happening 12 x 100 12 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Because it’s an easy-to-understand metaphor • Also: For C programmers, it’s accurate! • Variables are aliases for memory locations • When you assign, you’re putting a value in memory Why would we think this? 13 13 -
What does = do? Reuven M. Lerner • https://LernerPython.com Python
tutor doesn’t help 14 14 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Variables refer to values • Not memory locations • Not other variables • Values are anonymous Python isn’t like this 15 15 -
What does = do? Reuven M. Lerner • https://LernerPython.com If
values are nouns, then variables are pronouns 16 16 -
What does = do? Reuven M. Lerner • https://LernerPython.com Modify
the Python tutor 17 17 -
What does = do? Reuven M. Lerner • https://LernerPython.com Now
our image is accurate 18 18 -
What does = do? Reuven M. Lerner • https://LernerPython.com >>>
dis.dis(bytecode) 0 RESUME 0 1 LOAD_CONST 0 (100) STORE_NAME 0 (x) RETURN_CONST 1 (None) Disassemble “x = 100” 19 19 -
What does = do? Reuven M. Lerner • https://LernerPython.com x
= 100 What really happens when we assign? 20 20 -
What does = do? Reuven M. Lerner • https://LernerPython.com x
= 100 y = x x = 200 print(y) What does this code do? 21 Variable “x” refers to int 100 Variable “y” refers to whatever x refers to … not to x! Variable “x” refers to int 200 Prints 100, because y still refers to 100 21 -
What does = do? Reuven M. Lerner • https://LernerPython.com In
the Python Tutor… 22 x = 100 y = x x = 200 print(y) 22 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
The = operator isn’t the only way to assign to a variable! • Some keywords also do it def class import • We’re going to ignore those — but realize that they all assign to variables, as well as creating function, class, and module values. Other ways to assign 23 23 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
So far, we’ve assigned to global variables • Python keeps track of globals in a dict • (See them with globals() !) Global variables 24 24 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
But… globals are problematic! • One part of the program can step on another part • In Python, only functions create local variables • No functions? No locals • Indentation doesn’t create local variables Local variables 25 25 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Python’s compiler notices variable assignments in a function • It stores them in the function object def mysum(a, b): total = a + b return total >>> mysum.__code__.co_varnames ('a', 'b', 'total') “Declaring” local variables 26 26 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
If you assign to a variable in a function, it’s local • Even if there’s a global of the same name • STORE_FAST means: store in a local variable Local variables 27 27 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
myfunc(): x = 100 >>> dis.dis(myfunc) 1 RESUME 0 2 LOAD_CONST 1 (100) STORE_FAST 0 (x) RETURN_CONST 0 (None) Let’s disassemble! 28 28 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
The “global” keyword means: when we assign, we’ll assign to the global • No local variable is created • What if we want to assign to a global? 29 29 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
myfunc(): global x x = 100 >>> dis.dis(myfunc) 1 RESUME 0 3 LOAD_CONST 1 (100) STORE_GLOBAL 0 (x) RETURN_CONST 0 (None) Disassembling “global” 30 30 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Depending on context, = can thus mean 1. Assign to a global variable (outside of a function) 2. Assign to a global variable (inside of a function, via “global”) 3. Assign to a local variable (inside of a function) = means 3 different things 31 31 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
We’ve already seen this: def mysum(x, y): total = x + y return total • What if we want to know how many times mysum was run? • We can rewrite it as an inner function! • “counter” can be an integer in the outer function that tracks how often we’ve calculated sums What about inner functions? 32 32 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Running “outer” returns “mysum” • “counter” — a local in the outer function — sticks around across calls def outer(): counter = 0 def mysum(x, y): counter += 1 total = x + y print(f'[{counter}] {x} + {y} = {total}') return total return mysum Nested functions 33 33 -
What does = do? Reuven M. Lerner • https://LernerPython.com >>>
sum_counter = outer() >>> sum_counter(10, 3) UnboundLocalError: cannot access local variable 'counter' where it is not associated with a value Just one problem… 34 34 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
+= is assignment, not mutation • As always, assigning to “counter” creates a local variable • But we want to assign to “counter” in the outer function! • We can’t use the “global” keyword, because it isn’t • We can use the “nonlocal” keyword • Assignment then binds to the local in the enclosing function += assigns to a local! 35 35 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
outer(): counter = 0 def mysum(x, y): nonlocal counter counter += 1 total = x + y print(f'[{counter}] {x} + {y} = {total}') return total return mysum Use “nonlocal” to solve this 36 36 -
What does = do? Reuven M. Lerner • https://LernerPython.com >>>
sum_counter = outer() >>> sum_counter(10, 3) [1] 10 + 3 = 13 13 >>> sum_counter(20, 5) [2] 20 + 5 = 25 25 Let’s try it! 37 37 -
What does = do? Reuven M. Lerner • https://LernerPython.com >>>
dis.dis(sum_counter) -- COPY_FREE_VARS 1 3 RESUME 0 5 LOAD_DEREF 3 (counter) LOAD_CONST 1 (1) BINARY_OP 13 (+=) STORE_DEREF 3 (counter) 6 LOAD_FAST_LOAD_FAST 1 (x, y) BINARY_OP 0 (+) STORE_FAST 2 (total) Examining (some) opcodes 38 38 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Depending on context, = can thus mean 1. Assign to a global variable (outside of a function) 2. Assign to a global variable (inside of a function, via “global”) 3. Assign to a local variable (inside of a function) 4. Assign to a non-local variable (in the enclosing function) = means 4 different things 39 39 -
What does = do? Reuven M. Lerner • https://LernerPython.com >>>
mylist = [10, 20, 30] >>> mylist[1] = 999 What happens here? 41 41 -
What does = do? Reuven M. Lerner • https://LernerPython.com We
aren’t assigning. We are mutating. 42 42 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
The variable refers to the same data structure • But the data structure changes Mutating is different! 43 43 -
What does = do? Reuven M. Lerner • https://LernerPython.com Consider
this 44 Assignment changes this arrow (the name-to- value binding) Mutation changes this arrow (the value Itself) 44 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
normal_mutate(data): data[1] = 2 >>> dis.dis(normal_mutate) 1 RESUME 0 2 LOAD_CONST 1 (2) LOAD_FAST 0 (data) LOAD_CONST 2 (1) STORE_SUBSCR RETURN_CONST 0 (None) STORE_SUBSCR 45 45 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Depending on context, = can thus mean 1. Assign to a global variable (outside of a function) 2. Assign to a global variable (inside of a function, via “global”) 3. Assign to a local variable (inside of a function) 4. Assign to a non-local variable (in the enclosing function) 5. Mutate the value on the left (list, dict, or your own object) = means 5 different things 46 46 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Variables • Attributes • A private dict on each Python object (or value) • When you say “a.b”, you mean “attribute b on object a” • How to distinguish? • Variables live in namespaces • Attributes live in values (objects) Python has two storage systems 47 47 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Yes — on nearly everything! • The STORE_ATTR opcode assigns >>> import random >>> random.x = 100 >>> print(random.x) 100 Can we assign to an attribute? 48 48 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
set_random_x(): random.x = 1234 >>> dis.dis(set_random_x) 1 RESUME 0 2 LOAD_CONST 1 (1234) LOAD_GLOBAL 0 (random) STORE_ATTR 1 (x) RETURN_CONST 0 (None) What bytecode is running? 49 49 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Depending on context, = can thus mean 1. Assign to a global variable (outside of a function) 2. Assign to a global variable (inside of a function, via “global”) 3. Assign to a local variable (inside of a function) 4. Assign to a non-local variable (in the enclosing function) 5. Mutate the value on the left (list, dict, or your own object) 6. Assign a new value to the attribute on the left = means 6 different things 50 50 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Some attributes are special • That is: When we set them, a method is invoked • And when we read from them, another method is invoked • No () are needed! • These are properties Properties 51 51 -
What does = do? Reuven M. Lerner • https://LernerPython.com class
Car: def __init__(self): self._speed = 0 @property def speed(self): print('In speed getter') return self._speed @speed.setter def speed(self, new_speed): print('In speed setter') if new_speed < 0: raise ValueError('Too slow!') if new_speed > 140: raise ValueError('Too fast!') self._speed = new_speed Property example 52 52 -
What does = do? Reuven M. Lerner • https://LernerPython.com >>>
c = Car() >>> c.speed In speed getter 0 c.speed = 100 In speed setter c.speed In speed getter 100 Using our property 53 How can this be? Assignment invokes a method?!? 53 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
set_speed(): c.speed = 100 >>> dis.dis(set_speed) 1 RESUME 0 2 LOAD_CONST 1 (100) LOAD_GLOBAL 0 (c) STORE_ATTR 1 (speed) RETURN_CONST 0 (None) Bytecodes are the same 54 54 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
If a class has an attribute • And that attribute is a property • And we assign via the instance • Then we invoke the property’s “setter” method Attributes have some magic 55 55 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Properties are simple versions of descriptors. • The descriptor protocol: • De f ine a descriptor class with __get__ and __set__ methods • De f ine an owner class, and set a class attribute to an instance of the descriptor class • If we assign to the descriptor via an instance, the __set__ method is invoked Descriptors 56 56 -
What does = do? Reuven M. Lerner • https://LernerPython.com class
Descriptor: def __init__(self): self.value = 10 def __get__(self, obj, objtype=None): print(f'In __get__, {self=}, {obj=}, {objtype=}') return self.value def __set__(self, obj, new_value): print(f'In __set__, {self=}, {obj=}, {new_value=}') self.value = new_value De f ining a descriptor 57 57 -
What does = do? Reuven M. Lerner • https://LernerPython.com class
Owner: d = Descriptor() o = Owner() Using the descriptor 58 Class attribute, an instance of Descriptor 58 -
What does = do? Reuven M. Lerner • https://LernerPython.com >>>
o.d = 20 • o is an instance of Owner • d is a class attribute on Owner • We assign to d via the instance, o • d is an instance of Descriptor • Descriptor has a __set__ method • Assignment runs __set__! In __set__, self=<__main__.Descriptor object at 0x1059a9fd0>, obj=<__main__.Owner object at 0x1059aa3c0>, new_value=20 Assigning to the descriptor 59 59 -
What does = do? Reuven M. Lerner • https://LernerPython.com In
the Python tutor 60 60 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Instead of Descriptor, we’ll call it Speed • Instead of Owner, we’ll call it Car • Instead of d, we’ll call it speed • In other words, we’ve recreated our property… • …but now we can use it in multiple classes! Let’s make this more concrete 61 61 -
What does = do? Reuven M. Lerner • https://LernerPython.com class
Speed: def __init__(self): self._speed = 10 def __get__(self, obj, objtype=None): print(f'In __get__, {self=}, {obj=}, {objtype=}') return self._speed def __set__(self, obj, new_speed): print(f'In __set__, {self=}, {obj=}, {new_speed=}') if new_speed < 0: raise ValueError('Too slow!') if new_speed > 140: raise ValueError('Too fast!') self._speed = new_speed Our Speed descriptor 62 62 -
What does = do? Reuven M. Lerner • https://LernerPython.com class
Car: speed = Speed() c = Car() c.speed = 100 Putting Speed in the car 63 Class attribute, an instance of Speed 63 -
What does = do? Reuven M. Lerner • https://LernerPython.com In
Python Tutor 64 64 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
What if we have two instances of Car? car1 = Car() car2 = Car() • They share a Speed descriptor • That instance of Speed stores its value in self.value • So assigning to car1.speed changes Car.speed._speed • And assigning to car2.d also changes Car.speed._speed • Uh oh! 😱 A problem 65 65 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Don’t store a single value in the Speed descriptor • Instead, use a dict! • Keys are instances of Car (or whatever class is using Speed) • Values are the speci f ic values for that descriptor “owner” The solution 67 67 -
What does = do? Reuven M. Lerner • https://LernerPython.com class
Speed: def __init__(self): self.values = {} def __get__(self, obj, objtype=None): print(f'In __get__, {self=}, {obj=}, {objtype=}') return self.values[obj] def __set__(self, obj, new_speed): print(f'In __set__, {self=}, {obj=}, {new_speed=}') if new_speed < 0: raise ValueError('Too slow!') if new_speed > 140: raise ValueError('Too fast!') self.values[obj] = new_speed Updated Speed descriptor 68 68 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
We assign to car1.speed or car2.speed • We’re assigning to a class attribute (Car.speed) via the instance • That class attribute, of type Speed, has a __set__ method • Assigning to car1.speed gets transformed into a call to __set__ • self is the instance of Speed, aka Car.speed • obj is the instance of Car, aka car1 or car2 • new_speed is the value on the right of assignment • The effect is to mutate the dict in Speed.values In other words 69 69 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Do things this way, and you’ll have a memory leak! • The dict will always refer to each instance • And referred-to objects are never garbage collected • The standard solution: Use a WeakKeyDict for storing values • That way, the descriptor’s dict won’t keep the value from being freed Memory leaks 71 71 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Depending on context, = can thus mean 1. Assign to a global variable (outside of a function) 2. Assign to a global variable (inside of a function, via “global”) 3. Assign to a local variable (inside of a function) 4. Assign to a non-local variable (in the enclosing function) 5. Mutate the value on the left (list, dict, or your own object) 6. Assign a new value to the attribute on the left 7. Cause the __set__ method in a descriptor to f ire, if we assign to a class attribute via an instance = means 7 different things! 72 72 -
What does = do? Reuven M. Lerner • https://LernerPython.com 73
Opcode Meaning STORE_NAME or STORE_GLOBAL Assign to a global (outside a function, or inside with “global”) STORE_FAST Assign to a local (inside a function) STORE_DEREF Assign to a local in an enclosing function STORE_SUBSCR Mutate a value STORE_ATTR Assign to an attribute — which might, if the attribute is a descriptor, result in the execution of its __set__ method 73 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
assign_assign(): x = y = 5 >>> dis.dis(assign_assign) 1 RESUME 0 2 LOAD_CONST 1 (5) COPY 1 STORE_FAST_STORE_FAST 1 (x, y) RETURN_CONST 0 (None) Multiple assignment 74 74 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
assign_assign_assign(): x = y = z = 5 >>> dis.dis(assign_assign_assign) 1 RESUME 0 2 LOAD_CONST 1 (5) COPY 1 STORE_FAST 0 (x) COPY 1 STORE_FAST_STORE_FAST 18 (y, z) RETURN_CONST 0 (None) What if we do three? 75 75 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
unpacking2(): x,y = [10, 20] >>> dis.dis(unpacking2) 1 RESUME 0 2 LOAD_CONST 1 (10) LOAD_CONST 2 (20) BUILD_LIST 2 UNPACK_SEQUENCE 2 STORE_FAST_STORE_FAST 1 (x, y) RETURN_CONST 0 (None) What about unpacking? 76 76 -
What does = do? Reuven M. Lerner • https://LernerPython.com def
unpacking3(): x,y,z = [10, 20, 30] >>> dis.dis(unpacking3) 1 RESUME 0 2 BUILD_LIST 0 LOAD_CONST 1 ((10, 20, 30)) LIST_EXTEND 1 UNPACK_SEQUENCE 3 STORE_FAST_STORE_FAST 1 (x, y) STORE_FAST 2 (z) RETURN_CONST 0 (None) And with 3 elements… 77 77 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
Assignment seems obvious and simple • But this one operator does many different things • It creates variables, and binds their names to values • It creates attributes, and binds their names to values • It mutates values • It f ires methods (in properties and descriptors) • It can even cause memory leaks, if you aren’t careful • These different things feel similar to us as people • But Python sees them as totally different Conclusion 78 78 -
What does = do? Reuven M. Lerner • https://LernerPython.com •
My courses: https://LernerPython.com • Python articles: https://BetterDevelopersWeekly • Pandas puzzles: https://BambooWeekly.com • YouTube: https://YouTube.com/reuvenlerner • Bluesky: @lernerpython.com Questions? Comments? 79 79