offsets cleanup
This is mostly a small cleanup of offsets, want to keep this fairly trivial diff from obscuring more important upcoming changes.

The two non-trivial things here are 1) implement `_Tick` class in offsets.pyx with the most basic of its methods and 2) optimization of `Tick.__hash__`.  You'd be surprised how big a difference this particular optimization makes:

Before:
```
In [2]: day = pd.offsets.Day(2)
In [3]: %timeit hash(day)
100000 loops, best of 3: 11.7 µs per loop
```

After
```
In [3]: day = pd.offsets.Day(2)
In [5]: %timeit hash(day)
The slowest run took 8.61 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 1.86 µs per loop
```
Hello @jbrockmendel! Thanks for updating the PR.



Cheers ! There are no PEP8 issues in this Pull Request. :beers: 

##### Comment last updated on November 08, 2017 at 17:32 Hours UTC also add a note in perf for 0.22; as you make more changes u can add those issue numbers in (PR numbers) There's a lot of upcoming work in offsets.  Luckily it isn't all cut/paste, so it won't be quite the deluge of PRs.  Going to put together a thorough set of asvs; will remove the optimization and make this pure-cleanup for now. Yes

Sent from my iPhone

> On Nov 8, 2017, at 12:17 PM, Jeff Reback <notifications@github.com> wrote:
> 
> @jreback requested changes on this pull request.
> 
> In pandas/tseries/offsets.py:
> 
> > @@ -1227,12 +1227,7 @@ def onOffset(self, dt):
>          if self.normalize and not _is_normalized(dt):
>              return False
>          first_weekday, _ = tslib.monthrange(dt.year, dt.month)
> -        if first_weekday == 5:
> -            return dt.day == 3
> is this the same logic?
> 
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub, or mute the thread.
> 
 linting issue & rebase would like to have some benchmark asv's here as well.