Category: Python


Here’s a couple of quotes I gathered from a simple stroll around stackoverflow:

– Academic world: “Encapsulation ensures the safety of your code”
– CS world: “Encapsulation is a neat pattern to avoid bugs and ease readability.”
– Production world: “You’re not trying to add security by encapsulation, ARE YOU?”
– Python world: “We are all adults. Feel free to shoot yourself in the foot if you must.”

You see, back when I was beginning with Python,  I thought that encapsulation was an oppressive idea, fit to languages like Java that only seemed to make life difficult for programmers. But as I ease my mind into the possibility of enterprise scale development, the merits of encapsulation as a pattern become evident. Still, I do hate having to write two line getters and setters in Java.

So, does python have encapsulation? Of course it does:

– It’d seem that all class variables are public in Python. Not so. The variables live inside the object’s dict. What Python does is that it gives you default public getters and setters with neat syntax, and that’s all you need in the majority of cases. Need some specialized behavior? Just use property and override getters and setters with your own.

– Then there is encapsulation by convention. Don’t want someone accessing something from the outside? Prepend with single underscore. Someone REALLY shouldn’t rely on an implementation detail? Use double underscores which also mangles the name. There’s protected and private for you. Sure, no-one can really stop you from peaking inside and messing things up. But this convention is so strong in python that if you do, by design or mistake and not with a very, very good excuse, you might as well forfeit your pythonic license.

Python basically says: You are an adult, act like it. And treat others like adults too. But the pattern is still there.

So, yesterday NASA published a collection of sounds from historic spaceflights and current missions.
You can check them out here.

Well, I noticed there was no ‘download ALL’ button there, and because most links at a time were hidden by means of javascript my normal tools didn’t really work.

SO! It was time for some scripting!

First, I opened up the FireBug console [link] and tried to see if jQuery was used on the page.
Of course it was, BUT, with a twist. The $ shortcut was assigned to another library. No matter, I can still use jQuery ‘s full name.

So, let’s get a list with all the links to .mp3 files:

jQuery('a[href$=".mp3"]')

which means, get all anchor elements whose href attribute ends with “.mp3”

What should we do to them then?
Keeping it simple, let’s just print the href attribute for each of them on the console. So we go:

jQuery('a[href$=".mp3"]').each(
    function(){
        console.log(jQuery(this).attr('href'));
    })

Pretty straightforward. It’s a one-liner, but I indented here for clarity.

You’ll notice that at the end of the links, we also get an array of all the elements. Well, that’s because our whole statement also returns the collection.
So let’s copy-paste the links to a text file, let’s name it ‘in’.

........
/mp3/590318main_ringtone_135_launch.mp3
445945....min.js (line 30)
/mp3/577774main_STS-135Launchringtone-v2.mp3
445945....min.js (line 30)
/mp3/590196main_ringtone_135_landingCommanderComments.mp3
445945....min.js (line 30)
/mp3/590316main_ringtone_135_landingNaviusComments.mp3
445945....min.js (line 30)
/mp3/581549main_Apollo-8_Merry-Christmas.mp3
........

Oh bummer! We also got a lot of lines like “445945….min.js (line 30)” on them. Not really a problem, let’s crunch it up with python for the geek-out factor:
I ran this:

with open('in') as f:
    lines = f.readlines()
final = [line for line in lines if line.endswith('.mp3\n')]
with open('out', 'w') as f:
    f.writelines(final)
    f.write('\n')

Again, we only keep that lines that end with ‘.mp3’ (and the newline) as relevant.
What should we do with our list file now you ask? But of course use wget.
We want wget to grab all our .mp3s from the list in the file, prepending ‘http://www.nasa.gov’, as the urls are relative
Here it is:

wget -i b -B http://www.nasa.gov

And voila! Here is our collection of NASA mp3s for our geeky pleasure!

Python Object Reference

I have a friend struggling with some code wight now, so I’m copy-pasting an interactive session with some object reference basics that I hope will clarify some things 😉

There’s also a pastie for this in http://paste.lisp.org/+2E0W for easier reading.

