Python call a function by indirection - python

Windows7, Python2.7 MPD2.
I am writing a program to control MPD.
MPD has several (over 50) different functions.
Normally one would make a call in the form:
mpd_client.pause()
#or
mpd_client.playlistmove(playlist_name, old_pos, new_pos)
I want to encapsulate all the separate calls in one function so I can use a single try / except.
I am thinking I want to use some sort of lambda, and *args but I have little experience with either of those.
In the body of my program, I want to call something like this:
MPD('pause')
#or
MPD('playlistmove', playlist_name, old_pos, new_pos)
I envision my function looking something like...
def MPD(required_param, *args):
try:
mpd_client.required_param(args)
except:
...
of course, this isn't working.
Short of writing a huge switch statement and 50 different try structures, is there a way I can use lambda?
maybe something like:
lambda m=mpd_client.required_param: m(args)
but, this isn't working either.
I don't know.
Thanks, Mark.

You need to use getattr() to retrieve the actual method to call by name:
getattr(mpd_client, required_param)(*args)
(Note that you also need the * in front of the args for the function call as well, to re-expand the argument list back into separate arguments.)

what you need is object.__dict__, as in your code:
func = mpd_client.__dict__['pause']
func()
func = mpd_client.__dict__['playlistmove']
func(playlist_name, old_pos, new_pos)

Related

Is there a way to get the function parameters in the callee as the caller put it?

I want to achieve that calling foo(2*3) prints 2*3.
The reason is that I try to create a test framework for querying data files and I want to print the query statement with the assertion result.
I tried to get it work via the inspect module but I could not make it work.
In general, the answer is "no", since the value received by the function is the result of the expression 2*3, not the expression itself. However, in Python almost anything is possible if you really want it ;-)
For simple cases you could achieve this using the inspect module like this:
#!/usr/bin/env python3
import inspect
def foo(x):
context = inspect.stack()[1].code_context[0]
print(context)
def main():
foo(2 * 3)
if __name__ == '__main__':
main()
This will print:
foo(2 * 3)
It would be trivial to get the part 2 * 3 from this string using a regular expression. However, if the function call is not on a single line, or if the line contains multiple statements, this simple trick will not work properly. It might be possible with more advanced coding, but I guess your use case is to simply print the expression in a test report or something like that? If so, this solution might be just good enough.
Because the expression is evaluated before it is passed to the function, it is not possible to print out the un-evaluated expression.
However, there is a possible workaround. You can instead pass the expression as a string and evaluate it inside the function using eval(). As a simple example:
def foo(expr):
print(expr)
return(eval(expr))
Please note however that using eval is considered bad practice.
A better solution is to simply pass a string as well as the expression, such as foo(2*3, "2*3").

Why is there a syntax error in my Python function?

number=list(map(lambda x:int(x), input().split()))
first=".|."
second='-'
median=((number[0]-1)//2)+1
def Door(number[0],number[1]): # <<-- this one is resulting in a syntax error.
So I still fail to understand what is wrong with this code.
Can you please help me?
Thank you.
In this line:
def Door(...):
you are defining a function. You define a function with variables as parameters. When you call the function you pass it values.
What I think you are planning to do is first define Door() and then later call it with the values number[0] and number[1].
So begin your definition of the function like this:
def Door(a,b):
and when you want to call it, then you pass it the values number[0] and number[1], like this:
mydoor = Door(number[0],number[1])
Then, inside Door(), when your code refers to a and b, it is using the values of
number[0] and number[1]. This disconnect is so that the function can be called from different places with different parameters.
This applies even if you are defining the function just to modularize your code, and you only ever plan to call it from one place.

Appending tabs to all print statements in Python

I'm writing a Python console application, and I would like its output to be tabbed one tab over to set it apart from the command line.
Is there a single-command way to have tabs in front of all print statements without having to type each one explicitly?
Thank you!
There isn't any setting in Python to be able to do that, the easiest way would be to create a new function like so.
def printTab(*args):
args = ("\t",)+args
print(*args)
Comment on other answers:
If you let your new function take a single argument, rather than multiple arguments (using *args, you lose a lot of the functionality in the Python 3 print function.
What you'll want to do is just create an alternate print command for this specific use. It might look something like this:
from __future__ import print_function
def print_tabbed(str_to_print):
print('\t{}'.format(str_to_print))
While there may be a way to do what you ask (see this link if that's really what you want), I think it's a bad idea and you could improve a bit on this solution.
If you define a function like this :
def printWithTab("text"):
print("\t{}").format(text)
You could use this function instead.
>>>print(test)
test
>>> printWithTab("test")
test
(assuming python 3+)

Python 3: Can we avoid repeating an instance name when calling several of its methods?

I now (or so I have read) that it is not possible in Python 2.x, and can't find it for Python 3 either, but maybe I don't know how to search for it...
It easier to explain it with a simple Python example:
for i in range(11):
one_turtle.penup()
one_turtle.forward(50)
one_turtle.down()
one_turtle.forward(8)
one_turtle.up()
one_turtle.forward(8)
one_turtle.stamp()
one_turtle.forward(-66)
one_turtle.left(360/12)
I'd like to avoid repeating "one_turtle" the same way you can do in VBA, which it would result in something similar to this:
For i = 1 To 11
With one_turtle.penup()
.forward(50)
.down()
.forward(8)
.up()
.forward(8)
.stamp()
.forward(-66)
.left(360/12)
The code resulting from the With keyword is much clearer and easy to write and read (it'll need an End With and a Next lines but I wanted to focus the discussion). One of the main reasons I have decided to learn Python is because it is said to be very neat and "zen-like" to program. Is it really not possible to do this?
In your definition of all these member-methods, simply return self.
eg. Change definition of penup() like this:
def penup(self):
# Your logic
return self
The ideal solution is I think already posted, returning self is simply the cleanest way. However if you're not able to edit the turtle object or whatever, you can create an alias:
forward = one_turtle.forward
... some code ...
forward()
Now the function forward just applies forward to one_turtle, simple example
s = "abc"
x = s.upper
print(x()) # prints "ABC"

Alternative way to use getattr in python?

I am trying to call a object functions which also allows several different function to be called through same object :
for eg: sort(), facet(),exclude() are different functions with their
arguments and sort_flag, facet_flag and exclude_flag as condition set to true or false
can be called as:
si = sunburnt.SolrInterface("url","schema.xml")
response = si.query(arg1).facet(arg2).sort(arg3).exclude(arg4)
There can be certaing cases when I dont need to call all of these functions at same time or may be I dont have all the arguments to call these functions or vice versa. In that situtation how can I call si.facet(args).sort(args) something like this:
if sort_flag:
--append sort function to the query
if exclude_flag:
-- append exclude function
There can be alternative to do that using getattr but its confusing to use it using arguments of function and at same time it may generate lot of if check statements (for 3 flags close to 3 factorial statements)
I'm not sure I understood you, but can't you do this?
si = sunburnt.SolrInterface("url","schema.xml")
query = si.query(arg1).facet(arg2)
if sort_flag:
query = query.sort(arg3)
if exclude_flag:
query = query.exclude(arg4)
response = query.execute()

Categories