惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

B
Blog RSS Feed
B
Blog
N
Netflix TechBlog - Medium
量子位
月光博客
月光博客
博客园_首页
博客园 - Franky
酷 壳 – CoolShell
酷 壳 – CoolShell
Last Week in AI
Last Week in AI
T
The Blog of Author Tim Ferriss
Hugging Face - Blog
Hugging Face - Blog
雷峰网
雷峰网
M
MIT News - Artificial intelligence
J
Java Code Geeks
大猫的无限游戏
大猫的无限游戏
D
DataBreaches.Net
腾讯CDC
Engineering at Meta
Engineering at Meta
云风的 BLOG
云风的 BLOG
L
LangChain Blog
GbyAI
GbyAI
IT之家
IT之家
Y
Y Combinator Blog
人人都是产品经理
人人都是产品经理

Secret Weblog

Becoming More Xee: A Modern XPath and XSLT Engine in Rust Looking for new challenges! Repeat Yourself, A Bit The Curious Case of Quentell The Humble For Loop in Rust The Humble For Loop in JavaScript Don Question Best Practices I Was a 1980s Teenage Programmer Part 5: Achieving Assembly I Was a 1980s Teenage Programmer Part 4: The Call of Assembly The Tooling Shift I Was a 1980s Teenage Programmer Part 3: MSX-2 JavaScript: when you need two ways to do it! Empowering Programming Languages Bloat and Retrofuturism Refreshing my Blog Again Random Rust Impressions Apilar: An Alife System I Was a 1980s Teenage Programmer Part 2: Olivetti M24 I Was a 1980s Teenage Programmer: the Alphatronic SolidJS fits my brain Is premature optimization the root of all evil? Framework Patterns: JavaScript edition Roll Your Own Frameworks Framework Patterns Secret Weblog Highlights Refactoring to Multiple Exit Points mstform: a form library for mobx-state-tree Seven Years: A Very Personal History of the Web
Reg, Now With More Generic!
Martijn Faassen · 2013-10-28 · via Secret Weblog

A month ago I first announced the Reg library for Python. After posting it I got a comment asking why I didn't just use simplegeneric or PEP 443? One important reason is that I wasn't aware them. The other reason is that I want some special features. But it did get me thinking. Thanks commenter yesvee!

PEP 443

So what's PEP 443? It proposes functionality that lets you create generic functions that dispatch on their first argument (single dispatch):

from functools import singledispatch
@singledispatch
def fun(arg):
    return "The default"

@fun.register(int)
def int_fun(arg):
    return "Int argument"

@fun.register(list)
def list_fun(arg)
    return "List argument"

When you now call fun() it will dispatch to different implementations dependent on the type of the first argument:

>>> fun(1)
"Int argument"

>>> fun([])
"List argument"

>>> fun('foo')
"The default"

The advantage: dispatch on type, which is useful to extend classes from the outside, but just functions to the end user.

The Zope Component Architecture

Reg is the Zope Component Architecture (ZCA) reimagined. The ZCA is interface-centric. Objects are looked up by interface, and an interface looks a lot like a class. Here's what it looked like with Reg (which has a simpler registration API):

import reg

class IFunctionality(reg.Interface)
    pass

def int_fun(arg):
    return "Int argument"

def list_fun(arg)
    return "List argument"

r = reg.Registry()
r.register(IFunctionality, [int], int_fun)
r.register(IFunctionality, [list], list_fun)

And then this is how you'd use it:

>>> IFunctionality.adapt(1)
"Int argument"
>>> IFunctionality.adapt("List argument")
"List argument"

This API was in fact slightly less good as you could accomplish with the ZCA itself:

>>> IFunctionality(1)
"Int argument"
>>> IFunctionality("List argument")
"List argument"

This is because I wanted to keep Reg simpler, and the ZCA has to do quite a lot of wizardy to make the latter functionality work. But I actually wanted it in Reg. And that starts to look suspiciously like a generic function implementation.

So I started thinking about rewriting Reg so it presented itself much like generic functions as in PEP 443, but with special Reg sauce added. I talked it over with a few people at PyCon DE too. Thanks for helping me clarify my thinking!

All New Generic Reg

So last week I refactored Reg so be generic function based. Gone is lookup by interface, in is generic function calling. Here's what it looks like with Reg today:

import reg

@reg.generic
def fun(arg):
    return "The default"

def int_fun(arg):
    return "Int argument"

def list_fun(arg)
    return "List argument"

r = reg.Registry()
r.register(fun, [int], int_fun)
r.register(fun, [list], list_fun)

And using it looks like a normal function call, just like in PEP 443:

>>> fun(1)
"Int argument"

Reg doesn't deal with interfaces anymore. Interfaces tend to scare off Python developers as they're a new concept, and I realize they just weren't necessary anymore. Now people using your Reg-based APIs just use functions, like with any other API.

Why not use the decorator approach to register generic function implementations? Because Reg allows more than one registry. While writing this I realize that's not a good answer: I can provide this in Reg if I make the decorator a method on Registry. Stay tuned!

But anyway, Morepath, the web framework built on Reg that I'm working on, already supplies a decorator like this that integrates with its configuration engine.

Why Reg instead of PEP 443?

So what's the special Reg sauce? Why not just use PEP 443? Reg offers a few facilities that I needed in Morepath:

  • Multiple dispatch. PEP 443 offers single dispatch on the first argument. Reg implements multiple dispatch, on multiple arguments. This is handy when you're implementing a web framework such as Morepath, which dispatches on request and model.
  • You can isolate one set of generic implementation function implementations from another one in the same runtime. This is because Reg allows more than one registry in which these can be registered.
  • Registries can also be composed together. This allows a core framework to register some implementations and application code some more.
  • The registry to use can be implicit, or you can be totally explicit about what registry to use when you call a generic function.
  • Get all the generic functions that would apply to arguments. Register other things than functions and still look them up. I use these advanced use cases in Morepath in a few places.
  • Predicate support. The Pyramid web framework lets you register views not only by type, but also by other things, such as HTTP request method (GET, POST, etc). I've put support for this kind of thing in Reg itself, and I use it in Morepath. This bit is still underdocumented, please stay tuned!

Luckily you don't have to commit to Reg. You could implement your API using the more modest PEP 443 implementation first, and then switch to Reg should you discover its features would be helpful to you. You'd have to change how you register the implementations of generic functions, but not the API itself.

The New Reg Docs

I've updated and extended the Reg docs. Read the usage docs and check out the all new API documentation!

This should help you get started using Reg.

Road to Morepath

Reg is foundational to Morepath, the up and coming Python micro web framework with super powers. I've adjusted Morepath to use the new generic Reg. The morepath code is online. Stay tuned for docs!