Setting out to learn Python. Anyone wanna join?

I'd be tempted to use it (or at least refer to it too quickly after getting stuck) if I saw it, I'm weak

edit: you know, this isn't actually all that interesting. Nemmind.

I think I would have had a hell of a lot of trouble, this week, if I hadn't worked a bunch with recursion already.

A lot of it came together very quickly; my merge_sort algorithm, for instance, is just 7 lines long, and it worked the first time I tried. (which doesn't happen often, lemme tell ya!) I implemented a binary search function for the 'intersection' part of the assignment, on the theory that it would probably be faster than using Python's "in" operator, since I knew the lists were sorted. I don't know if that actually mattered, though; I did it because someone said in the forum that his initial 'obvious' implementation ended up being way too slow. I assumed that meant the 'in' operator, so I wrote the binary search.

(for those not taking the course: part of this week's assignment was sorting, merging, and intersecting lists manually, with some functions using recursion, and we weren't allowed to use sets or the sort commands.)

The part I had the most trouble with was the part I expected to be easiest; the 'generate all possible combinations of letters from a given input string' function. I've done that a bunch on my own for the Project Euler puzzles, but I didn't just copy and paste my old code, I tried to follow along with their description, and implement the algorithm their way, but I was getting really strange results. I was ending up with a bunch of extra repeat combinations.... it was generating about twice as many results as it was supposed to.

I finally dropped back to my version, which ended up being nine lines long. I overrode arguments in that function to add a named 'prefix' argument at the end, defaulting to the empty string, like this:

def gen_all_strings(word,prefix=""):

I initialized an empty result list, and first appended the prefix to it. Then, in the base case, I checked if the length of 'word' was one; if so, I appended prefix + word to the list, and returned that. (so the smallest version of the function returns [prefix,prefix+word].)

In the recursive case, I looped through the letters, one at a time, and extended (not appended) my result list with a recursive call to gen_all_strings, moving that letter from word over to prefix. So, if I started with a fresh call as gen_all_strings("abc"), it would first add the empty string (because prefix was ""), then recurse with prefix=a, word=bc, then prefix=b,word=ac, and so on. By extending instead of appending, the returned results from children all got flattened into the parent's list, right up the original caller.

My version of the function, with the added prefix argument, returns exactly what they're looking for, in exactly the order they're expecting, as far as I can see. (they don't actually care about order, but in their visible test cases, this algorithm produces them the way they're expecting.) But I didn't see how to do it without including the extra prefix argument. I'm sure I'm being stupid, but I'm just not seeing how to translate their proposed algorithm into workable code. I think mine's cleaner, anyway, but I wish I could make theirs work.

It'd be nice to see the canonical version of the code after we finished, each week. This is one of those cases where I'd be very interested in their implementation.

So I finally wound up half-finished on last week's Zombie assignment with a score of 55 on the last day before the hard deadline after a busier than expected last week. I implemented the bread-first search function correctly which was the core of the assignment, which I was satisfied with given that I'm now cut off (stupid hard deadlines).

And I decided to buckle down and do the next assignment today. I struggled with it a lot, despite the fact that recursion in principle makes perfect sense to me; it was only in implementation that I started to get bogged down in details and I essentially wrote a bunch of stuff and tested and tested until I had it working. It bothers me that I can't mentally model everything that's happening in a recursive call but I suppose that's a leap of faith that I need to take. It feels a lot like math concepts that didn't make sense to me until I started working with them more. I assume I'll get better/start to develop a more intuitive understanding as I do more with it?

I think my gen_all_strings wound up being pretty close to what they were asking for. Base case was len(word) == 1, which returned ['', word]. The rest was "rest_strings = gen_all_strings(all but the first letter of the word)" (so the requisite recursion), then an outer loop over strings in rest_strings, and an inner loop over the positions in strings evaluated as string[:position] + first letter in the word + string[position:], stored in a list. The return value was a concatenation of rest_strings + that list. (Hope that's pseudocode-y enough.)

It bothers me that I can't mentally model everything that's happening in a recursive call but I suppose that's a leap of faith that I need to take.

Professor Rixner keeps insisting that you shouldn't overthink recursion, but I wonder if that's more a function of limited lecture time, rather than it actually being that difficult. It's really just a logical extension of the rules we already know about for functions.

This is the way I think about them, at least: they're black boxes. You hand them some values, and they hand you back some values, either by mutating what you gave them, or by using return or yield. And functions, unless you manually make it otherwise, live in a completely private world; the only data they have is what you gave them. They can make their own local variables, which can't be seen from outside, and they have their own local state for loop counters and such, and all of it is completely separate from the calling program. When you call into a function, the language you're using sets aside a new chunk of memory to use for local variables; each new function invocation creates a new pointer (or set of pointers) to a unique namespace, just for that single run of just that single function.

As we've seen, this works across functions, too; if you call one function from another (instead of the main program), it has the same 'black box' approach. The only thing the subfunctions know about is what you gave them in the call. They don't even know what called them; they compute a result and return it to something, but they never know who asked for it. They're isolated from each other and from the main program, and that isolation helps keep bugs contained, and makes sure that functions don't accidentally mess each other up. We've been practicing with this for months; with functions A, B, and C, they can call around freely between themselves, and none of them will step on each others' variables or local state. By now, we all know the difference between locals and globals, and that globals are (mostly) bad.

Recursion is just a logical extension of that isolation. When you call function A from function A itself, the new function A gets all new variables, and is completely isolated from the calling function, even though it's the same code running. Then, if it calls itself again, the third invocation of A is separate from the second, and so's the fourth, and the fifth, and so on.

Another angle of comparison is thinking about objects and methods; if you have two separate Zombie objects, the methods you call in each Zombie instance are running the same code, but working on separate data. Recursion is just like that; each new layer of recursion is the same code, but working on new data.

But that burns memory. Each time you call a function, Python has to remember where to return to, and has to create a new namespace for its local variables. A complex recursion case can call itself thousands or even millions of times, burning a TON of memory and runtime.

In general terms, recursion often makes the computer do a lot more work to solve a problem, in exchange for making the problem simple to think about. Iterative algorithms will usually be faster, sometimes a LOT faster. But with many classes of problems, as fast as computers are these days, a simple-but-inefficient runtime is a better solution than a fast-but-complex one. Your time is expensive, computer time is cheap.

In a sense, from a 30,000-foot overview, you can argue that Python itself is an example of that argument; it's a slow language that's easy to write in. Recursion is kind of like that; you can express powerful ideas in just a few lines of code, but it be brutally difficult for the computer to actually run that code.

Malor wrote:

Recursion is just like that; each new layer of recursion is the same code, but working on new data.

Ok that's something I've definitely been tripping over. My brain kept telling me last night: "but, but, I already assigned to that variable!" I was thinking of a snake swallowing its own tail, but I guess what you're saying is the snake is actually having little clone babies, who may or may not squirm off and gum up the equipment?

I was thinking of a snake swallowing its own tail, but I guess what you're saying is the snake is actually having little clone babies, who may or may not squirm off and gum up the equipment?

Hah, what an image!

From that analogy, I guess you could say the whole point of new local variables is to make sure there's no squirming away or gumming up. Each time you call the function, even when you call it from itself, it gets its own little glass aquarium with its own snakes.

From another angle, say you have a utility function, A, and then you have functions B and C that both use it for something. (incredibly common: you've probably done this in most of your projects so far.) If you call A from B, and then call A from C, they're completely separate; all their variables are created fresh. If A has a variable called 'item', and B also has a local variable called 'item', then A can't see B's version, and B can't see A's. And if C also has an 'item' variable, neither A nor B can see it.

Further, B's version of A is separate from C's. The 'item' variable in B->A is not the same as 'item' in C->A. There's an 'item' in B, an 'item' in C, an 'item' in B->A, and an 'item' in C->A, and they're all different. Each function sees only its local 'item' variable. You probably already know this, you just probably haven't thought about it before.

That would happen even if you were somehow multithreaded, and calling into A twice at the same physical time. (which is apparently possible, but very hard to do in Python.) Each A would have its own local memory to work with, and they wouldn't stomp on each other.

It's the exact same thing when A calls A -- each new A is really and truly new. The old A still exists, but just like calling any other function, it's on hold, waiting for the results from A1. The all-new A is able to operate independently, and it may itself go on hold if it creates A2.... but it would also go on hold, in the exact same way, if it called functions named X or Y, and then would resume when they exited. Likewise, A1 is on hold waiting for A2's result. When A2 finishes, A1 resumes running, just like calling any other function. When it finishes, the original A starts running again.

In a very real way, recursion is nothing special. It's just calling a function. The fact that it happens to be the same function is not important to Python. It doesn't care. It sets up new variables like it always does. The only reason you care is because, if a function is calling itself, you'd better have a nice clear exit strategy, or you'll end up in an infinite loop.

That's what the 'base case' is for -- it's so the algorithm knows when to stop!

Well, I just snuck in under the wire on last week's assignment. It wasn't actually that difficult, but I was having a problem with scoring. I just wasn't really grasping the scoring algorithm correctly... what I needed to do was to multiply by SCORES[player] to negate the score for O, so that I could use the same find-the-max-value code, but what I didn't realize for quite awhile was that, when I returned my final score, I needed to multiply by that number a second time, so that the negative numbers ended up being negative again when they were passed upward. So I was having real issues debugging, and then procrastinated, and then got distracted by family business. Just squeaked it in today, my second late assignment.

This week's project, wow. Holy cow that looks difficult. I won't have time to work on it until tomorrow, but I bet it ends up taking most of the weekend.

(for those following along at home: last week's project was writing a recursive Tic Tac Toe player that was perfect, as opposed to the Monte Carlo player we did early in the course. This week's project is writing a solver for the 15 Puzzle.... that puzzle with 15 sliding blocks and a hole, in a 4x4 grid. It looks pretty brutal.)

I actually think I won't make it this time for the TTT player. I was going to work on it tonight when I got home but a client was having a crisis so I won't be home before the hard deadline. I'm still going to do it because I want to learn it but I'm a little disappointed that I won't get an official score. Oh well, I'm having a fun time just slamming my head against the problems.

I'm having a fun time just slamming my head against the problems.

Yeah, they're definitely getting into new territory for me, at this point. This week's project would be way out of my depth on my own, but they've done enough research, analysis, and explanation of the problem that I think I can probably do it. And, of course, all the grunt work they did, writing the puzzle architecture, helps a lot, too.

Gonna be a rough project for a noob, but I'm really looking forward to it. Hope I can figure it out.

One real benefit of going through the course has been to firm up my understanding of OO. I learned (some) programming back in the procedural days. It was enough to muddle along and write medium-sized programs (for the era, at least, maybe a thousand lines or so), but by no stretch of the imagination would anyone have called me an actual programmer.

I'd kind of looked over OO, but for some reason, I was always getting confused between classes and objects. The lightbulb finally went on, for me, two or three years ago, when I saw a disassembled OO program. For whatever reason, seeing the actual assembly generated alongside the source code finally twigged me to what that model was doing, and then the practice from this class has more or less cemented it into place.

This is trivial stuff for actual programmers, of course, but for someone who's spent most of his life writing scripts (albeit very complex ones), it's been a lot of fun.

Don't know if its been posted yet or not but NewBoston's videos are pretty good if you are a straight up beginner. I enjoyed them.

Woohoo, nailed it, 100 points.

It was, indeed, fairly difficult. (For those not in the course, this was writing a computer solver for the Fifteen puzzle.)

It took a real, focused effort, I'd guess probably twelve hours total. Without all the clues they gave us in the homework description, I doubt very much that I'd have finished, at least not before the deadline. What was particularly helpful was them saying "to solve this specific aspect of the problem, get the board into this state, and issue this magic string." If they hadn't provided those, and I hadn't been able to look them up somewhere, I doubt I'd have figured it out.

I lost some time early on because I didn't realize you were supposed to both update your puzzle and return the string you used. I'd structured my routines to just update the puzzle directly. After thinking about it, I tore them apart and rewrote them to accumulate a string of moves that needed to happen, but not to actually do any of them, or depend on them having been done. Rather, each function executed the string at the very end, in just one spot. It seemed cleaner that way.

So, overall, in the entire course, the only points I lost were 15 from the mathy homework in Week 2. I would have lost more in later weeks if I hadn't resorted to just outright Googling many of their questions. Like, the one where they wanted you to work out the formula for a factorial triangle was ridiculous -- mathematicians are famous for having figured that out! And I'm supposed to be working it out on my own? In a course for people with eight weeks of Python??

Oddly, later weeks, despite dealing with more advanced concepts, were frequently easier, because they switched to *recognizing* formulas, rather than having to *write* them. That I can usually handle. And, at this level, you don't need math that badly yet... it's mostly about understanding the various O levels for algorithms.

I imagine the next course is probably going to be beyond my skills, but I'll give it a shot.

edit: wow, in looking at the Coursera forums, they're not very busy. They must have lost a huge number of people.

This thread slowed way the heck down, too.

I don't think I saw this thread earlier. Just started the CodeAcademy class out of curiosity. I've done Python professionally before and I'm currently dusting off my skills for a project.

I finished last week's project, finally. My biggest problem actually wasn't so much with the recursion, I'm actually starting to feel sort of comfortable with that concept -- I just couldn't get my scores passed back up the tree correctly in a way that I could take the min or max. Once I simplified it significantly everything suddenly started working.

This week's project I plan on taking my time with, not worrying too much about the deadline since I'm already pythoned out for the week. I definitely plan on taking the next course, though I have a feeling that I'll have to devote significantly more time to it than for this one. Just 'whenever I have time on the weekend' is probably not going to cut it judging from the way they describe it, the last few weeks have been hard to fit everything in and I've felt like I've been scrambling.

I'm just really glad I discovered it as I had self-taught to the point that I was wondering where to go next to improve my programming skills. I know the bare fundamentals of things like C and assembly from reading (but not applying) computer books in the past, but I really wanted to improve my actual programming skills in something harmless like Python before I started adding that layer of complexity (I'd actually rather learn Java next). This class was the exact thing I needed and the deadlines helped keep me (relatively) focused.

Does anyone know how much longer you'll have access to the course materials after the end of the official class?

Malor wrote:

edit: wow, in looking at the Coursera forums, they're not very busy. They must have lost a huge number of people.

Yeah I checked them trying to find help with the practice activity (Nim minimax) and there very few posts from the past few weeks and almost none about the activity.

Yeah, I'll take the next one, too, but I'm worried about their math focus. I'm not at all sure I'll be able to pass with the skills I presently have, even though I can probably write the code they require.

I'm aware that this lack is a barrier to being a 'computer scientist', by their definition, but I'm really just trying to sharpen up my programming skills.

Hey everyone. How's things?! I know I've been sparse around here. Have had a lot of stuff that I've been working on outside of this, and as I mentioned before, I momentarily took a sidestep into more webdev-related stuff.

That being said, I was reading The Pragmatic Programmer recently and had an awesome idea. What if there was a big huge project we could work on not just to learn programming but to learn to program as part of a team? Don't know? Well then I'll tell you--it would be f*ckin sweet.

I hope this isn't against the TOS, but instead of giving you paragraphs and paragraphs of detail here, I'd like to direct you to my post on /r/learnprogramming. (GWJ team: if this isn't ok, let me know and I'll post here instead.)

I'd love it if you guys checked out my idea, let me know your thoughts, and especially let me know if you'd like to be a part of it. I feel like the learners here (myself included) are probably by this point in a position where they could contribute.

Thanks again. Really looking forward to hearing feedback on this.

Hello fellow learners! Long time no see. How is everything going for you? KingOctavious with ArmoredSquid, all the others with the Coursera specialization? How did that turn out, anyone take the third course as well?

I took a bit of an unwilling break from programming over the summer, but now I'm back with a study spree on edX. I started with MIT 6.00.1x, thinking I'd churn through it in preparation for 6.00.2x. I assumed it would be a walk in the park but it turns out it's a more rigorous intro to CS than expected, so I'm taking it slow and ditching 6.00.2x, which seems too data/math-centric for my taste. I also took a look at Harvard CS50x, which looks awesome but has a higher threshold than I'd like right now, with its focus on Linux and C.

Maybe most interesting is MIT 11.126x, "Introduction to Game Design". While not a programming course per se it does involve some digital game making and look promising. It just opened its first run yesterday, come join in! So far it's only introductory materials so it's not too late.

How did that turn out, anyone take the third course as well?

I took it briefly, and dropped it: it's very heavy math, and I just don't have the background to deal with it. I wouldn't mind learning, but it was much too advanced for where I was starting.

I had fun with courses 1 and 2, though.

zip(*[iter(x)])
Brain puzzler for you duders.

boogle wrote:

zip(*[iter(x)])
Brain puzzler for you duders.

This was considered too beautiful to live, and I had to comment/refactor it:

def get_unique_values(dicts: [{}], keys: [str]): return list(set(vs)) for vs in zip(*[tuple(d.get(k) for k in keys) for d in dicts])

Commented to explain:

Spoiler:
def get_unique_values(dicts: [{}], keys: [str]): """ Given a list of dicts with common keys, and a list of keys, yields lists of unique values for those keys found across all dicts. :param dicts: List of dicts with same keys :param keys: Keys to extract to lists of unique values :return: A list of unique values from the dicts, per key, in order keys were given """ assert isinstance(dicts, collections.Iterable) assert isinstance(keys, collections.Sized) assert len(keys) > 0 value_tuples = [] # Get a list of tuples containing (in order) the value for each key for each dict in the list # Example: Looking for keys ["a", "b", "c"] # [{"a": 1, "b": 2, "c": 3, "d": 4}, {"a": 1, "b": 5, "c": 3, "d": 6}] becomes [(1, 2, 3), (1, 5, 3)] for d in dicts: value_tuples.append(tuple(d.get(key) for key in keys)) results = [] # Split tuples up into separate lists by unzipping them with '*' # Example: [(1, 2, 3), (1, 5, 3)] becomes [(1, 1), (2, 5), (3, 3)] for values_for_key in zip(*value_tuples): # Convert to sets to only get unique values, then convert those sets to lists # Example: [(1, 1), (2, 5), (3, 3)] becomes [[1], [2, 5], [3]] results.append(list(set(values_for_key))) # Should now have a list of lists that can be unpacked by assigning to a tuple. # Example: returning [[1], [2, 5], [3]] # a, b, c = [[1], [2, 5], [3]] # a == [1] # b == [2, 5] # c == [3] # Need to be cautious when only requesting one key, as you'll match the outer list if you don't use a trailing comma # Examples: # BAD: a = [[1]] # a is a list of lists ([[1]]) # GOOD: a, = [[1]] # a is the inner list of ints ([1]) return results

Do not understand the relation...

boogle wrote:

Do not understand the relation...

We're not stumping nubs? It's like I don't even know you anymore.

Save the nub stumping for your next slap 'n tickle, you guys.

Still yet to hear a good reason why the adjectival form of Python is pythonic and not pythonesque.

il dottore wrote:

Hello fellow learners! Long time no see. How is everything going for you? KingOctavious with ArmoredSquid, all the others with the Coursera specialization? How did that turn out, anyone take the third course as well?

I took a bit of an unwilling break from programming over the summer, but now I'm back with a study spree on edX. I started with MIT 6.00.1x, thinking I'd churn through it in preparation for 6.00.2x. I assumed it would be a walk in the park but it turns out it's a more rigorous intro to CS than expected, so I'm taking it slow and ditching 6.00.2x, which seems too data/math-centric for my taste. I also took a look at Harvard CS50x, which looks awesome but has a higher threshold than I'd like right now, with its focus on Linux and C.

Maybe most interesting is MIT 11.126x, "Introduction to Game Design". While not a programming course per se it does involve some digital game making and look promising. It just opened its first run yesterday, come join in! So far it's only introductory materials so it's not too late.

Hey Dottore!

Unfortunately, Armored Squid appears to be dead. We got everything set up, but the project was never able to move into the "actually start writing code" stage. Not sure where it fell apart. Tried a few pushes to get everything going, but it sorta just stopped.

Oh well, was worth a shot. Right now I'm working on a few things, including a browser-based game and just generally learning about programming and webdev. Of these latter two, the focus is currently on web stuff. Though I know all the basics of web development, I started digging into Harvard's CS75 courses, and they are incredibly informative. Highly recommend to anyone else interested in becoming fully versed in this kind of stuff.

This came up in /r/python today: JetBrains has released a new, free variant of PyCharm (a pretty solid IDE if you're into IDEs) that helps the user to learn Python: http://blog.jetbrains.com/pycharm/20...

Seems pretty neat. Might be useful to the folks in this thread.

Michael wrote:

This came up in /r/python today: JetBrains has released a new, free variant of PyCharm (a pretty solid IDE if you're into IDEs) that helps the user to learn Python: http://blog.jetbrains.com/pycharm/20...

Seems pretty neat. Might be useful to the folks in this thread.

Awesome, I'll check it out. Thanks!

NaNoGenMo 2014 is starting today.

I mentioned this in the programming thread, but I thought it might be worth mentioning here to, since a lot of the people participating are using Python. If you want a project to practice on, or you just want to see some other people struggling with Python code, its a good opportunity.

Gremlin wrote:

NaNoGenMo 2014 is starting today.

I mentioned this in the programming thread, but I thought it might be worth mentioning here to, since a lot of the people participating are using Python. If you want a project to practice on, or you just want to see some other people struggling with Python code, its a good opportunity.

That is... A super intriguing idea.

This thread has been pretty quiet lately. I discovered something recently that has rekindled my learning of Python. www.CodeCombat.com. They created a series of a couple-hundred python mini-tutorials and turned each into a game of Kingdom Rush art-style where you guide your hero around with code and accomplish various objectives. It starts very slow, so its a bit of a grind if you have a lot of coding knowledge already, but there's xp to earn, gems to earn, and new items to buy that unlock additional coding powers.

The missions challenge you in a variety of ways:

An example of a level I'm doing now is a daily challenge, where you have a small forest map divided into 3 areas. There are coins all over and your objective is to collect 100 moneys worth of coins before time runs out or you die. Each of the 3 areas spawns a different type of enemy and you must visit at least 2 of the regions (the coins run out of one before you'll have 100)

I have glasses that lets me build arrays of items and enemies and tell their distances from me, a spellbook that gives me arrays and iterators like For and While, a watch that lets me know how many seconds have passed since the match started, so I can alter my strategy based on how much time is left.

So there's the RPG element: Equipping my hero with one kind of sword lets me slowly dish out huge spikes of damage, which is perfect for the ogres who spawn in the top right, but terrible against the horde that will spawn in the bottom right region
Strategy: Should I go for that gold coin that's 15 steps away or the two silver ones that are 10 steps away? What if those two are in opposite directions?
Efficiency: In this case, there's no bonus for fewer lines of code (not that that's the only measure of efficiency), but many levels do have that.
Tactics: If I want to, I can play with a real time element, where I can place target flags while the map is running and my hero will respond, based on how I've coded that. So I could rely on decent code for what to do when I've placed different colored flags and be super johnny-on-the-spot with placing flags when its go time. (I choose not to do this most of the time)

If I win this map with my solution, it will increment the difficulty and I can try again. If my solution fails, I have to wait till tomorrow to try again (officially).

Its free. There is a $9.99 subscription option that I consider a donation for good work, but also gives you a bunch of different heroes, a bunch of gems, and unlocks a slew of community generated levels/challenges.

You can play in Python, in JavaScript, and there are a handful of others I've never heard of too. (And it's down right now, which is the only reason I'm here writing instead of trying to write code that will pass the 2nd difficulty level of the mission above.