免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2297 | 回复: 0
打印 上一主题 下一主题

Ruby-style Blocks in Python [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-04-06 17:09 |只看该作者 |倒序浏览

Blocks are supposedly the
most liked feature in Ruby
. This proposal would enable a similar feature in Python:
using webapp.runner do (config):
    config.time_zone = 'UTC'
    config.log_level = 'debug'

Compare that to the Ruby equivalent:
Rails::Initializer.run do |config|
    config.time_zone = 'UTC'
    config.log_level = :debug
end

Unless I am missing something fundamental, adding a do statement seems to lend itself to doing blocks in a Pythonic way.
For those of you that don't know Ruby,
blocks
are simply syntactic sugar for defining anonymous functions/closures.
This is already possible in Python using the rather complicated-looking lambda keyword:
employees.select(lambda e: e.salary > developer.salary)
In contrast, Ruby provides the really sexy:
employees.select {|e| e.salary > developer.salary}
Where lambda limits Python developers to just expressions, Ruby allows for full multi-line blocks:
employees.select do |emp|
    if emp.salary > developer.salary
        fireEmployee(emp)
    else
        extendContract(emp)
    end
end

This is also possible in Python but at the needless cost of naming and defining a function first:
def throwaway_function(emp):
    if emp.salary > developer.salary:
        return fireEmployee(emp)
    else:
        return extendContract(emp)
employees.select(throwaway_function)
This is where my proposed do statement comes in, it would simplify the above to:
using employees.select do (emp):
    if emp.salary > developer.salary:
        return fireEmployee(emp)
    else:
        return extendContract(emp)
Which is hopefully simple and Pythonic enough to everyone's tastes to make this a reality for Python 2.7 and 3.1.
To facilitate this the grammar would need to be extended to something like:
using_stmt ::=
  "using" expression "do" [parameter_list] ":" suite
And when the do keyword is encountered, functionality should be delegated to a __do__ function in the same way that the import keyword delegates to __import__.
The delegation should map the following syntax:
using EXPR do PARAM_LIST:
    BLOCK_CODE
into the function call:
__do__(expr, callback, globals, locals)
Where callback is a function named ‘’ compiled with PARAM_LIST as its parameter_list and BLOCK_CODE as the function body. Like with import, globals() and locals() should be from the scope of the do statement.
As a starting point for discussion, I would like to propose the following as the default __do__ function:
def __do__(expr, callback, globals, locals):
    retval = None
    while 1:
        try:
            args = expr.send(retval)
            if not isinstance(args, tuple):
                args = (args,)
            retval = callback(*args)
        except StopIteration:
            break

This works thanks to Python's support of coroutines through generators
[PEP 342]
and would cover the common case of a generator instance being passed in as the EXPR.
And it just so happens to mirror the semantics of Ruby blocks quite beautifully:
>>> def generator():
...     yield
...     yield>>> using generator() do:
...     print "hello world"
hello world
hello world
The only aspect missing is Ruby's block_given? but that could easily be supported by alternative __do__ implementations if the need arises.
I expect the dominant usage of blocks to be for the creation of DSLs. This has almost become an art form in the Ruby world — with everything from Rake tasks to Rails configuration being done through
mini-DSLs built using blocks
.
It would be interesting to see what the Python world comes up with. The ability to custom define __do__ would allow Python hackers to do some really cool shit with blocks that Ruby hackers can't do for the moment.
And I can imagine a lot of existing frameworks like
Twisted
,
Trellis
,
Eventlet
and
Django
becoming even more simplified and powerful thanks to blocks.
What do you think?
Idealist Addendum:
Whilst I believe the above should suit Guido's taste, I am not so sure of the following. But in an ideal world, he would give it his blessing, so here goes =)
Ideally the do statement would map the following syntax:
using EXPR1 do EXPR2:
    BLOCK_CODE
into the function call:
__do__(expr1, expr2, block_code, indent_level, globals, locals)
This would give the __do__ function even more flexibility at very little cost. By default, EXPR2 would be treated as PARAM_LIST and together with BLOCK_CODE it would be compiled into the callback function described above.
But more enterprising __do__ functions could do interesting things like rewriting the AST of the BLOCK_CODE. Given that this is already done by many many Python libraries, it's not much of a stretch of the imagination. The benefit? Super nice Pythonic DSLs!
Anyways, that's enough ranting for one morning. What do you think? Let me know in the comments or on the
Python-Dev
mailing list.


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/78/showart_1891380.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP