Mm. Let's talk about this. I use this as one of my examples in my "WTF Python" introductory lecture...the first lecture I do in my Python Programming class.
I'll start with what's happening, move on to how to avoid it, then finish with when to use it.
First, a plug for another thread: if the idea of a "WTF Python Lecture" is intriguing to you, here's a thread where I talked about why I do that lecture!
So now, let's talk about what's happening in the above code snippet.
Python evaluates default arguments when it places the DEFINITION of the function into the environment. Not when it RUNS that function. So the default arguments keep the id they had at function definition time.
No problem when your defaults are immutable. But a list is mutable.
That means, when you change the list set in this function as the DEFAULT argument, it's gonna keep using that changed list in future calls that don't set that argument.
If I understand correctly, this was an oversight in the original implementation, but it has been kept bc...
1. There's a way around it and python strives to have "one right way" 2. It's well known, so people were already using the aforementioned circumnavigation 3. ALSO people were using THE FACT THAT PYTHON DOES THIS, and as such 4. Changing it would break people's code.
Zooming out:
The Python maintainers have a very different risk calculation to make about changing behavior than, I dunno, you or I do on a pet project, because their project is in active use by 8.2 million people whose code they need to not break.
This EXPLICITLY sets that default to a FRESH NEW list at function RUN time.
Another syntactic sugar you'll see on the above is "if not default_list." I don't use that for two reasons:
1. The above way is more explicit on what is happening because it doesn't bank on the reader having to remember that None is falsey.
So that's reason 1.
Reason 2: [ ] is also falsey.
So "if not default_list" will REASSIGN that name to a NEW empty list if someone passes in an empty list as the argument. Doesn't break things, but pointless.
BONUS REASON: "" and 0 are ALSO falsey so this behavior won't raise in some cases where someone is passing in the wrong kind of default.
I like my code to tell people when they're doing things wrong before they have to go investigate and then change half their program over it.
ANYWAY, we talked about why this happens and how to avoid it.
When do you use it?
Honestly I don't use this in prod code. I set an instance variable if I want an object to hang onto state.
I do use it occasionally in mocks. Here's how:
1. The object I am mocking mutates some state that I cannot access through an existing instance variable. 2. I don't want to add an instance var to an object JUST to test it, but I want to confirm something happened in this function... 3. Across multiple calls to the function.
Example:
class Logger(Loggable):
def log(msg): #prod behavior
class MockLogger(Loggable):
def log(msg, messages=[]):
messages.append(msg)
return messages
def test_dispatch_object__logs_to_snowplow():
dispatch.function_that_calls_log_twice()
assert dispatch.messages[0] == "First message I need sent"
assert dispatch.messages[1] == "Second message I need sent"
IN GENERAL, I'd say it's a little sneaky, and if we were all starting over with Python, maybe we'd make this not work this way.
But as it is, that's why it happens, how to get around it, and a use case.
I meant "is None" 😳
@threadreaderapp unroll so I can make some corrections and blogpostify
• • •
Missing some Tweet in this thread? You can try to
force a refresh
I'm seeing a fair amount of agreement on this, and "catching parse errors" has sort of become a thing of mine lately. So lemme try to answer this question in a way that an 8 year old might appreciate.
FIRST: I see these "There's no semicolons in Python" replies
I suspect the kid's ACTUAL example was some Python-specific thing, so Joe switched it for something more programmers would recognize and y'all seized the opportunity to get pedantic. You must be a riot at parties.
SECOND: if you're gonna deliberately miss the point of a lighthearted tweet to well-actually someone about how there's no semicolons in Python, you deserve this:
There are semicolons in Python. You delineate multiple statements on the same line with semicolons.
Currently working on the error productions question in @munificentbob's 'Crafting Interpreters.'
Because I am a fool, I am doing it on the finished interpreter and not on the chapter-incremental one where the question is actually presented.
One thing I am learning is that...
@munificentbob ...error productions are a difficult thing to do in a partial way, particularly if you are replacing a very common error (in this case 'Expect expression,' the base error at the bottom of the Parser tree).
I traded throwing an exception there for returning a new expression type.
@munificentbob 18 tests, not including mine, expect an exception there.
I am resolving this by going to each test, figuring out what parse error it's supposed to be checking for, and adding an error production there, too.
Am I making this too hard? Is there an incremental way to do this?
- I've done countless tech interviews, and some of them I even passed. I work at Mozilla FT.
- I do contracts, mostly mobile or data/ML work. 4 active clients, 2 additional awaiting grant awards.
- I give workshops 10-15x/year
I have needed to know how to use a binary tree countless times in my career. I have needed to know how to implement one twice. Both were FT interviews.
I have needed to use recursion twice in my career. I have needed to demonstrate that I could nine times in interviews.
But it's worth it because ultimately what we're doing, as that tweet explicitly states, is learning to treat thoughtful people we trust differently than we treat Nazis.
Y'all, I hope it's really f**king easy to distinguish people with a humanitarian track record from Nazis.
/2
SO, I want to acknowledge the things that make it harder. And I'm warning you, this is not going to be fun to read.
/3
Last week I tweeted for help deploying updates to a mobile app on the app/play stores. Thank you, folks who RT’d!
No one came forward. I’m taking that to mean even FT mobile devs aren’t confident they know how to do it.
So I figured it out myself. Here’s what I learned.
1/
Before I start, lemme reiterate that I did this alone after asking for help.
So any Android or iOS reply guys out there who are getting ready to make a name for themselves well-actuallying me in the replies can instead read this thread.
Let’s set the scene. You have to deploy an update to an existing mobile app, but every single provisioning profile, keystore, everything you ever generated to upload it the first time is somehow missing or expired.
Your mobile app is the jeep scene from Jurassic World. Congrats.