一种实现模块“重载”的方法

3 views
Skip to first unread message

Davies Liu

unread,
Mar 9, 2010, 11:42:21 AM3/9/10
to python-cn
Hi,

今天因重构代码需要,发现了一种巧妙的方法实现模块级别的"重载",即重新实现模块中的若干内部函数的功能得到一个新模块。

使用方法为:

a.py
==========
def bar():
return 'bar in a'

def foo():
print bar()
===========

b.py
============
from a import *
from luzong.utils import callby

@callby(foo)
def bar():
return 'bar in b'
============

测试
=========
>>> import a, b
>>> a.foo()
bar in a
>>> b.foo()
bar in b
=========

callby 的实现也非常简单:

====================
def clone_func(f, g):
"inspect a func f with globals g"
return f.__class__(f.func_code, g, f.func_name, f.func_defaults)

def callby(caller):
"auto inspect callers for a function"
def deco(f):
g = f.func_globals
callers = [caller,] if not isinstance(caller, (list, tuple)) else caller
for c in callers:
if c.func_globals is not g:
g[c.func_name] = clone_func(c, f.func_globals)
return f
return deco
====================

- Davies

张沈鹏

unread,
Mar 9, 2010, 12:02:41 PM3/9/10
to pyth...@googlegroups.com
打击你一下

这样就可以了

玩奇技淫巧还是我在行啊:)

import a

def bar():
    print "in b"

a.bar = bar

from a import *


foo()

Changsheng Jiang

unread,
Mar 9, 2010, 12:05:36 PM3/9/10
to pyth...@googlegroups.com
如果另有 c.py 里, 再 import a; a.bar 是 b.py 里的 bar 了.

                                                     Changsheng Jiang


2010/3/10 张沈鹏 <zsp...@gmail.com>

--
来自: `python-cn`:CPyUG ~ 华蟒用户组 | 发言:pyth...@googlegroups.com
退订: http://tinyurl.com/45a9tb //针对163/qq邮箱:http://tinyurl.com/4dg6hc
详情: https://groups.google.com/group/python-cn
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp

Davies Liu

unread,
Mar 9, 2010, 12:09:30 PM3/9/10
to pyth...@googlegroups.com
正解,zsp 那是倾入式的覆盖。

- Davies


2010/3/10 Changsheng Jiang <jiang...@gmail.com>:

张沈鹏

unread,
Mar 9, 2010, 12:10:58 PM3/9/10
to pyth...@googlegroups.com

ln c.py a.py


=============
cat b.py
=============

import a

def bar():
    return "in b"

a.bar = bar
from a import *

foo()

import c
c.foo()

张沈鹏

unread,
Mar 9, 2010, 12:38:23 PM3/9/10
to pyth...@googlegroups.com
import a
import sys
sys.modules['xxxx']=sys.modules['a']
del sys.modules['a']
import xxxx
from xxxx import *
xxxx.bar = lambda:"b"


import a
a.foo()
foo()

张沈鹏

unread,
Mar 9, 2010, 12:40:44 PM3/9/10
to pyth...@googlegroups.com
这样写流程更清晰


import a

import sys
sys.modules['xxxx']=sys.modules['a']
del sys.modules['a']

import a

import xxxx

from xxxx import *
xxxx.bar = lambda:"b"

a.foo()
foo()


limodou

unread,
Mar 9, 2010, 8:06:46 PM3/9/10
to pyth...@googlegroups.com
2010/3/10 Davies Liu <davie...@gmail.com>:

callby这种用法很不好理解,不直观,我的建议是直接定义foo,如果它调用的bar不是a.py的,则再定主乐bar不是更好。从上例来看,foo本身可能是不变的,但是它调用的bar却发生了变化。但是不如重新定义foo这样更让人容易理解a.py,
b.py之间的差异。如果要是再复杂,那还不如直接使用class呢,更清晰。


--
I like python!
UliPad <<The Python Editor>>: http://code.google.com/p/ulipad/
UliWeb <<simple web framework>>: http://uliwebproject.appspot.com
My Blog: http://hi.baidu.com/limodou

Zoom.Quiet

