This question already has answers here:
pyside connection Error "RuntimeError: Failed to connect signal clicked()"
(2 answers)
Closed 4 years ago.
I am fairly new to the concepts of OOP. I am having a hard time even wording my question. Maybe the question has been answered already, but worded differently!
I have a class called Create_Capsules(). It has two functions:
create a cube
create a sphere.
I created a class variable that appends the names of these newly created capsules.
Create Capsule Class (psuedo-code):
class Create_Capsule(object):
def __init__(self):
super(Create_Capsule, self).__init__()
self.user_capsules = []
def cube(self):
#psuedo-code
cap_name = create_cube(name='capsule_cube01')
self.user_capsules.append(cap_name)
return cap_name
def sphere(self):
#psuedo-code
cap_name = create_sphere(name='capsule_sphere01')
self.user_capsules.append(cap_name)
return cap_name
I have another UI Class that has two simple QPushButtons, Cube and Sphere.
The functions Create_Capsules().cube() and Create_Capsules().sphere() are being called from these buttons.
At the end of this process, I want to be able to query the class variable to get a list of all capsules created.
I tried to create an object of the Create_capsule class in the UI and pass that to the functions when the cube/sphere buttons are clicked.
Excerpts from the UI code:
Class toolUI(obj):
addNewBboxLabel = QLabel("Add New Capsule:")
user_capsule = Create_Capsule()
addCubeButton = QPushButton("Cube")
addCubeButton.clicked.connect(self.addCubeClicked(user_capsule))
# addCubeButton.clicked.connect(functools.partial(self.addCubeClicked), user_capsule)
addSphereButton = QPushButton("Sphere")
addSphereButton.clicked.connect(self.addSphereClicked(user_capsule))
# addSphereButton.clicked.connect(functools.partial(self.addSphereClicked), user_capsule)
def addCubeClicked(self, capsule_obj):
"""
Adds a cube to the scene
"""
user_cube = capsule_obj.cube()
print(user_cube)
print(capsule_obj.user_capsules)
def addSphereClicked(self, capsule_obj):
"""
Adds a sphere to the scene
"""
user_sphere = capsule_obj.sphere()
print(user_sphere)
print(capsule_obj.user_capsules)
On executing this, on opening the UI, a cube is being created (even without clicking the cube button in UI). And, I get this error message:
addCubeButton.clicked.connect(self.addCubeClicked(user_capsule))
RuntimeError: Failed to connect signal clicked()
I can choose to not bother about the class variable approach, and instead return the name of the capsule from the addCubeClicked() and addSphereClicked() functions, collect them in the UI and append a list there. But, that feels dirty as I don't want to clutter up my UI function with any other logic.
I feel like I am missing a key concept of OOP here.
In your toolUI class, you should wrap your code inside a method, such as __init__. You may also want to add self. to your widgets.
class toolUI(obj):
def __init__(self):
self.addNewBboxLabel = QLabel("Add New Capsule:")
self.user_capsule = Create_Capsule()
self.addCubeButton = QPushButton("Cube")
self.addCubeButton.clicked.connect(self.addCubeClicked(self.user_capsule))
self.addSphereButton = QPushButton("Sphere")
self.addSphereButton.clicked.connect(self.addSphereClicked(self.user_capsule))
Part of the reason was that your code didn't exist with an unique instance of the class, and self was not a defined variable. Placing it inside a method with a self param will define that variable for use and also allow other methods to access properties belonging to that object (e.g. self.addCubeButton).
I've got a big list (30-50) of game objects that change between 5-7 states in a sudo-sequential order that radically alters their behavior.
My initial naive approach was to give each game object a State variable and then every action command would take it through an if-else block to find the correct action corresponding to state.
Option 1 (Naive Approach)
class Bot:
def action(self):
if self.state == 1:
action1()
if condition1_to_2():
self.state = 2
elif self.state == 2:
action2()
#...
list_of_bots = [Bot(), Bot(), ...]
for bot in list_of_bots:
bot.action()
But I thought, with 50 game objects, doesn't this if-else traversing begin to take up significant time?
Couldn't I speed up performance by going straight to state's correct code?
The only way I can think of implementing this is to use inheritance (either an interface or subclasses) and make each game state of each game object its own subclass, destroying and creating a new object every time it changes state.
Option 2 (Inheritance)
class Bot:
def action(): raise NotImplementedError
class Bot1(Bot):
def action():
action1()
class Bot2(Bot):
def action():
action2()
#...
list_of_bots = [Bot1(), Bot2(), ...]
for bot in list_of_bots:
bot.action()
This way each game object wouldn't have to check what state it was in every tick of the game which saves like 300 operations per tick.
My only problem is that it feels a bit like overkill making so many new classes. Is there a more compact but equally efficient solution to this problem?
I thought a state dictionary or list (assuming those give an O(1) access time), but how can you link a list to a code block?
Option 3 (Impossible?)
class Bot:
def __init__(self):
self.action_list = [action1(), action2(), ...]
self.state = 1
def action():
self.action_list[self.state]
The solution must be done in raw python3 (no pip install).
Your Option 3 can work with function references, however I am not sure if this program structure is the best to use. But to accomplish storing a list of function references you can do so like this:
class Bot:
def __init__(self, game_map):
self.action_list = [self.action1, self.action2] # Stores function references
self.state = 1
self.game_map = game_map # Pass in game_map object that the class can use
def action(self):
self.action_list[self.state]() # Calls function reference
def action1(self):
# Does something
def action2(self):
# Does something
Edit: I added in an example of how to pass in the game_map object you mentioned in the comments. You can then use self.game_map wherever in your action functions which will be the same object your game controller is updating as long as you are modifying that map each time instead of creating a new one.
I am building a Path Planner that will help people plan a path through an RPG console game.
I want to create a table that shows each step through the stage. I have actually implemented a working version of this, however, it is seemingly awful OOP design; it breaks all sorts of principles, and I believe it is not even legitimate OOP. The problem is, clearly, that Table is a God Class.
Due to this, I have decided to rewrite it while trying to keep in mind proper OOP principles. I want to break up Table into multiple classes.
My problem is I need various objects to talk to each other. However, my solution is to always use composition. This breaks the dependency principle as well as the single responsibility principle.
Here is the main Table that will store the player's steps:
class PathTable(object):
''' A path table. '''
def __init__(self):
# table is a list of dicts, representing rows
self._table = []
#property
def table(self):
return self._table
def addStep(self, step):
''' Adds a step to the table. '''
self._table.append(step)
def rmStep(self):
''' Removes the last step from the table. '''
try:
del self._table[-1]
except:
raise IndexError('Tried to remove item from an empty table.')
Now, I have created an InputManager that is responsible for accepting and validating user input:
class InputManager(object):
''' Responsible for managing user input. '''
def __init__(self):
pass
def addFight(self, position):
''' Add a 'fight' at table[position]. '''
# table._table[position]['input'] = 'fight'
# Need to somehow edit a particular row in the Table.
However, now I do not know how I can access PathTable._table[position]. Without breaking all kinds of OO design principles.
It is frustrating, because the entire job of InputManager is to access PathTable. But I cannot use composition to place InputManager inside PathTable, because it is bad design.
What is a clean way to accomplish this?
I am a beginner, and I am trying to learn.
First add support for editing a step's row in your PathTable class:
class PathTable(object):
def __init__(self):
self._table = []
## NB : This defeats the whole point of making `_table` private
##property
#def table(self):
# return self._table
def add_step(self, step):
''' Adds a step to the table. '''
self._table.append(step)
def rm_step(self):
''' Removes the last step from the table. '''
return self._table.pop()
def update_step(self, position, key, value):
self._table[position][key] = value
Then pass a PathTable instance to your InputManager:
class InputManager(object):
''' Responsible for managing user input. '''
def __init__(self, path_table):
self._path_table = path_table
def add_fight(self, position):
''' Add a 'fight' at table[position]. '''
self._path_table.update_step(position, 'input', 'fight')
As the title says, I'm writing a Console Menu Generator in Python. I have 2 classes, Menu and Item. But I get into troubles. Here is the code:
class Menu:
def AddItem(self,item):
class Item:
def __init__(self,text,ToDoNext):
self.text=text
??????????????
self.item.append(Item())
def Show():
for i in range(len(self.item)):
print(str(i+1)+") "+str(self.item[i])+"\n")
print("0) Back\n")
option=int(input())
self.item[option].????????????
This code basically do the next:
Main=Menu()
Menu.AddItem("Open file",ToDo1)
Menu.AddItem("Save file",ToDo2)
Menu.Show()
'''1) Open file
2) Save file
0) Back
_
'''
If I write 1 and press enter should do the portion of code ToDo1, for example.
The solution that I thought is the nextone:
def ToDo1():
print("Hello, world!")
Menu.AddItem("Say Hello","ToDo1()")
and use an eval() function inside the Show().
But I'm not pretty sure this is not the correct way to do that.
I would like you to show me a better way, and if you have ever do something like that (Console Menu Generator) to share the code and see another way of doing the same.
I absolutely recommend creating a class Item, even if you only have text and function attributes!
Who knows what kind of complex logic you will need later on.
With this in mind, creating a menu would probably look something like this:
main = Menu()
main.AddItem(Item("Open", openFile))
main.AddItem(Item("Close", closeFile))
Also, on top of your text and function attributes, you should add parent attribute to the Item class. parent simply points at the parent menu of our item:
main = Menu()
# automatically calls main.AddItem(item1)
open = Item("Open", openFile, main)
# automatically sets parent to main
main.Add(Item("Close", closeFile))
Now that we know how a proper Menu and Item should work, we can start coding the classes.
Menu
This shouldn't be too hard, all we need are add_item(), remove_item() and draw() methods and a list of items.
Also it would be good to draw our menu's name, so lets add name attribute.
class Menu:
def __init__(self, name, items=None):
self.name = name
self.items = items or []
def add_item(self, item):
self.items.append(item)
if item.parent != self:
item.parent = self
def remove_item(self, item):
self.items.remove(item)
if item.parent == self:
item.parent = None
def draw(self):
print(self.label)
for item in self.items:
item.draw()
Obviously we could code much more methods and attributes for our menu, but that includes all the essential methods.
Item
Item class should be even easier, it hardly needs any methods at all.
Item obviously needs a name and a function (function will be ran when item gets activated), on top of that it has the earlier mentioned parent attribute.
We probably should create a setter for parent, which would automatically move the item under an other menu, but I'll leave that for you if you want to do it.
Also don't forget the draw()-method for item too, we must be able to draw our items the way they want to be drawn, not the way our Menu wants to draw them.
class Item:
def __init__(self, name, function, parent=None):
self.name = name
self.function = function
self.parent = parent
if parent:
parent.add_item(self) # use add_item instead of append, since who
# knows what kind of complex code you'll have
# in add_item() later on.
def draw(self):
# might be more complex later, better use a method.
print(" " + self.name)
Final thoughts
We've now finished our menu, it works and you should be able to use it as a basic menu.
However, the superior console menu would only have one class called MenuItem.
Each item's parent would be an other MenuItem (each, but the root MenuItem's of course) and the menu would look something like this when it's drawn:
[-] Root
[+] Submenu of Root
[-] An other submenu of Root
This menu runs functions, others open/close
<This menu has focus on it>
Select this menu by pressing mousedown
[+] A third submenu of Root
Where not giving function parameter would create items list and allow users to close/open the menuitem.
If function is given, it will work normally and only execute the function when selected.
To go even a step further, we would have separated MenuItem and two subclasses: ActionMenu and ContainerMenu.
But please keep in mind, this is somewhat hard to code and not for beginners. You might wanna stick with the first version I went through.
Functions can be passed around freely in Python. If you say AddItem("Say Hello", ToDo1), you pass the value ToDo1, which is a function object. You can then store it in self.function, later fish it with fn = self.item[option].function, and then call it with fn(). It's all clearer when you realize that a regular function call like do_stuff() is actually two things: first getting the function object from the variable do_stuff (which is typically a never-modified global variable), then calling this function object.
Here is a working example
usually the Class Menu part would be in another file called "myMenu" and imported with the command from myMenu import myMenu
items is an array of dictionaries. Each list item has a dictionary with two entries, "text" and "func"
The input is called as n-1 as arrays start at zero
import sys
class myMenu:
items=[]
def AddItem(self,text,function):
self.items.append({'text': text, 'func':function})
def Show(self):
c=1
for l in self.items:
print c, l['text'],"\n"
c = c +1
def Do(self,n):
self.items[n]['func']()
def clist():
print "cheeses are wensleydale and cheddar\n"
def bye():
print "bye"
sys.exit(0)
if __name__ == "__main__":
m=myMenu()
m.AddItem("cheese",clist)
m.AddItem("quit",bye)
while(True):
m.Show()
n=input("choice>")
m.Do(n-1)
If you want to have the menu items as a class instead of a dictionary, then declare the class immediately after class MyMenu, so something like this (not tested)
class myMenu:
items=[]
class Item:
func=None
text="default"
def __init__(self,t,f):
self.text=t
self.func=f
def AddItem(self,text,function):
self.items.append(Item(text,function))
for future readers! it's easy to have a python console menu using console-menu.
pip install console-menu
now, let's implement our menu
from consolemenu import *
from consolemenu.items import *
# Create the menu
menu = ConsoleMenu("Title", "Subtitle")
# Create some items
# MenuItem is the base class for all items, it doesn't do anything when selected
menu_item = MenuItem("Menu Item")
# A FunctionItem runs a Python function when selected
function_item = FunctionItem(
"Call a Python function", input, ["Enter an input"]
)
# A CommandItem runs a console command
command_item = CommandItem("Run a console command", "touch hello.txt")
# A SelectionMenu constructs a menu from a list of strings
selection_menu = SelectionMenu(["item1", "item2", "item3"])
# A SubmenuItem lets you add a menu (the selection_menu above, for example)
# as a submenu of another menu
submenu_item = SubmenuItem("Submenu item", selection_menu, menu)
# Once we're done creating them, we just add the items to the menu
menu.append_item(menu_item)
menu.append_item(function_item)
menu.append_item(command_item)
menu.append_item(submenu_item)
menu.show()
you would get a menu like this
which one of the following is considered better a design and why ?.
i have 2 classes , one for the gui components and the other is for it's events.
please put in mind that the eventClass will be implemented so many times, (sometimes to get data from an oracle databases and sometimes mysql databases )
class MainWindow:
def __init__(self):
self.myEvents = eventClass() # the class that has all the events
self.button = button # consider it a button from any gui library
self.menu = menu # menu box
def bottonEvent(self):
data = self.myEvents.buttonEvent()
self.menu.populate(data)
class eventClass:
def __init__(self):
pass
def getData(self):
return data # return data to puplate in the list
OR
class MainWindow:
def __init__(self):
self.myEvents = eventClass(self) # the class that has all the events
self.button = button # consider it a button from any gui library
self.menu = menu # menu box
def bottonEvent(self):
self.myEvents.ButtonEvent()
class eventClass:
def __init__(self,window):
pass
def ButtonEvent(self):
window.menu.populateData()
please inform me if anything was unclear
please help ,
thanks in advance
The first choice is better "decoupled": the event class needs and has no knowledge whatsoever about the window object or its menu attribute -- an excellent approach that makes the event class especially easy to unit-test in isolation without any overhead. This is especially nice if many implementations of the same interface need to exist, as you mention they do in your case.
The second choice introduces a mutual dependency -- an event object can't work without a window object, and a window object builds an event object. That may be an acceptable complication in more abstruse cases where it buys you something, but for this specific use it sounds more like an arbitrary extra difficulty without any real plus.
So, I would recommend the first form.