作者XperiaZ6C (索尼)
看板Python
标题[问题] function物件可以透过class呼叫吗
时间Sat Aug 22 09:08:09 2020
Python一个很方便的功能是函数可以当作参数传递
那请问我可以在class里面取得调用的函数物件吗
例如我想做到在函数被调用前
可以做其他处理
拿print来举例好了
像是下面程式码这样
class Logger(object):
def int(self, value):
print('Call int()')
return int(value)
def float(self, value):
print('Call float()')
return float(value)
logger = Logger()
logger.int('123')
logger.float('123')
我只知道可以用下面的方法取得函数的名称
class Logger(object):
def __getattr__(self, name):
print('Call %s()' % name)
但是函数物件要怎麽抓?
像是如果我有20个函数的话
那class里面就要写20遍
如果之後又需要扩充到40个函数
那就还要在class里面加40个
有没有什麽方法是可以把logger.func()里的func()直接抓来用的
例如什麽
class Logger(object):
def __getfunc__(self, func, arg):
# do something
return func(arg)
之类的
这样我只要定义一个函数
後面不过扩充几个需要做一样处理的函数
我都不需要再增加class里面的函数数量
感谢
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 111.184.77.196 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/Python/M.1598058491.A.1F6.html
※ 编辑: XperiaZ6C (111.184.77.196 台湾), 08/22/2020 09:11:06
1F:→ gmccntzx1: 你的意思是,每当一个 member method 被呼叫时,就要08/22 09:23
2F:→ gmccntzx1: 抓到是谁被呼叫吗?08/22 09:23
3F:→ gmccntzx1: 如果要的效果是这样,我目前是有想到可以透过 metacla08/22 09:25
4F:→ gmccntzx1: ss 去做08/22 09:25
也不算是member method被呼叫
因为像是int()一开始是没有定义在class Logger里面
之所以会在里面定义是因为要在直接执行int()前做一些处理
假设今天有个函数是 ringing(1)
那我不用管这个函数实际做了什麽
我只要用 logger.ringing(1) 这样去呼叫它
这个Logger class就会在执行完预处理後直接return ringing(1)
像是上面的概念这样
class Logger(object):
def __getfunc__(self, func, arg):
# do something
return func(arg)
※ 编辑: XperiaZ6C (111.184.77.196 台湾), 08/22/2020 09:51:15
5F:→ gmccntzx1: 我厘清一下你想做的事:也就是说,任何一个没有定义在08/22 09:58
6F:→ gmccntzx1: Logger class 里的 function ‘foo’,只要透过 logg08/22 09:58
7F:→ gmccntzx1: er.foo() 这种方式呼叫,你就可以先透过 logger 去做08/22 09:58
8F:→ gmccntzx1: 你想做的事再让那个 function 做自己的事罗?08/22 09:58
9F:→ gmccntzx1: 先说好了,如果要透过这种呼叫方式来达到这种功能是有08/22 10:06
10F:→ gmccntzx1: 点奇怪。虽然说你可以硬是透过 `__getattr__()` 让08/22 10:06
11F:→ gmccntzx1: logger 在找不到 member method 时(也就是上述的情况08/22 10:09
12F:→ gmccntzx1: ),去其他 scope 找你要的 function ,如 globals()08/22 10:11
13F:→ gmccntzx1: 。但是这样你就要自己处理 name resolution 的问题。08/22 10:12
14F:→ gmccntzx1: 再来,怎麽取得 caller 的 arguments 又是另一个问题08/22 10:13
15F:→ gmccntzx1: 但是如果你没有需要处理 caller arguments 的话,那上08/22 10:19
16F:→ gmccntzx1: 面那个问题就省了08/22 10:19
17F:推 skyconquer: 我回了一篇文在底下,请参考看看。08/22 10:27
18F:推 TitanEric: 怎麽觉得跟decorator有关08/22 10:37
19F:→ gmccntzx1: 我是这样觉得,但目前还不清楚原 PO 真正的问题08/22 10:39
20F:→ gmccntzx1: 怕变成 XY problem08/22 10:40
21F:→ gmccntzx1: 先给原 PO 看看这个是不是你想要的结果:08/22 10:45
感谢您的详细解说
让我发现我整个会错意了
因为函数并不是定义在global 或是 local scope
而是客户给的一个Java Code里面
我这边是要用RPC去呼叫
这样好像是根本找不到function没错
客户给的Java code会像这样
package com.example.java.rpc;
public class JavaCode implements RpcInterface {
public boolean click() {
// do something
}
而我Python端可以继承现有的RpcInterface
然後给他Java的package name
就能产生一个接口去呼叫Java里面的函数
class UseJavaCode(RpcInterface):
def test_java_code(self):
self.java = self.load_interface('com.example.java.rpc')
self.java.click()
而我这边是希望写一个Python wrapper去把这个interface包起来
在呼叫Java之前做一些处理
class Wrapper(object):
def __init__(self, rpc):
self.java = rpc.load_interface('com.example.java.rpc')
def click(self):
# do something
return self.java.click()
class UseJavaCode(RpcInterface):
def test_java_code(self):
self.java = Wrapper(self)
self.java.click()
但是这样客户以後扩充他的Java code
我这边的Python wrapper就也要跟着扩充
所以才想说有没有办法直接抓到class.func()的.func()进来到class里面跑
像是
class Wrapper(object):
def __init__(self, rpc):
rpc.java = load_interface('com.example.java.rpc')
self.java = rpc.java
def __getfunc__(self, func):
# do something
return self.java.func()
抱歉造成大家误解了QQ
※ 编辑: XperiaZ6C (111.184.77.196 台湾), 08/22/2020 11:51:58
※ 编辑: XperiaZ6C (111.184.77.196 台湾), 08/22/2020 11:54:09
※ 编辑: XperiaZ6C (111.184.77.196 台湾), 08/22/2020 12:06:14
23F:→ gmccntzx1: 试试看这是不是你要的效果:08/22 12:30
25F:→ gmccntzx1: 但是这个做法就如同前面提到的,若你需要处理 caller08/22 12:31
26F:→ gmccntzx1: arguments 的话,还要额外透过 frame 去抓资讯08/22 12:31
27F:→ gmccntzx1: 另一个做法是改成用 function wrapper 把每一个 rpc08/22 12:33
28F:→ gmccntzx1: 提供的 function 都包过一次,这种方法对於也要处理08/22 12:33
29F:→ gmccntzx1: arguments 的话会比较方便,但是缺点就是一旦 wrapper08/22 12:34
30F:→ gmccntzx1: 太多,要转进呼叫到实际上 rpc 的 function 也需越多层08/22 12:34
31F:→ gmccntzx1: 接续上面第一种方式,也可以不透过 frame 去抓 caller08/22 12:58
32F:→ gmccntzx1: argument08/22 12:58
非常感谢您!
第二个方法看起来可以解决这个问题
再次感谢
※ 编辑: XperiaZ6C (111.184.77.196 台湾), 08/22/2020 13:27:21
34F:→ gmccntzx1: (`・∀・)b 08/22 17:27
35F:→ azuel: 看了这些讨论之後我觉得自己好菜 08/23 18:03
36F:推 gmccntzx1: @azuel 不用这样说,每个人都嘛是从新手开始走起。觉 08/23 20:51
37F:→ gmccntzx1: 得自己不足的时候,就继续努力把能力练起来,这才是该 08/23 20:51
38F:→ gmccntzx1: 做的事。而且说实在的,我也没有解决了什麽高深的问题 08/23 20:51
39F:→ gmccntzx1: ,纯粹只是分享以我目前所知所能构成的解法。以後对 P 08/23 20:51
40F:→ gmccntzx1: ython 了解更透彻後,说不定又会有更好的解法。共勉之 08/23 20:51