unread,
Mar 9, 2010, 8:07:44 PM3/9/10
to pyth...@googlegroups.com
2010/3/10 张沈鹏 <zsp...@gmail.com>:
> 这样写流程更清晰
>
PHP学习记录->教学文章->Mix-in技术与分布类编程
http://floss.zoomquiet.org/data/20051115110605/index.html

> --
> 来自: `python-cn`:CPyUG ~ 华蟒用户组 | 发言:pyth...@googlegroups.com
> 退订: http://tinyurl.com/45a9tb //针对163/qq邮箱:http://tinyurl.com/4dg6hc
> 详情: https://groups.google.com/group/python-cn
> 严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp
>

--
http://zoomquiet.org 人生苦短? Pythonic!

Zoom.Quiet

unread,
Mar 9, 2010, 8:13:20 PM3/9/10
to pyth...@googlegroups.com
2010/3/10 limodou <lim...@gmail.com>:
收录!
http://wiki.woodpecker.org.cn/moin/MiscItems/2010-03-10

是也乎,是也乎,能够进行这种发现是好的,
只是,最后,想得到简洁的可复用,清晰的代码,还是简单点来比较好...

Leo Jay

unread,
Mar 9, 2010, 10:47:22 PM3/9/10
to pyth...@googlegroups.com
2010/3/10 张沈鹏 <zsp...@gmail.com>:

感觉你没理解LZ要的是什么。
他之所以叫“重载”,是因为,你调用b的foo使用的是b的bar,但你调用a的foo的时候,使用的应该是a的bar。
看看他的测试用例吧:


=========
>>> import a, b
>>> a.foo()
bar in a
>>> b.foo()
bar in b
=========

你的程序做不到这一点的。

--
Best Regards,
Leo Jay

张沈鹏

unread,
Mar 9, 2010, 11:55:05 PM3/9/10
to pyth...@googlegroups.com

你没有
看下面的方法...

import a

import sys
sys.modules['xxxx']=sys.
modules['a']
del sys.modules['a']

import a

import xxxx

from xxxx import *
xxxx.bar = lambda:"b"

a.foo()
foo()
--
Best Regards,
Leo Jay

--
来自: `python-cn`:CPyUG ~ 华蟒用户组 | 发言:pyth...@googlegroups.com
退订: http://tinyurl.com/45a9tb //针对163/qq邮箱:http://tinyurl.com/4dg6hc
详情: https://groups.google.com/group/python-cn
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp



--
卖空间 http://stdyun.com/vhost
写书 http://stdyun.com/book/web2dev
豆瓣 http://www.douban.com/people/zuroc
博客 http://zsp.javaeye.com

Pan Shi Zhu

unread,
Mar 10, 2010, 12:02:50 AM3/10/10
to pyth...@googlegroups.com
> 感觉你没理解LZ要的是什么。
> 他之所以叫"重载",是因为,你调用b的foo使用的是b的bar,但你调用a的foo的时候,使用的应该是a的bar。
> 看看他的测试用例吧:

楼主本来就是在误用“重载”这个词,你跟着误用,无语。。。

重载这个词是指同一个函数给定不同参数时具有不同的行为,覆盖是指通过继承之后重写相关函数来替换相关功能的办法。python中根本不支持重载。只支持覆盖。

重载只可能在 C++ 之类强类型检查的语言中出现,而且重载会导致 ABI 的 name mangling
问题(连接库中的名字跟函数真实名字不同)。python 这种语言中不可能写两个一模一样的函数具有不同参数还能同时生效。

黄毅

unread,
Mar 10, 2010, 12:25:13 AM3/10/10
to python-cn
2010/3/10 Davies Liu <davie...@gmail.com>

Hi,

今天因重构代码需要,发现了一种巧妙的方法实现模块级别的"重载",即重新实现模块中的若干内部函数的功能得到一个新模块。

使用方法为:

a.py
==========
def bar():
   return 'bar in a'

def foo():
   print bar()
===========

b.py
============
from a import *
from luzong.utils import callby

@callby(foo)
def bar():
 return 'bar in b'

