I am new in python and trying to figure out how to modularize my functions. My project is a unit testing framework for Restful APIs. For brevity I've simplified the code.
type_parser.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--type', help='a or b')
args = parser.parse_args()
def A(func):
def return_func():
if args.type == "b":
return func()
else:
pass
return return_func
def B(func):
def return_func():
if args.type == "a":
return func()
else:
pass
return return_func
api_funcs.py
from type_parser import *
class ApiFunctions:
#A
def login():
print "cool"
#B
def logout()
print "not cool"
main.py
from api_funcs import *
api = ApiFunctions()
def __main__():
api.login()
api.logout()
__main__()
CLI
python main.py --type=a
Outcome
Expected:
cool
Actual:
TypeError: return_func() takes no arguments
It works if I take api functions out of a class and call it straight up, but I would want to make it more abstract since there will be 3 sets of APIs
Update - I figured out the answer
class ApiFunctions:
#A
def login(self):
print "cool"
#B
def logout(self)
print "not cool"
def A(func):
def return_func(self):
if args.type == "b":
return func(self)
else:
pass
return return_func
In python the object itself has to be explicitely part of method singature.
Thus you need to write:
def login(self):
Writing self.login is kinda like ()* writing login(self). Since login() takes no argument you get an error.
(*) said kinda like, don't write it
api_funcs.py
from type_parser import *
class ApiFunctions:
#A
def login(self):
print "cool"
#B
def logout(self)
print "not cool"
Related
I have a question about parsing arguments in python. Example code below.
Class Parser:
def __init__(self):
self.args = argparse.ArgumentParser()
self.args.add_argument("--email")
self.args.add_argument("--file")
self.args.add_argument("--save")
self.args.add_argument("--time")
self.args_parsed = self.args.parse_args()
def get_email(self):
return self.args_parsed.email
def get_file(self):
return self.args_parsed.file
def get_save(self):
return self.args_parsed.save
def get_time(self):
return self.args_parsed.time
Class functions(Parser):
def __init__(self):
super().__init__()
def Function1(self):
pass
def Function2(self):
pass
def Function3(self):
pass
def Function4(self):
pass
if __name__ == '__main__':
try:
arguments = sys.argv[1:]
if "--file" in arguments:
Function1()
elif "--save" in arguments:
Function2()
elif "--email" in arguments:
Function3()
elif "--time" in arguments:
Function4()
except IndexError:
print("Invalid argument")
Basically what my question is I want to add a lot more options then I already have, and I would have to keep on continuing the if elif chain. Is there a way to reduce this to only parse the arguments the user chooses? thanks
I know that you can do something like this:
my_dict = {
"file": Function1,
"save": Function2,
"email": Function3,
"time": Function4
}
if __name__ == '__main__':
try:
arguments = sys.argv[1]
if arguments:
my_dicts[arguments]()
But how can I do that with multiple values? Thanks
Welcome to Stack Overflow! Like the other commenters have said it's difficult to help you because there's a lot of different things you could do depending on what you intend to do beyond the code you showed us. In the future, I would suggest that you read how to ask a good question
That being said, here's something that could help you:
#!/usr/bin/env python3
import argparse
def email_handler(email_argument):
print(f'The email {email_argument} has been chosen')
def file_handler(file_argument):
print('I have to do something different with this file:',
file_argument)
def save_handler(save_argument):
print('Maybe you want to save', save_argument)
def time_handler(time_argument):
print(f'We have to take time {time_argument} into account')
options_handlers = {
'email' : email_handler,
'file' : file_handler,
'save' : save_handler,
'time' : time_handler
}
parser = argparse.ArgumentParser()
for current_option in options_handlers:
parser.add_argument(f'--{current_option}')
arguments_extracted = parser.parse_args()
arguments_accessible = vars(arguments_extracted)
for (current_argument, current_value) in arguments_accessible.items():
if current_value is not None:
current_handler = options_handlers[current_argument]
current_handler(current_value)
Does that answer some of your questions?
I have a class file. Let's call it "C1.py". The sample code looks like below.
class C1(object):
def __init__(self):
self.greeting = "Hello, world!"
def M1(ans):
if ans == 1 or ans == 2:
return True
else:
return False
Now, I have another python file in the same folder, which will access the class file shown above.
from trial import C1
def getAns(class1):
while True:
ans = input("Answer: ")
if class1.M1(ans):
return ans
break
sample = C1()
print sample.greeting
ans = getAns(sample)
print ans
When I run those files, sample.greeting prints fine. Everything is fine until when the execution reaches the line "ans = getAns(C1)", which gives the error "M1() takes exactly 1 argument (2 given)".
So, where in the code should I change so that I can call that method successfully?
Note here that the above code is only the abstraction of my whole program to highlight my problem. It sounds stupid with just the code above alone. So, please, please bear with that for me.
M1 is currently defined as a method of C1, as such it needs to have an additional self argument which would be the instance of the class. I.e
class C1(object):
def __init__(self):
self.greeting = "Hello, world!"
def M1(self, ans):
if ans == 1 or ans == 2:
return True
else:
return False
In other languages such as C++ or Java the presence of self (or this) is implicit, but in python it's explicit.
alternatively if you don't want or need M1 to access C1's state you could make M1 static via #staticmethod i.e.
class C1(object):
def __init__(self):
self.greeting = "Hello, world!"
#staticmethod
def M1(ans):
if ans == 1 or ans == 2:
return True
else:
return False
I am currently looking at trying to use a callback in Python.
What I would like to do is return a value from the callback and then use this return value for conditional processing. So for example if the user enters "Y" I would like to print something to the console.
As I am new to Python the code below is as close as I can get currently but:
a) I am not sure if it is the Pythonic way of doing it
b) the correct way of doing it?
class Observable:
def subscribe(self,callback):
self.callback = callback
def fire(self):
self.callback()
class CallBackStuff:
def doCallback(self):
userInput = raw_input("Please enter Y or N?")
return userInput
if __name__ == '__main__':
s = CallBackStuff()
o = Observable()
o.subscribe(s.doCallback)
t = o.fire()
print t
The easiest way I can think of to do this in your code is to just store the input as
a variable in the CallBackStuff object. Then after you've called the call-back function, you can just access the input data from the CallBackStuff instance. Example below.
class Observable:
def subscribe(self,callback):
self.callback = callback
def fire(self):
self.callback()
class CallBackStuff:
storedInput = None # Class member to store the input
def doCallback(self):
self.storedInput = raw_input("Please enter Y or N?")
if __name__ == '__main__':
s = CallBackStuff()
o = Observable()
o.subscribe(s.doCallback)
o.fire()
print s.storedInput # Print stored input from call-back object
class Observable(object):
def __call__(self, fun):
return fun()
class Callback(object):
def docallback(self):
inp = raw_input()
return inp
if __name__ == "__main__":
print Observable()(Callback().docallback)
I am trying to use functional programming to create a dictionary containing a key and a function to execute:
myDict={}
myItems=("P1","P2","P3",...."Pn")
def myMain(key):
def ExecP1():
pass
def ExecP2():
pass
def ExecP3():
pass
...
def ExecPn():
pass
Now, I have seen a code used to find the defined functions in a module, and I need to do something like this:
for myitem in myItems:
myDict[myitem] = ??? #to dynamically find the corresponding function
So my question is, How do I make a list of all the Exec functions and then assign them to the desired item using the a dictionary? so at the end I will have myDict["P1"]() #this will call ExecP1()
My real problem is that I have tons of those items and I making a library that will handle them so the final user only needs to call myMain("P1")
I think using the inspect module, but I am not so sure how to do it.
My reason to avoid:
def ExecPn():
pass
myDict["Pn"]=ExecPn
is that I have to protect code as I am using it to provide a scripting feature within my application.
Simplify, simplify, simplify:
def p1(args):
whatever
def p2(more args):
whatever
myDict = {
"P1": p1,
"P2": p2,
...
"Pn": pn
}
def myMain(name):
myDict[name]()
That's all you need.
You might consider the use of dict.get with a callable default if name refers to an invalid function—
def myMain(name):
myDict.get(name, lambda: 'Invalid')()
(Picked this neat trick up from Martijn Pieters)
Simplify, simplify, simplify + DRY:
tasks = {}
task = lambda f: tasks.setdefault(f.__name__, f)
#task
def p1():
whatever
#task
def p2():
whatever
def my_main(key):
tasks[key]()
Not proud of it, but:
def myMain(key):
def ExecP1():
pass
def ExecP2():
pass
def ExecP3():
pass
def ExecPn():
pass
locals()['Exec' + key]()
I do however recommend that you put those in a module/class whatever, this is truly horrible.
If you are willing to add a decorator for each function, you can define a decorator which adds each function to a dictionary:
def myMain(key):
tasks = {}
def task(task_fn):
tasks[task_fn.__name__] = task_fn
#task
def ExecP1():
print(1)
#task
def ExecP2():
print(2)
#task
def ExecP3():
print(3)
#task
def ExecPn():
print(4)
tasks['Exec' + key]()
Another option is to place all the functions under a class (or in a different module) and use getattr:
def myMain(key):
class Tasks:
def ExecP1():
print(1)
def ExecP2():
print(2)
def ExecP3():
print(3)
def ExecPn():
print(4)
task = getattr(Tasks, 'Exec' + key)
task()
# index dictionary by list of key names
def fn1():
print "One"
def fn2():
print "Two"
def fn3():
print "Three"
fndict = {"A": fn1, "B": fn2, "C": fn3}
keynames = ["A", "B", "C"]
fndict[keynames[1]]()
# keynames[1] = "B", so output of this code is
# Two
You can just use
myDict = {
"P1": (lambda x: function1()),
"P2": (lambda x: function2()),
...,
"Pn": (lambda x: functionn())}
myItems = ["P1", "P2", ..., "Pn"]
for item in myItems:
myDict[item]()
This will call methods from dictionary
This is python switch statement with function calling
Create few modules as per the your requirement.
If want to pass arguments then pass.
Create a dictionary, which will call these modules as per requirement.
def function_1(arg):
print("In function_1")
def function_2(arg):
print("In function_2")
def function_3(fileName):
print("In function_3")
f_title,f_course1,f_course2 = fileName.split('_')
return(f_title,f_course1,f_course2)
def createDictionary():
dict = {
1 : function_1,
2 : function_2,
3 : function_3,
}
return dict
dictionary = createDictionary()
dictionary[3](Argument)#pass any key value to call the method
#!/usr/bin/python
def thing_a(arg=None):
print 'thing_a', arg
def thing_b(arg=None):
print 'thing_b', arg
ghetto_switch_statement = {
'do_thing_a': thing_a,
'do_thing_b': thing_b
}
ghetto_switch_statement['do_thing_a']("It's lovely being an A")
ghetto_switch_statement['do_thing_b']("Being a B isn't too shabby either")
print "Available methods are: ", ghetto_switch_statement.keys()
Often classes are used to enclose methods and following is the extension for answers above with default method in case the method is not found.
class P:
def p1(self):
print('Start')
def p2(self):
print('Help')
def ps(self):
print('Settings')
def d(self):
print('Default function')
myDict = {
"start": p1,
"help": p2,
"settings": ps
}
def call_it(self):
name = 'start'
f = lambda self, x : self.myDict.get(x, lambda x : self.d())(self)
f(self, name)
p = P()
p.call_it()
class CallByName():
def method1(self):
pass
def method2(self):
pass
def method3(self):
pass
def get_method(self, method_name):
method = getattr(self, method_name)
return method()
callbyname = CallByName()
method1 = callbyname.get_method(method_name)
```
def p1( ):
print("in p1")
def p2():
print("in p2")
myDict={
"P1": p1,
"P2": p2
}
name=input("enter P1 or P2")
myDictname
You are wasting your time:
You are about to write a lot of useless code and introduce new bugs.
To execute the function, your user will need to know the P1 name anyway.
Etc., etc., etc.
Just put all your functions in the .py file:
# my_module.py
def f1():
pass
def f2():
pass
def f3():
pass
And use them like this:
import my_module
my_module.f1()
my_module.f2()
my_module.f3()
or:
from my_module import f1
from my_module import f2
from my_module import f3
f1()
f2()
f3()
This should be enough for starters.
I am on exercise 43 doing some self-directed work in Learn Python The Hard Way. And I have designed the framework of a game spread out over two python files. The point of the exercise is that each "room" in the game has a different class. I have tried a number of things, but I cannot figure out how to use the returned value from their initial choice to advance the user to the proper "room", which is contained within a class. Any hints or help would be greatly appreciated.
Apologies for the poor code, I'm just starting out in python, but at my wit's end on this.
Here is the ex43_engine.py code which I run to start the game.
from ex43_map import *
import ex43_map
import inspect
#Not sure if this part is neccessary, generated list of all the classes (rooms) I imported from ex43_map.py, as I thought they might be needed to form a "map"
class_list = []
for name, obj in inspect.getmembers(ex43_map):
if inspect.isclass(obj):
class_list.append(name)
class Engine(object):
def __init__(self, room):
self.room = room
def play(self):
# starts the process, this might need to go inside the loop below
next = self.room
start.transportation_choice()
while True:
print "\n-------------"
# I have tried numerous things here to make it work...nothing has
start = StartRoom()
car = CarRoom()
bus = BusRoom()
train = TrainRoom()
airplane = AirplaneRoom()
terminal = TerminalRoom()
a_game = Engine("transportation_choice")
a_game.play()
And here is the ex43_map.py code
from sys import exit
from random import randint
class StartRoom(object):
def __init__(self):
pass
def transportation_choice(self):
print "\nIt's 6 pm and you have just found out that you need to get to Chicago by tomorrow morning for a meeting"
print "How will you choose to get there?\n"
print "Choices: car, bus, train, airplane"
choice = raw_input("> ")
if choice == "car":
return 'CarRoom'
elif choice == "bus":
return 'BusRoom'
elif choice == "train":
return 'TrainRoom'
elif choice == "airplane":
return 'AirplaneRoom'
else:
print "Sorry but '%s' wasn't a choice." % choice
return 'StartRoom'
class CarRoom(object):
def __init__(self):
print "Welcome to the CarRoom"
class BusRoom(object):
def __init__(self):
print "Welcome to the BusRoom"
class TrainRoom(object):
def __init__(self):
print "Welcome to the TrainRoom"
class AirplaneRoom(object):
def __init__(self):
print "Welcome to the AirplaneRoom"
class TerminalRoom(object):
def __init__(self):
self.quips = [
"Oh so sorry you died, you are pretty bad at this.",
"Too bad, you're dead buddy.",
"The end is here.",
"No more playing for you, you're dead."
]
def death(self):
print self.quips[randint(0, len(self.quips)-1)] # randomly selects one of the quips from 0 to # of items in the list and prints it
exit(1)
Instead of returning a string try returning an object, ie
if choice == "car":
return CarRoom()
It might be a good idea to make a Room class, and derive your other rooms from it.
The Room base class can then have a class variable which automatically keeps track of all instantiated rooms.
I haven't thoroughly tested the following, but hopefully it will give you some ideas:
# getters.py
try:
getStr = raw_input # Python 2.x
except NameError:
getStr = input # Python 3.x
getStr.type = str
def typeGetter(dataType):
def getter(msg):
while True:
try:
return dataType(getStr(msg))
except ValueError:
pass
getter.type = dataType
return getter
getInt = typeGetter(int)
getFloat = typeGetter(float)
getBool = typeGetter(bool)
def getOneOf(*args, **kwargs):
"""Get input until it matches an item in args, then return the item
#param *args: items to match against
#param getter: function, input-getter of desired type (defaults to getStr)
#param prompt: string, input prompt (defaults to '> ')
Type of items should match type of getter
"""
argSet = set(args)
getter = kwargs.get('getter', getStr)
prompt = kwargs.get('prompt', '> ')
print('[{0}]'.format(', '.join(args)))
while True:
res = getter(prompt)
if res in argset:
return res
.
# ex43_rooms.py
import textwrap
import random
import getters
class Room(object):
# list of instantiated rooms by name
ROOMS = {}
#classmethod
def getroom(cls, name):
"""Return room instance
If named room does not exist, throws KeyError
"""
return cls.ROOMS[name]
def __init__(self, name):
super(Room,self).__init__()
self.name = name
Room.ROOMS[name] = self
def run(self):
"""Enter the room - what happens?
Abstract base method (subclasses must override)
#retval Room instance to continue or None to quit
"""
raise NotImplementedError()
def __str__(self):
return self.name
def __repr__(self):
return '{0}({1})'.format(self.__class__.__name__, self.name)
class StartRoom(Room):
def __init__(self, name):
super(StartRoom,self).__init__(name)
def run(self):
print textwrap.dedent("""
It's 6 pm and you have just found out that you need to get to Chicago
by tomorrow morning for a meeting! How will you get there?
""")
inp = getters.getOneOf('car','bus','train','airplane')
return Room.getroom(inp)
class CarRoom(Room):
def __init__(self,name):
super(CarRoom,self).__init__(name)
class BusRoom(Room):
def __init__(self,name):
super(BusRoom,self).__init__(name)
class TrainRoom(Room):
def __init__(self,name):
super(TrainRoom,self).__init__(name)
class PlaneRoom(Room):
def __init__(self,name):
super(PlaneRoom,self).__init__(name)
class TerminalRoom(Room):
def __init__(self,name):
super(TerminalRoom,self).__init__(name)
def run(self):
print(random.choice((
"Oh so sorry you died, you are pretty bad at this.",
"Too bad, you're dead buddy.",
"The end is here.",
"No more playing for you, you're dead."
)))
return None
# create rooms (which registers them with Room)
StartRoom('start')
CarRoom('car')
BusRoom('bus')
TrainRoom('train')
PlaneRoom('airplane')
TerminalRoom('terminal')
.
# ex43.py
from ex43_rooms import Room
def main():
here = Room.getroom('start')
while here:
here = here.run()
if __name__=="__main__":
main()