>>> # First, lets make a Class to help with tests
>>> class Coco(object):
	def __init__(self, value=0):
		self.value = value

>>> # Lets make a list of instances, the dumb way
>>> a = [Coco()] * 4
>>> a
[<__main__.Coco object at 0xb64c9cac>, <__main__.Coco object at 0xb64c9cac>,
 <__main__.Coco object at 0xb64c9cac>, <__main__.Coco object at 0xb64c9cac>]

>>> # See that the addresses are the same? Lets look values
>>> [i.value for i in a]
[0, 0, 0, 0]

>>> # Now, let's try to change one of them
>>> a[0].value = 1

>>> # We now expect [1, 0, 0, 0], right?
>>> [i.value for i in a]
[1, 1, 1, 1]

>>> # NOPE! All of them changed because it's THE SAME OBJECT
>>> 

>>> # Let's do it again the smart way
>>> a = []
>>> for i in range(4):
	a.append(Coco())

>>> a
[<__main__.Coco object at 0xb64b906c>, <__main__.Coco object at 0xb64d128c>,
 <__main__.Coco object at 0xb64d1c2c>, <__main__.Coco object at 0xb64d1c0c>]

>>> # See that the addresses are different?
>>> [i.value for i in a]
[0, 0, 0, 0]

>>> a[0].value = 1
>>> [i.value for i in a]
[1, 0, 0, 0]

>>> # Pretty cool huh?
>>> 

>>> # Lets also put the list in variable b
>>> b = a
>>> [i.value for i in a]
[1, 0, 0, 0]

>>> [i.value for i in b]
[1, 0, 0, 0]

>>> # And change a value in b
>>> b[0].value = 0
>>> [i.value for i in b]
[0, 0, 0, 0]
>>> [i.value for i in a]
[0, 0, 0, 0]
>>> # a and b are the same object. A no brainer!
>>> 

>>> # Now let's copy once with copy() and once with deepcopy()
>>> from copy import copy, deepcopy
>>> a_copy = copy(a) # You can also do =a[:] for lists and =a.copy() for dicts
>>> a_deepcopy = deepcopy(a)
>>> a
[<__main__.Coco object at 0xb64b906c>, <__main__.Coco object at 0xb64d128c>,
 <__main__.Coco object at 0xb64d1c2c>, <__main__.Coco object at 0xb64d1c0c>]

>>> a_copy
[<__main__.Coco object at 0xb64b906c>, <__main__.Coco object at 0xb64d128c>,
 <__main__.Coco object at 0xb64d1c2c>, <__main__.Coco object at 0xb64d1c0c>]

>>> a_deepcopy
[<__main__.Coco object at 0xb64d1a4c>, <__main__.Coco object at 0xb64d1a2c>,
 <__main__.Coco object at 0xb64d1a0c>, <__main__.Coco object at 0xb64d19ec>]

>>> a_copy[0].value = 4
>>> a_deepcopy[1].value = 6
>>> # Can you foretell what will happen now?
>>> [i.value for i in a_copy]
[4, 0, 0, 0]

>>> [i.value for i in a_deepcopy]
[0, 6, 0, 0]

>>> [i.value for i in a]
[4, 0, 0, 0]

>>> # While a and a_copy are not the same, their contents are shared!
>>> # Here's how to try when in doubt
>>> a is b
True

>>> a is a_copy
False

>>> a[0] is a_copy[0]
True

>>> a[0] is a_deepcopy[0]
False

>>>
>>> # PS. If you make a list the dumb way
>>> a = [Coco()] * 4

>>> # ..you'll have a list of the same objects even after a deepcopy
>>> k = [Coco()] * 4
>>> k_deepcopy = deepcopy(k)
>>> k_deepcopy[0].value = 1
>>> [i.value for i in k_deepcopy]
[1, 1, 1, 1]

>>> k_deepcopy[0] is k_deepcopy[3]
True

>>> # ..although, not the same ones as the originals
>>> [i.value for i in k]
[0, 0, 0, 0]

>>> k_deepcopy[0] is k[0]
False

>>>
>>> # Hope that's helpful ;)
>>>

Nick