Sunday, 23 September 2012

Python: "or" and "and" operators yield more stuff than bool

Python's and and or operators don't yield bool. They don't calculate the result of the expressions into booleans, and most certainly do not give us True or False.

They return one of the objects we put in. So they are not useful only in if statements, and can't convert to a boolean by themselves (without bool(), that is).

You might be familiar with using or like this since it's a common alternative to ... if ... else .... Take this __init__ method for example:

    def __init__(self, form=None):
        self.form = form or self.make_form()

It is straightforward, readable, and short. Pythonic indeed.

If the right operand is an expression which would throw an error, as long as the left operand is true, you don't have to worry. The right expression will not be evaluated. This is not old. We have seen it in if statements in the C language. I have used it countless times in Java to avoid NullPointerException. It wouldn't make any sense for a machine or virtual machine to evaluate both expressions if the first one already evaluates to true.

>>> def get_sth():
...     raise NotImplementedError
... 
>>> [1] or get_sth()
[1]
>>> [] or get_sth()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in get_sth
NotImplementedError


A very good use of this is to try to tentatively get a resource in one manner which is more likely to succeed, and then try a more risky or less desireable fallback if the first manner yields nothing.

This is awesome for creating intuitively usable classes. For example, a make_form implementation could be a single-line "raise NotImplementedError", so client code can initialize the class without passing in a form object every time, but if they want to use the defaults they just have to inherit the class and make their own make_form method. It's very practical, intuitive and informative behavior just for a single expression, isn't it?

