Optimize kv binding

Here's some numbers for the pr after all the commits below. This replaces the earlier example from when it was half finished. I removed the rebind parts from the test code because rebinding is just more binding, so it's also about 2.5x faster (I tested).

changes
--------

Recognizing that functions are the most expensive, I removed the usage of inner functions and partial calls from `create_handler` gaining a binding speed factor of 2.5x. 

To achieve it, I added a `fast_bind/unbind` method to EvenDispatcher which is used solely by the kv language. Those function accept positional args and pass it on to the callback. They also have some optimizations mentioned in the docs, since they are meant exactly for this: fast binding.

Furthermore, to reduce the number of isinstance we have to check, I made Observable a super class of EventDispatcher stubbung the required binding methods. In my mind this makes the inheritance structure saner, anyway. Observable also has proxy_ref, so we can skip any try/except or if hasattr.

Finally, there's also some minor optim to proxy_ref of widget. Each of the small optims above improved perf, if even by smallish amounts.



numbers
--------

binding properties means a rule like `boo0_out: self.obj0.obj1.obj2.obj3.obj4.boo0_in...`
binding events used a rule like `on_boo0_out: self.obj0`

```
binding properties - __master__: 0.256174957224, pr: 0.107697072426
binding event - master: 0.01135848443, pr: 0.0104205454551
unbinding properties - master: 0.152547753701, pr: 0.0143842986728
dispatching `boo0_in` - master: 0.0151368482948, pr: 0.0153673603215
```

profiling
----------

In addition, I also profiled before/after of the creation of the widget with the properties:

With master:

```
         252129 function calls in 1.056 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     5000    0.308    0.000    0.892    0.000 lang.py:1426(update_intermediates)
    35000    0.128    0.000    0.301    0.000 lang.py:1414(get_proxy)
     5000    0.123    0.000    0.123    0.000 {method 'bind' of 'kivy._event.EventDispatcher' objects}
    36002    0.121    0.000    0.178    0.000 widget.py:312(proxy_ref)
    31001    0.064    0.000    0.064    0.000 {isinstance}
    37003    0.059    0.000    0.059    0.000 {hasattr}
    35003    0.056    0.000    0.056    0.000 {method 'append' of 'list' objects}
     1000    0.047    0.000    1.020    0.001 lang.py:1520(create_handler)
    25001    0.044    0.000    0.044    0.000 {getattr}
    25000    0.040    0.000    0.040    0.000 {method 'property' of 'kivy._event.EventDispatcher' objects}
        1    0.009    0.009    1.044    1.044 lang.py:1791(_apply_rule)
     5001    0.008    0.000    0.008    0.000 {len}
     1000    0.006    0.000    0.011    0.000 copy.py:66(copy)
     1000    0.005    0.000    0.008    0.000 {eval}
     1010    0.005    0.000    0.005    0.000 {method 'create_property' of 'kivy._event.EventDispatcher' objects}
     1000    0.004    0.000    0.004    0.000 {locals}
        1    0.004    0.004    1.056    1.056 playground3.py:13(__init__)
     1000    0.004    0.000    0.004    0.000 copy.py:113(_copy_with_constructor)
        1    0.003    0.003    0.007    0.007 lang.py:1020(create_missing)
     2002    0.003    0.000    0.003    0.000 collections.py:73(__iter__)
     1000    0.003    0.000    0.003    0.000 {method 'update' of 'dict' objects}
     1000    0.003    0.000    0.003    0.000 {setattr}
     1010    0.002    0.000    0.002    0.000 {method 'format' of 'str' objects}
        1    0.002    0.002    0.003    0.003 collections.py:104(values)
     1000    0.002    0.000    0.002    0.000 {method 'get' of 'dict' objects}
        1    0.001    0.001    1.045    1.045 widget.py:283(__init__)
```

with pr:

