问题
Is there anyway to do something like this:
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"
Where caller in A
uses some form of introspection to determine the class of the calling method's object?
EDIT:
In the end, I put this together based on some of the suggestions:
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
It's not perfect for all the reasons supplied, but thanks for the responses: they were a big help.
回答1:
Assuming the caller is a method, then yes you can, by looking in the previous frame, and picking out self
from the locals.
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"
Üglŷ as heck, but it works. Now why you would want to do this is another question altogether, I suspect that there is a better way. The whole concept of A isn't allowed to call B is likely to be a mistake.
回答2:
The caller is always an instance of A. The fact that you're calling it inside a B method doesn't change that. In other words: Insiode B.foo
, ref
is an instance of A
, so calling ref.foo()
is a call on A
, B
is not involved on that call (it could happen top-level).
The only sane way is to pass a reference to self
so A can check if it is B or not.
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"
回答3:
Something like this may meet your needs better:
class A(object):
def foo(self):
# do stuff
class B(A):
def foo(self):
raise NotImplementedError
class C(A):
pass
...but it's difficult to say without knowing exactly what you're trying to do.
来源:https://stackoverflow.com/questions/1497683/can-python-determine-the-class-of-an-object-accessing-a-method