Here's what my task is:
Dependant on the "Logged In" user, they'll have different access rights and will see different menus.
I have tried using the .get()
function.
choices = {1: "| Student Details", 2: "| Student Grades", 3: "| Finance", 4:"| Staff Details", 5:"| Staff Payments"}
print(choices.get(1))
print(choices.get(4))
GIVEN OUTPUT >>
| Student Details
| Staff Details
But it will look very inefficient with all the Access Rights. Some access rights have access to different menus e.g (Access Level 1 = Menu 1 and Menu 4). So I cannot just use a for
loop to print all menus like so.
for option,num in choices.items():
print(option,num)
I've also attempted using the itemgetter() function which is available in the operator module, but I was unable of figuring out how to: 1. Print the outcome in lines, 2. Numerate the outcome in order (1,2,3)
choices = {1: "|Student Details", 2: "| Student Grades", 3: "| Finance", 4:"| Staff Details", 5:"| Staff Payments"}
print(itemgetter(3,5)(choices))
GIVEN OUTPUT >>
('| Finance', '| Staff Payments')
REQUIRED OUTPUT >>
1 | Finance
2 | Staff Payments
Here's an example of the inefficient code I have at the moment:
if user_name == "Mike":
print("-Managing Menu-")
print("1 | Staff Payments. ")
print("2 | Finance. ")
option = int(input("Option Choice (1-2): "))
while option not in range(1,2):
option = int(input("Option Choice (1-2): "))
if option == 1:
print("Welcome to Staff Payments")
elif option == 2:
print("Welcome to Finance.")
else:
print("Error.")
I'd really appreciate any feedback and help with this task.
-
\$\begingroup\$ Welcome to Code Review! Good job on your first post. \$\endgroup\$SirPython– SirPython2016年01月16日 22:54:11 +00:00Commented Jan 16, 2016 at 22:54
3 Answers 3
I'm not sure I understand your exact problem. But maybe you can simplify the code as follows:
class Menu(object):
def __init__(self, title, group_name):
self.title = title
self.group_name = group_name
class User(object):
def __init__(self, name, groups):
self.name = name
self.groups = groups
def get_menus(self, menus):
user_menus = []
for menu in menus:
if menu.group_name in self.groups:
user_menus.append(menu)
return user_menus
if __name__ == '__main__':
menus = (
Menu('Student Details', group_name='student-details'),
Menu('Student Grades', group_name='student-grades'),
Menu('Finance', group_name='finance')
)
users = (
User('mike', groups=['finance', 'student-details', 'grades']),
User('John', groups=['finance'])
)
# Actual logic
user = users[0] # mike
user_menus = user.get_menus(menus)
print('-Managing Menu-')
for index, menu in enumerate(user_menus):
print(index+1, '|', menu.title)
option = None
while option not in range(1,len(user_menus)+1):
try:
option = int(input('Choose option: '))
except ValueError:
print('Invalid option')
for index, menu in enumerate(user_menus):
if index+1 == option:
print('Welcome to', menu.title)
What we did here is created a menu object and a user object that hold all information relating to groups (access rights). In the menu definition we also give it a group name (or access name if you prefer). And then when we define the user we also set the groups that user can access (what menus it can access).
That simplifies the code and makes it so that we don't need to use if's for each user and each group (access right).
After defining all of this it's simply a matter of using user.get_menus(menus) to get the right menus for that user. Later on we loop through the options. We don't hardcode the choices (range(1,2)) but use the already existing user_menus list to know how to create the menu.
-
\$\begingroup\$ Please explain what you did to the code in addition to providing the updated code. \$\endgroup\$anon– anon2016年01月17日 03:54:32 +00:00Commented Jan 17, 2016 at 3:54
-
\$\begingroup\$ I really appreciate the effort put in as well as the explanation but right now I'm a beginner so I have no knowledge of
class *name*(object) - Never used the class command, def __init__(self, title, group_name) - Honestly no clue what self. is used for, for menu in menus: if menu.group_name in self.groups: user_menus.append(menu) return user_menus - I'll need to break the code down to get what it does
But I'll do some research on all these new functions - Sorry but if it's a "Thanks" comment but I really appreciate it ! \$\endgroup\$TwilightKillerX– TwilightKillerX2016年01月17日 18:07:04 +00:00Commented Jan 17, 2016 at 18:07
You say that using itemgetter
is better than using choices.get
, as you don't have to call get
multiple times,
however this is wrong.
If we look at itemgetter
it says that it uses __getitem__
.
Python's function get
also uses __getitem__
but allows a default value.
And so the following give the same:
print(itemgetter(3, 5)(choices))
print(tuple(map(choices.get, [3, 5])))
As you say using the above is bad, as it doesn't print things on new lines, you could use str.join
.
As you want to join each one with a newline or '\n'
.
print('\n'.join(map(choices.get, [3, 5])))
In both examples this won't give the same output as your inefficient code. As there are no numbers before the choice.
To improve your inefficient code, you could alternately make an options dictionary,
and use options.get
but with a supplied default value.
options = {
1: "Welcome to Staff Payments",
2: "Welcome to Finance"
}
print(options.get(option, "Error."))
Alternately to your current code pattern, you can make a dictionary holding users with places they are allowed to. This would be by supplying user-names, and the allowed places in a dictionary.
# Access control list
ACL = {
"Mike": [3, 5],
"Joe": [1]
}
places = ACL[user_name]
options = dict(enumerate(map(choices.get, places)))
print("-Managing Menu-")
for option, num in choices.items():
print("{} {}".format(option, num))
option = int(input("Option Choice (1-2): "))
while option not in range(1,2):
option = int(input("Option Choice (1-2): "))
if option == 1:
print("Welcome to Staff Payments")
elif option == 2:
print("Welcome to Finance.")
else:
print("Error.")
As you can see, whilst we took advantage of a new dictionary to print the allowed places,
you would still need boilerplate for all the locations.
Instead you could use str.format
to display the places, just like I did for the menu.
choices = {
1: "Student Details",
2: "Student Grades",
3: "Finance",
4: "Staff Details",
5: "Staff Payments"
}
def managing_menu(user_name):
places = ACL[user_name]
options = dict(enumerate(map(choices.get, places)))
print("-Managing Menu-")
for option, place in choices.items():
print("{} | {}".format(option, place))
option = int(input("Where do you wish to go: "))
while option not in options:
option = int(input("Where do you wish to go: "))
location = options.get(option, None)
if location is None:
print("Error.")
return
print("Welcome to {}.".format(location))
There are some other ways that you can improve the code:
don't use raw
int(input())
's instead use them with atry
andexcept
. This will cause the program to not crash if you enterFinance
, rather than2
.You also are probably calling a function after printing "Welcome to Finance", and so you would need to add that functionality to the options dictionary. (It's not hard)
You should change the place you define option to become a function, this is as you are likely to need the function in more than that one location.
With the itemgetter
you have almost done it. You just have to enumerate it and join it with the new line as separator.
print('\n'.join("%s %s" % (str(i),s) for i,s in enumerate(itemgetter(3,5)(choices),1)))
This only prints the REQUIRED OUTPUT. Joe Wallis's answer gives you the full solution.
-
\$\begingroup\$ Did research into these functions so I could understand the code, correct me if I'm wrong please. '\n'.join() - Elements of a sequenece joined by str(new line) seperator. for i,s in - i = number from enumerate, s = item from dictionary enumerate(),1 - Basicaly numerates the items got from itemgetter() beginning with 1 \$\endgroup\$TwilightKillerX– TwilightKillerX2016年01月17日 18:41:51 +00:00Commented Jan 17, 2016 at 18:41
-
\$\begingroup\$ Hi, thank you for response. I think that you understand it correctly. Just one terminology related thing. s is a value from the choices dictionary, not an item. In python terminology, item is a tuple of key and value. \$\endgroup\$user1112457– user11124572016年01月17日 19:00:08 +00:00Commented Jan 17, 2016 at 19:00
Explore related questions
See similar questions with these tags.