作者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/m.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