你直接在 b.py 里定义同名函数不就可以了
def foo():
    return 'bar in b'
 
--
来自: `python-cn`:CPyUG ~ 华蟒用户组 | 发言:pyth...@googlegroups.com
退订: http://tinyurl.com/45a9tb //针对163/qq邮箱:http://tinyurl.com/4dg6hc
详情: https://groups.google.com/group/python-cn
严正: 理解列表! 智慧提问! http://wiki.woodpecker.org.cn/moin/AskForHelp



--
http://codeplayer.blogspot.com/

大熊

unread,
Mar 10, 2010, 12:57:20 AM3/10/10
to pyth...@googlegroups.com
**kwargs
 
--
新四害:丰田车的底盘,开发商的楼盘,股市的大盘,前男友的硬盘

四不象

unread,
Mar 10, 2010, 4:55:26 AM3/10/10
to pyth...@googlegroups.com
可惜python没有匿名函数,不然写出来就完美了
--

Zoom.Quiet

unread,
Mar 10, 2010, 5:01:12 AM3/10/10
to pyth...@googlegroups.com
2010/3/10 四不象 <tabri...@gmail.com>:
> 可惜python没有匿名函数,不然写出来就完美了
>
有吧... _() ?

--
http://zoomquiet.org 人生苦短? Pythonic!

Zhang Jiawei

unread,
Mar 10, 2010, 7:47:26 AM3/10/10
to pyth...@googlegroups.com
pyqt 的很多函数支持 重载, 因为 原生的 c++ 就有重载。 python 本身实现不了重载,但是可以通过 c++ 实现这种重载。

在 2010年3月10日 下午6:01,Zoom.Quiet <zoom....@gmail.com>写道:

Can Xue

unread,
Mar 10, 2010, 8:27:24 AM3/10/10
to pyth...@googlegroups.com
Python 的函数既然能接受 *args, **kwargs 这种形式的参数,支不支持函数重载实质上也没有什么区别了。

Zhang Jiawei

unread,
Mar 10, 2010, 8:58:42 AM3/10/10
to pyth...@googlegroups.com
我只讨论可以不可以重载,不说可以不可以以后有没有区别,有一说一。说话不要绕行。

何况你这话说的宽了点,你不如说 Python 既然是动态语言,支不支持函数重载实质上也没有什么区别了。

传参的类型和个数都可以用动态特性来替代重载的功能,关键在于动态不在于 *args **kwargs

*args 说白了是 li = [xxx]  def fun(li)

**kwargs 同理。

Leo Jay

unread,
Mar 10, 2010, 10:08:43 AM3/10/10
to pyth...@googlegroups.com
2010/3/10 Pan Shi Zhu <pan.s...@gmail.com>:

>> 感觉你没理解LZ要的是什么。
>> 他之所以叫"重载",是因为,你调用b的foo使用的是b的bar,但你调用a的foo的时候,使用的应该是a的bar。
>> 看看他的测试用例吧:
>
> 楼主本来就是在误用“重载”这个词,你跟着误用,无语。。。
>

嗯嗯,sorry,说错。
历史原因,一直对重载对应overload还是override不清楚。

> 重载这个词是指同一个函数给定不同参数时具有不同的行为,覆盖是指通过继承之后重写相关函数来替换相关功能的办法。python中根本不支持重载。只支持覆盖。
>
> 重载只可能在 C++ 之类强类型检查的语言中出现,而且重载会导致 ABI 的 name mangling
> 问题(连接库中的名字跟函数真实名字不同)。python 这种语言中不可能写两个一模一样的函数具有不同参数还能同时生效。
>

就算你导出一个最简单的void foo(),没有overload也会被mangle的。

大熊

unread,
Mar 10, 2010, 8:35:10 PM3/10/10
to pyth...@googlegroups.com
纠结这些oo的概念就能写出好东西来了?

因地制宜,活学活用!

EK

unread,
Mar 10, 2010, 10:43:03 PM3/10/10
to python-cn`CPyUG`华蟒用户组(中文Py用户组)
见识了动态构造函数的方法,收藏了
Reply all
Reply to author
Forward
0 new messages