Here is the or expression behavior, described:
  • When one of the operands evaluate to True, return the one which evaluates to True.
    • >>> 1 or 0
      1
      >>> 0 or 1
      1
  • When both evaluate to True, returns the left one (python won't even look at the second operand, so you can rest assured no methods will be called, if any.)
    • >>> 1 or [1]
      1
      >>> [1] or 1
      [1]
  • When both evaluate to False, returns the right one.
    • >>> 0 or []
      []
      >>> [] or 0
      0
We can use the last caracteristic, too. Sometimes two values are False, but we want to use one over the other. (standard falsy values are the empty list, the empty tuple, 0, False, None, and the empty string).

The and operator is rather interesting. It gives you:
  • The right operand, when both evaluate to True:
    • >>> True and 1
      1
      >>> 1 and True
      True 
  • the operand which evaluates to False, when one of them is falsy:
    • >>> 19 and 0
      0
      >>> 0 and 19
      0
  • The left operand, when both evaluate to False
    • >>> 0 and False
      0
      >>> False and 0
      False

Thursday, 20 September 2012

Interesting-c

I'm creating a new programming language!

This language will be created through transcompilation to C. Inspired by the concept of CoffeeScript, and including a lot of Python philosophies and ideas, I will try to create a language which is really easy to use, and yet fast as C.

One of the most important features will be reflection and metaprogramming facilities. This will help developers by describing the structure of their programs at runtime. This makes for good ORM's, serializers, etc.

It will not use classes for encapsulation, but instead a new concept I have created. It will build upon the capabilities of classes and the concept of "is-a" relationships. More on these soon.

interesting-c aims to be able to interpret 99% of existing C programs as interesting-c. So a C program will (almost) always be a interesting-c program. This allows developers to convert gradually to interesting-c.

interesting-c will have a module system. modules will be able to import other modules as well as pure C source or header files. The syntax will be something like this:

    import "c_module.c";
    import icmodule;

When importing, interesting-c will just add a #include directive to the compiled source, but it will simulate the concept and behavior of a namespace. It will parse the #included file and look for identifiers which the current module can use. Optionally, users will be able to use import module_name as alias syntax to assign the module to an identifier so its namespace can be isolated from the local module namespace. This poses a new problem: C has no concept of a namespace and will not allow the programmer to choose between foo in module1.c and foo in module2.c. It's unclear how I will solve this

interesting-c will discourage (but still support) preprocessor directives. But there will be a lot more space for safer, more interesting pre-compile-time magic as well as runtime magic. And yet, you will still be able to shoot yourself in the foot and use macros as much as you want.

Early work

I have started creating interesting-c, and it really gives me new interesting problems to solve.

I am using PLY (python-lex-yacc)'s lex to create the lexer. My challenge right now is to preserve whitespace as possible, as well as most of the code appearance, since it's important for the users to be able to opt in and out of interesting-c at any time, so it will be something easy to adopt.

I have been creating small C programs to test C language features. Programs like these help me test whether and how the language supports something.

    /* Test whether floating point numbers can be octal */

    int main(int argc, char* argv[]){
        float oct = 01.1f;
        return 0;
    }

Monday, 10 September 2012

Python: str.split has a "limit" argument

I have recently made this little discovery. It seems that str.split has a maxsplit argument, which tells it to only split into a certain amount of parts. This could be really useful for text parsing.
I have in the past run into some (rare) situations where I needed to do this, but didn't know of the maxsplit parameter, and ended up using str.join and slices, to recreate the rest of the string with the delimiters.

It's a little boring to do, and it is ugly.
>>> url = '/posts/blog-1/10251/'
>>>
>>> #problem: split the URL into two parts
... #such that first_part == 'posts' and second_part == 'blog-1/10251'
... #first solution: split and join with slices.
...
>>> first_part = url.strip('/').split('/')[0]
>>> second_part = '/'.join(url.strip('/').split('/')[1:])
>>> first_part, second_part
('posts', 'blog-1/10251')
However, if we do this using the split limit argument, it becomes much more readable.
>>> #second solution: use unpacking, and str.split() with the limit argument
...
>>> first_part, second_part = url.strip('/').split('/',1)
>>> first_part, second_part
('posts', 'blog-1/10251')
>>>
The "limit" argument asks you how many splits you would like, not how many fragments you would like. So specify the n-1 when you want n fragments.

What about splitting by whitespace?

Splitting by whitespace is one of the most powerful features in str.split(). Since I usually invoke this functionality using "".split() without any arguments, I was worried about splitting by whitespace, with the limit argument being a positional-only argument, but you can also use "".split(None).
This is nice since the exact whitespace that used to be there would be impossible to recover with the above tactic (since it's not just a delimiter character).
>>> 'OneFragment TwoFragments ThreeFragments'.split()
['OneFragment', 'TwoFragments', 'ThreeFragments']
>>> 'OneFragment TwoFragments ThreeFragments'.split(maxsplit=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: split() takes no keyword arguments
>>> 'OneFragment TwoFragments ThreeFragments'.split(None, 1)
['OneFragment', 'TwoFragments ThreeFragments']

Split by whitespace, and preserve it.

When you split by whitespace, str.split splits by spaces, tabs, carrier returns and newlines. There are many whitespace characters, and sometimes you want to preserve this information. When using string.split and joining it back, you have no way of getting that information back. It's gone. However, the maxsplit argument allows you to preserve the existing whitespace.
>>> 'And together we fled.\r\nWe said:\r\n\t"Hello!"'.split(None, 1)
['And', 'together we fled.\r\nWe said:\r\n\t"Hello!"']
>>> print _[1]
together we fled.
We said:
        "Hello!"

Friday, 7 September 2012

Python: Unpacking works with one item!

One of the advantages in python is that it is very practical to unpack variables out of short lists and tuples. Some pieces of code which would otherwise be repetitive and ugly (a = lst[0]; b = lst[1]) end up clean, short and easy to read.

>>> a,b = [1,2]
>>> a
1
>>> b
2
>>> 
It's the reason behind python's multi-return values making sense. When we create code that is going to be used by other modules, it opens up a lot of possibilities, and eases the writing and understanding of the client code that uses them.
>>> #create_monkey will use the monkey count in its calculations.
... This value is very useful for client code, but it is rather expensive to obtain.
... monkey, new_monkey_count = create_monkey()
>>>

My discovery today is that you can "unpack" a list or tuple even when it contains only one item. Check it out:

ActivePython 2.7.2.5 (ActiveState Software Inc.) based on
Python 2.7.2 (default, Jun 24 2011, 12:22:14) [MSC v.1500 64 bit (AMD64)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> a, = [1]
>>> a
1
>>> a, = []
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: need more than 0 values to unpack
>>> 

This opens up some possibilities. If we are one hundred percent sure that the list contains a single value, we can unpack that into a variable instead of using [0], which is inherently ugly.

When you are not sure whether the container is empty (or more than one item), you can always catch the resulting ValueError. Or use this:

>>> (a,) = [] or ['default']
>>> a
'default'
>>> 
However, the comma is very subtle and future code readers (including the smartass who decided to use this obscure thang) will probably not notice it. This effectively makes refactoring affected code tricky.

Furthermore, someone may think that it is a syntax error, edit the comma out, and TypeErrors and ValueErrors start popping up everywhere. Subtle bug hunting fun!

There is a little workaround for these readability issues, which is to use full tuple syntax:
>>> (a,) = [1]
>>> a
1
>>>
So it seems like I can use this single-unpacking to do good and not just evil.
It seems to be really interesting, but I am not sure whether I should use it in real code. Seems like I have some meditation to do.
In the meantime, I can show off a little.
>>> a, = 1,
>>> a
1
>>>  

Saturday, 25 August 2012

django-model-permissions

I have created a small library to help create access control in Django projects. It uses a "lock" paradigm, where you can lock certain methods in Django Models (right now it actually works on every class, but I may be adding features that need more tight integration).

The purpose is to take access control to the Model layer, and out of the Controller (view) layer.

Here's how you use it (taken from the readme)

First, apply locks to some model methods:
class Example(models.Model, LockingMixin):
    class Meta:
        permissions = [
            ('example_can_get_id', 'Can get ID')
        ]

    name = models.CharField(max_length=33)

    @locks.permission('app.example_can_get_id')
    def get_id(self):
        return self.id
Then, instance it and use it. When you try to access a locked method, modelpermissions will throw an exception.
model = Example.objects.create(name='name')

try:
    model.get_id()
    assert False #remove this
except PermissionDenied:
    'django.core.exceptions.PermissionDenied was thrown'

But now let's unlock this model instance and try again

model.unlock(user)

model.get_id()
'no exception thrown'
 
Locks aren't limited to permission locks. You can use @locks.conditional and pass it a function that receives the model instance and do more flexible stuff with it.

And the future looks nice, too. Instead of just raising PermissionDenied, I feel that this could make more interesting stuff, like use an alternate method, when the user doesn't have enough permissions (even return a different Proxy model from the lock() method, which will start to return the model instance itself for chainability), and a different LockingMixin to lock things only when you explicitly call lock() on the Model.

It's available on github. Try it out!

Tuesday, 14 August 2012

Django Test Coverage

The django-test-coverage (https://github.com/srosro/django-test-coverage) is an exciting project that leverages coverage.py in Django projects.
It is most helpful in figuring out if your project is being comprehensibly covered by your automated tests. When you run ./manage.py test, django-test-coverage outputs coverage information. It doesn't help much that the coverage information prints out even when tests fail, making you scroll your command line session a bit more, but this might be fixable.
I was looking for a way to check test coverage for a Django application, and noticed that the project didn't have its own setup.py, nor was it ready for Django 1.4 because of a python package issue. I forked the project, created an appropriate python package, and moved the files in. Then I created a setup.py.
Not a big change, but it allowed me to test my application with coverage on Django 1.4, as well as install django-test-coverage much more cleanly, using pip.
My own fork is here: https://github.com/fabiosantoscode/django-test-coverage. You can report any bugs, suggest stuff to be added, fork, pull request...
Django becomes an even greater and more useful framework because of small plugins like these. It's fascinating how a few lines of code mostly wrapping external functionality can make such a big difference.

Wednesday, 6 June 2012

The most useless thing in the world?

One day, I will need something like this.

>>> class CallableInt(int):
...    def __call__(self):
...       return self
...
>>> a = CallableInt(1)
>>> a()
1
>>>

Won't I?