Monday, November 27, 2017

My first real open source project!

Okay, I might be overselling it there in the title. But I have created an open source project, that has a real, publicly available web app and has even had a contribution (some spelling corrections) from another human being. It's a small victory, but I'll take it!

Wednesday, October 25, 2017

Today in things I didn't know about Python - __call__

If you define a __call__ method in your class it will get called when you call an instance of that class. I didn't know that. That is all.

In [336]: class foo:
    def __init__(self):
        print "in init"
    def __call__(self):
        print "in call"

In [337]: bar = foo()
in init

In [338]: bar()
in call

Monday, May 22, 2017

Today in things I didn't know in Python - sets

I'm slowly and thoroughly reading through the Python documentation. From the amount I'm learning in the process, I clearly should have done this some time ago.

Today I'm reading about sets. I knew a few things about sets:
- Sets are mutable, unordered, collections of unique objects
- You can declare an empty set with 'set()'
- You can declare a set with things in it like this: '{1, 2, 2}'
- You can get the difference, union, intersection, etc. like this:
 - my_set.thing_I_want(other_set)
- How to create a set comprehension

But there were things I didn't know about sets:
- You don't have to use the .operation() version, you can use operators! Some of which are more intuitive to me than others.

Operation Equivalent Result
s.issubset(t) s <= t test whether every element in s is in t
s.issuperset(t) s >= t test whether every element in t is in s
s.union(t) s | t new set with elements from both s and t
s.intersection(t) s & t new set with elements common to s and t
s.difference(t) s - t new set with elements in s but not in t
s.symmetric_difference(t) s ^ t new set with elements in either s or t but not both
s.update(t) s |= t return set s with elements added from t
s.intersection_update(t) s &= t return set s keeping only elements also found in t
s.difference_update(t) s -= t return set s after removing elements found in t
s.symmetric_difference_update(t) s ^= t return set s with elements from s or t but not both


- There is such a thing as immutable set (it's another class)*
- If you do use the operation_name function version for union, intersection, difference, or symmetric_difference, you don't need to cast the second thing to a set (it just needs to be iterable)


*Edited to add that I've realised it's depreciated and replaced by frozenset since 2.6

Monday, April 24, 2017

Can you use a tuple as a dictionary key? Well, that depends.

Today I was asked if you can use a tuple as a dictionary key. I wasn't sure, and looked into it. And the answer seems to be, 'it depends'.

Can you ever use a tuple as a dictionary key? Yes:


In [35]: my_tup = (1, 2)

In [36]: my_dict = {my_tup: 1}

In [37]: my_dict
Out[37]: {(1, 2): 1}



Can you ALWAYS use a tuple as a dictionary key? Nope:

In [38]: my_other_tup = ([1, 2], 2)

In [39]: my_dict = {my_other_tup: 2}
------------------------------------------------------------
TypeError                 Traceback (most recent call last)
<ipython-input...> in <module>()
----> 1 my_dict = {my_other_tup: 2}

TypeError: unhashable type: 'list'


You can use a tuple as a dictionary key, but only if it's hashable all the way down.

Thursday, March 30, 2017

Don't put nullable fields in your MySQL unique keys

MySQL will allow you to include a nullable field in a unique key. I heartilly recommend that you don't do it.

You may already be aware that NULL isn't equal to anything. That's why we always have 'IS NULL' instead of '= NULL' in our where clauses. When they say not equal to anything, they really mean not equal to anything. Not even itself.

So let's say you have a table that looks a bit like this:

always1 always2 always3 sometimes1 sometimes2
a b c d e
f g h NULL NULL
i value1 value2 NULL NULL

and you have a unique key on always2, always3, and sometimes1

You build some logic around the fairly reasonable idea 'we'll try to insert, and if we get a duplicate key error, we'll update instead'.

And then you try to insert
'always2 = "value1", always3 = "value2", sometimes1 = NULL, always1 = m, sometimes2 = n'
expecting this to fail because of a duplicate key error and update the values for always1 and sometimes2 for the third row above. But it won't. Because NULL isn't equal to itself. So you'll end up with a table like this:

always1 always2 always3 sometimes1 sometimes2
a b c d e
f g h NULL NULL
i value1 value2 NULL NULL
m value1 value2 NULL n


Beware!

Tuesday, October 20, 2015

How long is the pound symbol?

In Python 3, the pound symbol, £, is one character long, as you would expect.

Python 3.4.0 (default, Jun 19 2015, 14:20:21)
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> len('£')
1



But in Python 2 (which I, like many people, have to use for work), it is two characters long.

Python 2.7.6 (default, Jun 22 2015, 17:58:13)
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> len('£')
2


Unless you convert it to unicode.

In [152]: len(u'£')
Out[152]: 1

Worth knowing!

It's also worth being aware that 'str's get a bit funny in Python 2 when you wander out of ascii-land. And iterating through them will not do what you expect. I recommend sticking to unicode where you can.

Sunday, October 4, 2015

"java.lang.RuntimeException: Reader tag must be a symbol" Clojure

Very quick blog post because I couldn't see this anywhere on the top page of results:

If you're learning clojure, and you get this error
'java.lang.RuntimeException: Reader tag must be a symbol'

check if you're putting whitespace between # and ( in an anonymous function literal. Don't do that. 


(If it was something else causing that error for you, please add it to the comments when you work it out)