2009-09-30 68 views
2

反正有做這樣的事情:Python可以判斷類的對象的訪問方法

class A: 
    def foo(self): 
     if isinstance(caller, B): 
      print "B can't call methods in A" 
     else: 
      print "Foobar" 
class B: 
    def foo(self, ref): ref.foo() 

class C: 
    def foo(self, ref): ref.foo() 


a = A(); 
B().foo(a) # Outputs "B can't call methods in A" 
C().foo(a) # Outputs "Foobar" 

呼叫者A採用某種形式的自省來確定類調用方法的對象?

編輯

最後,我把這個共同基礎上的一些建議:

import inspect 
... 
def check_caller(self, klass): 
    frame = inspect.currentframe() 
    current = lambda : frame.f_locals.get('self') 
    while not current() is None: 
     if isinstance(current(), klass): return True 
     frame = frame.f_back 
    return False 

它不適合提供的所有原因,但爲響應感謝:他們是一個很大的幫助。

+2

你提到你有大量的類互相調用。您似乎試圖插入某種「安全性」,以限制允許哪些類執行什麼操作。這通常是一個壞主意。 請解釋你爲什麼要這樣做,也許有人可以想出一個更好的解決方案的用例。 – 2009-09-30 12:41:01

+2

你在做rong – Triptych 2009-09-30 14:36:22

回答

6

假設主叫方是一個方法,則是你可以通過觀察前一幀,並挑選出從當地人self

class Reciever: 
    def themethod(self): 
     frame = sys._getframe(1) 
     arguments = frame.f_code.co_argcount 
     if arguments == 0: 
      print "Not called from a method" 
      return 
     caller_calls_self = frame.f_code.co_varnames[0] 
     thecaller = frame.f_locals[caller_calls_self] 
     print "Called from a", thecaller.__class__.__name__, "instance" 

醜陋的心裏很不舒服,但它的作品。現在爲什麼你想這樣做完全是另一個問題,我懷疑有一個更好的方法。 A的整個概念不允許調用B很可能是一個錯誤。

+2

在許多情況下失敗:調用頂層方法,在自由函數中調用方法,使用另一個名稱作爲'self'(使用'self'只是一個約定)等 – nosklo 2009-09-30 12:23:09

+0

是的。我同意傳入呼叫者是一個更好的解決方案。 – 2009-09-30 12:36:43

+1

你可以看到調用者是否有來自'frame.f_code.co_argcount'的參數並且看到'frame.f_code.co_varnames [0]'中的第一個參數的名字。 – 2009-09-30 13:28:31

4

調用者始終是A的一個實例。您在B方法中調用它的事實不會改變這一點。換句話說:Insiode B.foo,refA的一個實例,所以調用ref.foo()是調用AB不涉及該調用(它可能發生在頂層)。

唯一理智的方法是通過引用self,以便A可以檢查它是否爲B。

class A(object): 
    def foo(self, caller=None): 
     if isinstance(caller, B): 
      print "B can't call methods in A" 
     else: 
      print "Foobar" 

class B(object): 
    def foo(self, ref): ref.foo(self) 

class C(object): 
    def foo(self, ref): ref.foo(self) 

a = A(); 
B().foo(a) # Outputs "B can't call methods in A" 
C().foo(a) # Outputs "Foobar" 
a.foo()  # Outputs "Foobar" 
+0

希望透明地做到這一點。當方法數量顯着增加時,這是無法管理的。 – blakef 2009-09-30 12:05:30

+6

@blakef:我編輯了我的問題,爲什麼這是一個壞主意。通話可能發生在頂層。試圖檢測發生呼叫的地方是錯誤的設計。你應該改爲分享爲什麼在地球上**你想阻止一個類的方法在另一個類上調用方法。 – nosklo 2009-09-30 12:08:17

+0

這個問題最終變得學術化。您的解決方案是更好的方法,但我對如何在不涉及調用者代碼的情況下完成此任務感興趣。 – blakef 2009-09-30 15:44:30

0

像這樣的東西可能會滿足您的需求更好地:

class A(object): 
    def foo(self): 
     # do stuff 

class B(A): 
    def foo(self): 
     raise NotImplementedError 

class C(A): 
    pass 

...但很難不知道你想要做什麼可說的。