We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Teeing up Python: Code Golf

00:00

Formal Metadata

Title
Teeing up Python: Code Golf
Title of Series
Number of Parts
160
Author
License
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
95
Thumbnail
1:04:08
102
119
Thumbnail
1:00:51
CodeComa BerenicesSoftwareSystem programmingBuildingBlock (periodic table)Intrusion detection systemImplementationExecution unitLink (knot theory)Active contour modelWindowOperator (mathematics)Variable (mathematics)Ultraviolet photoelectron spectroscopyComplex (psychology)Address spaceDefault (computer science)Letterpress printingContext awarenessException handlingCodeBitData managementInformationSoftware frameworkMultiplication signSet (mathematics)Exception handlingContext awarenessBlock (periodic table)Field (computer science)Line (geometry)Closed setFerry CorstenStatement (computer science)View (database)Socket-SchnittstelleInitial value problemEquals signMobile WebMemory managementSingle-precision floating-point formatCurvatureOperator (mathematics)AnalogyCountingFormal language1 (number)Default (computer science)CuboidAddress spaceDrop (liquid)Local ringMoment (mathematics)InternetworkingPresentation of a groupExecution unitComplex (psychology)Data structureStructural loadSemiconductor memoryCASE <Informatik>Computer fileVariable (mathematics)ImplementationSystem callMultilaterationLogicLoop (music)Physical systemBuildingActive contour modelResultantHypothesisTerm (mathematics)Right angleProfil (magazine)NumberType theoryObject (grammar)SoftwareMobile appExpressionFlow separationWordEaster egg <Programm>Lecture/Conference
Letterpress printingImplementationContext awarenessBoilerplate (text)SpacetimeData managementBitOvalOpen setRight angleClosed setFerry CorstenBlock (periodic table)Functional (mathematics)Context awarenessMixed realityEmailQuicksortStatement (computer science)Game controllerCodeBoilerplate (text)Letterpress printingLine (geometry)Computer animation
Context awarenessLetterpress printingFunction (mathematics)Digital filterReduction of orderTotal S.A.ResultantIterationDoubling the cubeElectronic mailing listNumberRevision controlFunctional (mathematics)Level (video gaming)Power (physics)Type theoryObject (grammar)Functional programmingOrder (biology)ProgrammschleifeBlock (periodic table)Element (mathematics)MereologyStatisticsTerm (mathematics)Function (mathematics)Process (computing)Error messageNeuroinformatikoutputBitOvalQuicksortReduction of orderCASE <Informatik>Single-precision floating-point formatMultiplication signTransformation (genetics)Boolean algebraCodeSlide ruleCuboidAutomatic differentiationLambda calculusSpacetimeVideo gameComputer clusterCore dumpMoment (mathematics)Form (programming)ImplementationSummierbarkeitInterior (topology)TwitterMaizeFitness functionTotal S.A.EmailComputer animation
Digital filterElectronic mailing listCondition numberSinguläres IntegralTexture mappingReduction of orderFunction (mathematics)Range (statistics)Ultraviolet photoelectron spectroscopyNumberCase moddingString (computer science)BitResultantSummierbarkeitElectronic mailing listTouchscreenLambda calculusTransformation (genetics)QuicksortPattern languageInformationVisualization (computer graphics)Condition numberFunctional (mathematics)MappingFunctional programmingKey (cryptography)Element (mathematics)IntegerReduction of orderLevel (video gaming)Type theoryControl flowFormal languageReading (process)Fitness functionRevision controlTotal S.A.Filter <Stochastik>Poisson-KlammerCodePositional notationAtomic numberBit rateStatement (computer science)Slide ruleOnline helpCASE <Informatik>Presentation of a groupNumeral (linguistics)Subject indexingOpen setLoop (music)Shared memoryNormal (geometry)Software testingCovering spaceEndliche ModelltheorieVariable (mathematics)Cellular automatonData structureCuboidRight angleMultiplication signComputer animation
Slide ruleTouchscreenCoding theoryReduction of orderCodeUltraviolet photoelectron spectroscopyOperations researchLibrary (computing)Presentation of a groupPoint (geometry)WhiteboardCodeMultiplication signInstance (computer science)Medical imagingFood energyStructural loadFilm editingMereologyLengthError messageProduct (business)Pascal, BlaiseLibrary (computing)CASE <Informatik>Different (Kate Ryan album)Operator (mathematics)TouchscreenPresentation of a groupSummierbarkeitMachine codeXMLProgram flowchartComputer animation
BitTwitterHypermediaBlogFacebookLink (knot theory)Lecture/ConferenceComputer animation
Chemical equationQuicksortCodeMechanism designVideo gameFilm editingMeeting/Interview
CodeMultiplication signSoftwareElectronic mailing listLecture/Conference
Slide ruleQuicksort19 (number)CASE <Informatik>Electronic mailing listLecture/Conference
Element (mathematics)WaveFunctional programmingQuicksortIntegrated development environmentDebuggerMultiplication signLecture/Conference
Transcript: English(auto-generated)
All right, great, thanks for coming, and I hope you all can hear me. Luckily, we've got this wonderful mic. My name's Lee Sheng. I'll be talking about code golfing with Python. So, a little bit about the company I work for. It's Yelp. We connect people with great local businesses.
So we have an app and a mobile website to help you find interesting local businesses to work with. And a little bit about myself is I'm an engineer at Yelp building distributed systems primarily with Kafka. And previously, I've been at Amazon, a startup called WeBeData and Dropbox. And I intern at Starfleet a little bit as a data scientist. You'll get the pun in a moment if you think about it.
So a few caveats. I'm not actually a golf player, so my analogies may fall a little bit flat. I'm not talking about traditional code golfing in the way of maximizing every single character that you use to produce a particular result. I find that that tends to generate unreadable code. The way that I'm going to try to express code golfing
is a way that generates more readable code while being more concise. And finally, because we're talking about code, I use a lot of modest-face type. So if that hurts your eyes, I'm sorry. That's just kind of what we're dealing with in this presentation. So for me, I'm defining code golfing as minimizing the number of strokes in each block of code. And I'll define what a stroke
in terms of what I'm saying is later. And my thesis is that concise code requires less cognitive load to understand because we spend a lot more time reading code than we actually do writing it. And so spending a little bit of time to be more concise enables the people that look at the code later to, and especially yourselves, when you look at your own code,
to understand what it is. And I find that a great exercise when you're looking at concise code is to say, can I read this out loud using English or whatever my native language is, very simply. And finally, to quote William Shakespeare, like, brevity is the soul of wit, to kind of continue along the lines of,
shorter things is better. And I sound a bit like a snake oil salesman. And what I'm trying to say is, when you shorten your code, you'll increase your clarity. And to, of course, because this is snake oil, I've harmed no pythons in the making of this talk. So what are strokes?
I kind of define them as plus one for any keywords, variable names, and operators. So I want to promote the idea of using longer variable names rather than single character ones, and to be more expressive using the language. And then I don't count white space, dots, commas, parentheses, quotes, colons, and I'll give more examples of this visually later.
But I just want to kind of explain where I'm coming from. And these, I believe, are all the kind of like, structural things that kind of separate out the individual blocks of information. So kind of ultimately what we're talking about is counting the units of information present in a particular block of code. So why even bother doing something like this?
Python has this wonderful Easter egg called import this, and it will tell you about the philosophy of Python. So I've selected a few lines here that I thought are particularly relevant to this topic. Beautiful is better than ugly, simple is better than complex, and if the implementation is easy to explain, it may be a good idea.
So if you're all seeing code like this, it's kind of a little thing where you pull out the address field from this my contact dict, you set an unknown as your default, and then that way, if it actually exists in there, you can replace the unknown with a particular thing. That took me a long time to explain what this actually does. So Python has this wonderful feature
where you can just say, I want to get this attribute out of a dict and pass it a default value if it's not there. So this is way shorter. I can describe exactly what it is in like, eight words. And to go back to my strokes metaphor, I can count them all up. So two male is a variable, is one. My equal sign is an operator, that's the second one. If you work that out, that's about 12 strokes.
And then my kind of get using a default thing is only six strokes at the end of the day. So that like, numerically, I can think about exactly how much I'm making my code shorter and have a framework for doing this. So for the visual learners to kind of like, see where this information is actually going, the final line is kind of really where
the nuts and bolts is going on. Like, I have two male, I'm setting it to the address field of the dict of my contact. This if statement is kind of extraneous. Like, that actually just goes away entirely, and the default in that first line, that unknown, like, that's what gets pulled into the final result. So visually, this kind of shows like,
where those lines are going away, or those keywords. And so along the lines of a simple get, like, we can also just initialize a dict in the same way. Like, we've kind of seen code like this, this little block of code takes this item in this count variable, which I'm trying to, in this count dict, and kind of every time
you run into a particular item, you want to increment the count by one, and so you have to initialize it by zero if you haven't seen it before. So you might wrap this little block of code inside of a loop or something like that. And this is also similarly like, a giant block of code, hard to describe. Python has this collection called a default dict, which lets you set your initial value for a dictionary.
You import this default dict, and then you can just, you tell it what you want the default value to be. In this particular case, I want it to be an int, which defaults to zero. But you can give it a more complex object if that's what you need in your particular use case. And then you can just use the object as though it were automatically initialized with the thing that you want.
So I can just start incrementing it by one whenever I encounter an item. So this is much, much shorter. And you see, like, I'm moving from 18 strokes down to 13, and that's including this import at the top, which you probably only see once per file. So if you do this multiple times, it actually saves you a lot of work. So another thing I want to talk about is cleaning up resources.
So a lot of times we'll open up network sockets, we'll open files, we'll be doing a lot of things with resources, and when we open, in this particular case, we're opening files, reading them out, line by line, printing them out, and then finally we have to close it at the end. Why even bother closing this up? Like Python has a memory manager that deals with the variables and stuff
in memory that we allocate, closes them up when they fall out of scope. Why shouldn't we do this with resources? Well, it turns out that we actually can. Python has this feature called a context manager that lets you kind of define the particular thing that you want to do using this with keyword, set it to the variable, and once it exits that block,
Python will close the thing automatically. So this saves you one stroke, but at the end of the day, if you look, that close statement is really the only thing that you're saving. And I've got a roommate here because that's the automatic cleanup tool. Now, that didn't seem like it saved you that much, but I think where it really starts to come into play is when you have to deal with exceptions.
So in this kind of contrived example, I'm opening up my end file and I'm raising exception just to do some stuff, and I have to wrap it in a try-finally block to make sure that my file gets closed. With the context manager, it just happens automatically. Like, it knows how to catch the exception,
run the closing portion of the piece of code, and then re-raise the exception so that something upstream can actually handle it. So I don't have to do anything else. It's already handled automatically, and this is much more natural because this is how I'm thinking about the code and the business logic that I'm trying to run. So to do one of these context managers, so simple, right?
Like, you've got this wonderful arcane block of code. You implement these double underscore enter and the double underscore exit methods. And so this particular example I took off of the Python example where you kind of poorly add an HTML tag to a print statement. So in this sort of thing, we've got the enter method,
which prints out the opening tag with the name that you pass into this thing. And then on the exit, when you exit the block, it prints out the closing tag so you can print out a bunch of stuff in the middle and it'll be wrapped in these HTML tags. This is a lot of boilerplate, right? I think we can do a little bit better. Python has this built-in decorator called a context manager
with the idea that a lot of these things follow the path of a function execution. You run a few lines of code in the beginning, you give control back to the thing that's within the block that you want to run, and then you'd run some stuff afterwards. So in this particular example, if I decorate this method called tag
with a context manager, I can print out the header tag. I yield control back to the main function or the block that I'm running this from, and then print out my closing tag. So this is way, way shorter, and I think way easier to understand compared to this enter exit thing that I had before. And then this even gives me enough space
to print out an example at the end that shows how this can be used. I have my H1 header tag with the foo stuff printed out, and when I run this, the result will be that it prints out foo wrapped in those tags. That's really great. So next I want to talk a little bit about functions. So functions, I'm sure we've all heard of them, they aren't really that scary.
What they do is they take something as input, and then they do some processing on it, and then they produce some output. So in this particular example, I want to say that I have this cook function, I'm taking in some corn, and then when I run the cook function on it, I can produce popcorn. This particular contrived example doesn't do any of the error checking
to make sure that I actually passed in corn to produce the result, but it kind of shows this input and output sort of thing. Python has this feature called a lambda, which is another way of defining a function without giving it a name, and this will come into play in a little bit when I talk about some of the other functional programming aspects,
but it's an important concept to understand. So in this particular case, I've got lambda food, which is the thing that's being passed in, and the result is this popcorn. So it's equivalent to the function above, except I don't give it a name, but it's an object that Python can deal with, and you can pass this around just like anything else, like any other variable that's set to an int
or something like that. So this can be a very powerful concept to utilize with functions that act on other functions. So when people talk about functional programming, they're talking about three major methods, which I'm gonna go through real quick. We have the map, filter, and reduce. So the first one is map, which takes one of those functions like the cook one that I mentioned before,
as well as a list of items. So you take map, you run the list of items, and you have the function, and what map returns is a list of items where that function has been run on every single element of that list. So as in this particular example, if I run map with a list of corn, a cow, and an egg,
with the cook function, I'm returning the output with cook run on all of them, so the result is a list of popcorn, a hamburger, and a fried egg. Pretty simple, right? So the next kind of functional programming thing that there is is called filter, and what this does is it also takes a list of items,
and it takes a function that returns a Boolean, and it returns a list of items for which that Boolean evaluates to true. So in this particular case, I've got the list of popcorn, hamburger, and fried egg before, and the isVegetarian function, and then my output list is a popcorn and a fried egg. Assuming that you think that eggs are vegetarian,
that's a matter for debate and outside of the scope of this talk. And finally, we have the reduce function, which takes a list of items again, and it takes a aggregator function, which is a function that takes in two inputs and produces one output. So in this particular case,
we have popcorn and a fried egg as the list for reduce. You pass it to eat function, and the result is, of course, poop. And I'm not really not that clever. I stole this tweet from someone else, but I thought it was a good way to kind of describe the three main functions of functional programming. So that seemed a little academic. Let's get into some examples, and I find that examples are very well done
with Gufus and Galant, which are part of my childhood in terms of kind of describing a good kid and a bad kid and how they interact with the world. Gufus is the bad kid that does poor, reckless things, and in this example, he runs around with scissors pointed up so that when he trips and falls, he stabs one of his eyes out. And Galant is the good kid
who walks around very carefully with scissors pointed down so that when he falls, he doesn't hurt himself too badly. So Gufus and Galant explore functions. Gufus thinks very iteratively. He focuses on how to compute the result, thinks about the computations that he's trying to make, and ultimately, he loops over data to do the things that he's trying to do.
Galant, on the other hand, thinks functionally about the end result that he's trying to produce, and he focuses on what the result is. And so using kind of this mathematical function-oriented thing, he composes the functions in order to produce the result that he's looking for. So let's talk about how they can use map.
Gufus, in this example, is trying to compute, given this nums array, to compute a new list that has a double version of all of these numbers. And so what happens is Gufus iterates over this array and has this result called double nums and appends number times two to every single,
when you encounter every single number. This is pretty straightforward, reasonable block of code. It's actually very clear, I would say. Now with functional programming, what you can do is you have this map function, and you want to pass it into lambda, which takes this, what did I even type here? Okay, that's a typo on the slide. It should be X, and I don't know why
this got turned into Xbox. But imagine that there is an X there. Maybe I was playing video games or something while making this slide. So I'm passing it a function with lambda of X, which is that thing that we saw before. And this lambda transforms X to X times two,
and I pass it in the same numbers thing. I run the map function, which will produce the double of the results, and I have to tell Python that I want a list at the end, and that's an implementation detail that I might not go into. So this is a little bit shorter, fits on one line, possibly a little bit clearer if you're starting to think in that sort of functional transformational form.
And now we've got reduce. So we've got this, let's say I want to compute the total sum of all of the numbers in the list. I have my total equals zero. I'm iterating continuously over the list, or at least Goofus does, and then kind of adds this thing to the total.
And this takes 10 strokes as well. So Gallant has this accumulator function, which is this lambda X comma Y, taking in two variables, and then the result is X plus Y. And then he continues to run this over the nums thing. He runs reduce, and he gets the total in the same sort of way. So this is also 10 strokes. It's about the same thing, but it's kind of shorter, compact, fits on one line,
which is great, because I have a wide screen monitor, and this is a wide screen. And finally, filters. Goofus iterates over the numbers. He runs this for loop again. We've got this result accumulator thing, which is a list, and we say, if this number mod two equals zero, we append this to the result, 16 strokes.
Gallant can just run this filter method using a lambda that says that, do lambda X mod two equals zero, which is that same little if statement, returns true when it's even, runs it over the nums list, and then runs the filter thing over it, and that produces that same over only even thing with 12 strokes. So that's quite a bit shorter.
So this is, I think, a distinct advantage here for functional programming. Yay. But wait, there's more. So now that functional programming seemed a little bit arcane in some ways, I would say. Took a little bit to introduce and a little bit to explain. Python has this concept called a comprehension, which can be used in a lot of these cases,
and it's a much more natural way of constructing these lists, and Dix as well. So we have this kind of result. We've seen this pattern in many of the examples that I was just talking about before. We have this kind of results list that we're trying to produce. We want to iterate over everything in a collection of things. We run a condition on it,
and then we kind of append some sort of transformation on this particular thing. This is kind of the basic pattern that the previous three examples that I was talking about was doing. And this is kind of 14 strokes at the end of the day. Now, not all of the examples use all of these features, but they're all kind of there. So list comprehension is a way to define a list using this kind of bracket notation,
which is what we say with the list. And we say, I want to do this transformation on the item for all the items in the thing if this condition is true. That was very natural for me to read out loud, right? Result is the list of the transformed item for the item in things if the condition is true on that thing. Very, very clean and easy to articulate.
Whereas the previous one, if I were to try to describe it, it's a little bit harder. I couldn't quite do it on stage. And this is actually a little bit shorter, right? This is 12 strokes rather than 14. So back to that like visual sort of thing that I think is kind of shows you where this information is going is we still are setting this result list, and we're kind of creating a list at the end.
We want to have this four item in things that kind of moves to the middle. We still have that if statement, which is the filter thing, and that goes to the end. And then this transformation moves towards the beginning. So this is like, we're moving this result out of pen thing in our list sort of thing. And this is where those like two strokes go to. So let's kind of go through those functional examples again,
and like let's see if we can do this with a list comprehension. So before when I was talking about producing the doubled version of every element in a particular list, we've got this map of Lambda with, and this one actually has the right thing without the Xbox. This takes 10 strokes. Now with Billy Mays's list comprehension,
we just say double nums is the list of X times two for every X in nums. Very simple to articulate in plain language. And this is super easy to understand, right? Filtering works in much the same way. Galant has this thing where I'm going to filter
for only even numbers within this list of nums. 12 strokes. And Billy Mays uses the comprehension. We have only evens X for X in nums if X mod two is equal to zero. Now this is actually a little bit longer. So my metaphor kind of breaks down a little bit, but like which one is easier to understand?
I would say the second one is much easier to understand. So don't listen to everything that I say, but think about what you're trying to do and what your goals are. And better reduces. We've got this total accumulator and we have this like Lambda X and we have mod this to do. But then think about it like all of these functions,
when I'm saying a list comprehension, my result is a list. This total thing is really just producing a single number. And the Shamwell guy who's the Billy Mays's chief competitor realizes that there is in fact just a sum function in Python. And you can just call that on a list and it will produce the result that you want to do. So why not use that instead because it really just does the thing that you want.
So think about these built-ins. And I cheesed a little bit about with Dix and Dix comprehensions work in the same way that list comprehensions do. So instead of doing X for X whatever, whatever, you do for X and Y, the two like the key and the value for the particular list.
So here's a new example of Goofus trying to create a mapping of integer values from zero to 26 with the letters that they correspond to. So this has, you know, character 97 is the ASCII value for A, so I add zero to A and I'll get that like A value. So my result will be a dict with zero to A,
one to B and so on and so forth all the way up to 25 to Z. And this is 17 strokes. So when I use the dict comprehension, I have nums to letters which is the same variable and I have X which is the numeric index that I have and then the char 97 plus X function which turns that number into a particular string.
And basically this works in the same sort of way that the list comprehension does. You can use the if filter as well. So if you understand list comprehensions, you can do this with a dict as well. And this is 14 strokes, so it's much shorter and I like it. So where can conciseness help? I would say they're helpful in presentations like this. The more code that I can fit onto a slide,
the easier it is for it to read and with wide screen monitors, like you can fit a lot more. And also on the screen when I'm actually coding, like I can type a lot more, I can see a lot and get a better picture for the code that I'm interacting with at any given point in time. And finally, like if you're ever interviewing, I think that on a whiteboard, being able to write code very concisely
will give you a lot more ability to fit more code on your whiteboard. As an example, quick whiteboarding tip. If you start coding in the middle of a whiteboard, like kind of like naturally your eyes are drawn there, you're essentially dealing with like in this, like with this font size, a 26 by six screen. If you're coding on a screen,
you would start at the upper left. So why don't you do that with a whiteboard? You start from there and your screen is way, way bigger. So that lets you do a lot more. I'm sure that we've all encountered that instance where we've been coding on a whiteboard and then we're trying to juggle around and we run into the edge and we draw all kinds of arrows, really convoluted and hard to follow. So start at the top left on a whiteboard, the same way that you start on a piece of paper on a piece of code.
So final takeaways. I'd say that stroke reduction, which is making code more concise, reduces the cognitive load to understand code. We read code a lot more than we write it and therefore like the less we have to, the less energy we have to spend to understand the code that we've written, the better we are and like better able to understand
like kind of the broader picture of how things are. And Python has a lot of great features for enabling us to do more with less and I think this is a big part of learning and discovering all the different techniques and kind of mastering the art of Python. And finally with the sum operation that I talked about, for a lot of common things, if you think that this should be really, really obvious,
there actually is probably a built-in or a library. So you should search and try to find what that is because it will do exactly what you would expect it to do and hopefully cover a lot of those edge cases that you don't want to deal with. So let somebody else have dealt with them first and like not have to worry about them later. So finally a quote by Blaise Pascal.
I apologize for the length of this presentation but I didn't have enough time to make it any shorter. And a little bit about Yelp. We're hiring, so come see us at our booth. And here's our wonderful social media links. We've got a Facebook thing with our engineering stuff. We've got Twitter where we advertise our engineering blog where we talk about
a lot of the cool stuff that we do with Python as well as other things. And we've got GitHub which of course is a social network these days. And that's the end of my talk. Okay we have five minutes so I could take some questions.
If someone has a question please raise your hand. No, ah there are two. So sometimes it's nice to observe a mechanism
for making some code shorter and more concise. And you're really impressed with it. And you show somebody and they say I don't understand that, it's not clear. I preferred it the long way because it's easy for my mind to read and comprehend. You sort of want to keep it because you're so proud of it but you sort of sometimes have to let go.
Do you have anything to say about that? I think it's always a delicate balancing act between clarity and conciseness. It's definitely something that I encounter especially when I'm reviewing code written by other people. If it takes me longer to think about it, it's something, like for example the first time that I saw this comprehension I was actually like this is really complicated,
this is really confusing and this is very arcane. But as I kind of grew and learned about it and I asked those questions, I'm like oh this is actually more clear as a particular thing and I've kind of promoted on the teams that I'm on, this is a much more concise way of doing this and because it's such a common thing to do. For less common things like producing lists
or I don't know, I struggle to think of a less common, like if you were trying to open up a network soccer or something where there's a lot more non-straightforward kinds of things, the explicitness and explaining exactly what you want to do, comments are kind of like the best way of getting around it. And I think it's really about understanding what the team that you're working on is comfortable with and which kind of conciseness techniques
are best adopted there. Does that kind of make sense? Thank you very much for your talk. I really like the golf metaphor. Do you know what the 19th hole stands for? Hole 19? Not so much, what's that? It's the place where we get food so it's doubly perfect that you have to
stall right before lunch. Ah, see I should have thought about that when I was creating these slides but I didn't know what my slot was right before lunch. So everybody off to the 19th hole, right? Okay, any more questions? Oh, yeah. Great, thanks.
So one of the downsides of doing these sorts of things is that sometimes they make debugging harder because there are cases where you want to actually have the array which doesn't actually materialize when you do all these list comprehensions. So do you have any recommendations on how to deal with that? Not offhand, I think sometimes if I'm debugging it's
yeah, I think the thing that I kind of wave my hands around in the functional programming example where they produce this, where you have to wrap it in a list, it actually produces a generator which lets you produce the individual items in that particular thing. So if you're kind of like iterating over that
you can produce the element, look at each element within there and kind of use that as a debugging tool. When you generate these comprehensions or something like that straight off the bat, sometimes it's worth just kind of outputting them or inspecting them in a debugger. Sorry if that doesn't quite answer your question. Debugging is a harder sort of concept that really depends on the environment
and other stuff that you're doing. So maybe go to some of the PyCharm talks and I'm sure they'll give you some better advice on that. All right, one last one? Anyone? Nope, well then give him a hand.