开发者

How can I detect if the caller passed any variables to my function in Python?

I guess the subject sounds pretty stupid, so I'll show some code:

def foo(**kwargs):
    # How can you detect the difference between (**{}) and ()?
    pass
foo(**{})
foo()

Is there any way to detect inside of foo, how the method was called?

Update 1

Because there were some comments why you possible want to do something, I'll try to explain some background.

super(MyClass开发者_如何学C, self).foo(*args, **kwargs) sucks - a lot of wasteful duplication. I want to write 'self.super()'. In this case, just call the super class and hand over all parameters that the calling method got as well. Works like a charm.

Now the problematic magic part:

I want to say 'self.super(something)' and in this case, only 'something' is passed to the super method. Works for most cases.

This is where it breaks:

def foo(self, fnord=42, *args, **kwargs):
    self.super(*args, **kwargs)

So the super method should get the arguments that the calling method - however if *args, **kwargs are empty, currently the library can not detect this condition and passed all arguments including 'fnord'...

Of course I could use self.super.foo(*args, **kwargs) as an alternative syntax but that's lame :-)

PS: Yes, I know p3k's super, but still not nice and it does not work with Python 2.x...

Update 2

Actually even Python's ast module removes the **{} (ast.parse('foo(**{})')) so it looks like this happens so early in the parsing process that you can not get this information later on...

So in the end I have either to give up on that specific problem (raising an AmbiguousSyntaxError) or to use text parsing as proposed by ~unutbu. Re-thinking my approach, the latter might actually feasable because I only need to know if it is self.super(\s*), self.super(\S+).


This hack only works with CPython.

import traceback

def foo(**kwargs):
    # stack is a list of 4-tuples: (filename, line number, function name, text)
    # see http://docs.python.org/library/traceback.html#module-traceback

    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    print('foo was called: %s'%text)

foo(**{})
# foo was called: foo(**{})
foo()
# foo was called: foo()

As an example of how this might be useful:

def pv(var):
    (filename,line_number,function_name,text)=traceback.extract_stack()[-2]
    print('%s: %s'%(text[text.find('(')+1:-1],var))

x=5
pv(x)
# x: 5

Notice that pv is called with just the value x, but it prints both the "name" of the variable (as it was called), and the value of a variable. Sometimes I use this when debugging and am too lazy to write out the full print statement.


In your update to your original question you wrote you want to be able to do something like this:

def foo(self, fnord=42, *args, **kwargs):
    self.super(*args, **kwargs)

Does this do what you want?

def foo(self, fnord=42, *args, **kwargs):
    self.super(fnord=fnord, *args, **kwargs)


So basically it is not possible to do that with the provided Python modules. I had to fall-back to plain-text regexes which work for me pretty well given the simplicity of my requirements.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