```
         180127 function calls in 0.680 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     5000    0.311    0.000    0.564    0.000 lang.py:1424(update_intermediates)
    36002    0.062    0.000    0.062    0.000 widget.py:313(proxy_ref)
    35003    0.055    0.000    0.055    0.000 {method 'append' of 'list' objects}
    31001    0.055    0.000    0.055    0.000 {isinstance}
    25001    0.044    0.000    0.044    0.000 {getattr}
     1000    0.044    0.000    0.647    0.001 lang.py:1517(create_handler)
    25000    0.039    0.000    0.039    0.000 {method 'property' of 'kivy._event.EventDispatcher' objects}
     5000    0.011    0.000    0.011    0.000 {method 'fast_bind' of 'kivy._event.EventDispatcher' objects}
     5001    0.008    0.000    0.008    0.000 {len}
        1    0.007    0.007    0.668    0.668 lang.py:1776(_apply_rule)
     1000    0.006    0.000    0.010    0.000 copy.py:66(copy)
     1000    0.005    0.000    0.008    0.000 {eval}
     1010    0.005    0.000    0.005    0.000 {method 'create_property' of 'kivy._event.EventDispatcher' objects}
        1    0.004    0.004    0.680    0.680 playground3.py:13(__init__)
        1    0.003    0.003    0.007    0.007 lang.py:1003(create_missing)
     2002    0.003    0.000    0.003    0.000 collections.py:73(__iter__)
     1000    0.003    0.000    0.003    0.000 {method 'update' of 'dict' objects}
     1000    0.003    0.000    0.003    0.000 copy.py:113(_copy_with_constructor)
     1000    0.002    0.000    0.002    0.000 {setattr}
     1010    0.002    0.000    0.002    0.000 {method 'format' of 'str' objects}
        1    0.002    0.002    0.003    0.003 collections.py:104(values)
     1001    0.002    0.000    0.002    0.000 {hasattr}
     1000    0.002    0.000    0.002    0.000 {method 'get' of 'dict' objects}
        1    0.001    0.001    0.669    0.669 widget.py:284(__init__)
```

Test code
----------

```
from kivy.lang import Builder
from kivy.uix.widget import Widget
import pstats
import cProfile
import timeit
from kivy.base import EventLoop
EventLoop.ensure_window()
Widget()


class TestWidget(Widget):

    def __init__(self, **kwargs):
        for i in range(5):
            self.create_property('obj{}'.format(i), self)

        # create bool props to be used in rule source
        for i in range(5):
            self.create_property('boo{}_in'.format(i), False)

        # create bool props to be used for rule target
        for i in range(1000):
            self.create_property('boo{}_out'.format(i), False)
        super(TestWidget, self).__init__(**kwargs)


prop_rule = ' and '.join(['self.obj0.obj1.obj2.obj3.obj4.boo{}_in'.format(i)
                          for i in range(5)])
prop_rule = ['    boo{}_out: {}'.format(i, prop_rule) for i in range(1000)]

event_rule = ['    on_boo{}_out: self.obj0'.format(i) for i in range(1000)]

rule = prop_rule

kv = '\n'.join(['<TestWidget>:'] + rule)
Builder.load_string(kv)

count = 100
test_bind = True
profile = True

widget = TestWidget()
prop = widget.property('boo0_in')

if test_bind:
    print timeit.timeit('TestWidget()', "from __main__ import TestWidget", number=count) / float(count)
    print timeit.timeit('prop.dispatch(widget)', "from __main__ import widget, prop", number=count) / float(count)

elif not profile:
    objs = [TestWidget() for _ in range(count)]
    keep_refs = []
    print timeit.timeit('Builder.unbind_widget(objs[0].uid) or keep_refs.append(objs.pop(0))',
                        "from __main__ import objs, Builder, keep_refs", number=count) / float(count)
else:
    cProfile.runctx("TestWidget()", globals(), locals(), "Profile.prof")

    s = pstats.Stats("Profile.prof")
    s.strip_dirs().sort_stats("tottime").print_stats()
```