Trying to access an attribute inside a nested class from in Python - python-3.x

I am trying to learn test driven development but I ran into such a silly issue and for the life of me I do not understand what is going on. I am following the book clean craftsmanship and am on the bowling example where classes get tested, this book is in java but I rather do python. Here is the example code I have written:
class BowlingGame:
def __init__(self) -> None:
self.frames = [Frame for _ in range(10)]
class Frame:
def __init__(self) -> None:
self.rolls = [Roll]
class Roll:
pass
and the test suit is:
from bowling import BowlingGame, Frame
game = BowlingGame()
def test_game_has_ten_frames():
assert len(game.frames) == 10
assert type(game.frames[0]) == type(Frame)
assert type(game.frames[9]) == type(Frame)
def test_frame_has_atleast_one_roll():
len(game.frames[0].rolls) == 1
the results give:
collected 2 items
test_bowling.py .F [100%]
===================================================================================== FAILURES ======================================================================================
__________________________________________________________________________ test_frame_has_atleast_one_roll __________________________________________________________________________
def test_frame_has_atleast_one_roll():
> len(game.frames[0].rolls) == (1)
E AttributeError: type object 'Frame' has no attribute 'rolls'
test_bowling.py:13: AttributeError
============================================================================== short test summary info ==============================================================================
FAILED test_bowling.py::test_frame_has_atleast_one_roll - AttributeError: type object 'Frame' has no attribute 'rolls'
I have tested that it is of type frame in the first test. Yet it claims that Frame doesn't have rolls but this doesn't make any sense to me as its the only attribute it has.
Can someone please explain what is happening before I lose my mind?
I have made a Frame class outside of the game and it was able to locate the rolls so I know the attribute exists. Yet when I try to access it from the game class this is when issues are occurring. What in the python is happening ?????

Related

Assigned attribute is None in a Process

Consider the following peice of code.
from multiprocessing import Process
class A(Process):
def __init__(self):
self.a = None
super(A, self).__init__()
def run(self) -> None:
self.a = 4
def print_a(self):
print(self.a)
if __name__ == '__main__':
b = A()
b.start()
b.print_a()
I want output to be :-
4
But after running the code, the output is :-
None
What am I doing wrong and how to fix it ?
My final Remarks :-
I am a noob in Python. I used to use Thread in java, and we never had such issue there. Initially, i didn't knew there is a godly class like threading in python too.
Simply put, what i wanted to do, is just the thing for which we use threading's Thread class. After using that, all my issues are fixed. The code I provided above is just a simple enact of the actual code where the shared variable is a non-Picklable class Web3 and it was giving me tons of problems with multiprocessing. It's just that my understanding and knowledge of python was shallow. I didn't realise that having a seperate memory for variables is what Process is for...

Python - can call same class twice(or more) in thread?

I don't very understand the classes logic in python but cannot answer on web.
I have create a class to generate person info:
class person:
def fristnameGen(gender):
...
def emailGen(firstname,surname):
...
i create a bot to call it like this:
from person import *
class bots:
def __init__(self):
self.person = person()
def createDB(self):
print(self.person.name)
#do something...
finally i call it by a button with thread
from bots import *
import threading
class Panel:
def __init__(self):
self.top = tk.Tk()
self.bot = bots()
self.buildUI()
def foo(self):
self.bot.createDB(self.stringPhone.get())
def threadTheAction(func, *args):
t = threading.Thread(target=func, args=args)
t.setDaemon(True)
t.start()
def buildUI(self):
Button = tk.Button(self.top, text ="Start", command = lambda :self.threadTheAction(self.foo))
I get this error:
TypeError: 'Panel' object is not callable
However, i call it directly, its work
Button = tk.Button(self.top, text ="Start", command = lambda :self.foo())
How to fix the error?
...
2. Moreover, i tried create p1 = person() and p2= person() and print it. Found p1 and p2 is a same person, i prefer each new a class have a new one. How to generate "new person" using classes?
Thank you
You seem to have a lot of confusion about Object Oriented Programming in Python. Some of your methods have self parameters and some do not, seemingly at random. That's the source of your current error.
The threadTheAction method in your Panel class is getting the Panel instance passed in as its first argument, but that's named func in the method (since you omitted self). The real function you're passing as an argument gets caught in the variable argument *args. When the thread tries unsuccessfully to call it, you get an exception. Adding self before func would fix the immediate problem:
def threadTheAction(self, func, *args):
I suspect if your code got further along, you'd run into other errors with other methods without self in their parameter lists. For instance, none of the methods you've shown in person are likely to work correctly.
As for your second question, you haven't shown enough of person to know what's happening, but you're probably doing instance variables wrong somehow. With no self parameter in the methods, that's almost inevitable (since you assign to self.whatever to set a whatever attribute on the current instance). If you need help squaring that away, I suggest you ask a separate question (Stack Overflow is best when each question is self-contained) and provide the full code for your person class.

How to better structure my classes and properties?

I am trying to programme a board game using python and object orientated programming. However, the structure of my classes and properties seems a bit tortuous even if I have made it do what I want. It doesn't seem very elegant and I'm sure it will lead to things getting too complicated and making the code hard to follow as I progress. I will try to give a simplified example of how I've structured things:
class GameState:
def __init__(self, n_players):
self.n_players = n_players
self.players = []
for player in range(self.n_players):
self.players.append(Player(player))
// other properties
// other functions
class Player:
def __init__(self, name):
self.name = name
self.building = Building()
self.workers = 3
// other properties
class Building:
def __init__(self):
self.worker = False
def action(self, player):
if self.worker == True:
player.workers += 1
But now if I want a player to use the building action I have to do something like the below. It feels like I should be able to structure things better to avoid having to pass an instance of a Player class to the Building action function.
game = GameState(4)
game.players[0].building.action(game.players[0])
The idea is that each player will have an instance of the Building class.
It's hard to suggest alternatives without knowing the exact format of your game. If each building is only ever associated with a single player at a time, I'd add that to the initialisation and reference it directly.
class Building:
def __init__(self, player):
self.worker = False
self.player = player
def action(self):
if self.worker == True:
self.player.workers += 1
Alternatively, if each player will only ever have one building associated with them, then the action function should probably be in the player class rather than the building.

Trouble working with and updating dictionary using a class and function in Python 3 [Newbie]

I am somewhat new to coding. I have been self teaching myself for the past year or so. I am trying to build a more solid foundation and am trying to create very simple programs. I created a class and am trying to add 'pets' to a dictionary that can hold multiple 'pets'. I have tried changing up the code so many different ways, but nothing is working. Here is what I have so far.
# Created class
class Animal:
# Class Attribute
classes = 'mammal'
breed = 'breed'
# Initializer/Instance Attribrutes
def __init__ (self, species, name, breed):
self.species = species
self.name = name
self.breed = breed
# To get different/multiple user input
#classmethod
def from_input(cls):
return cls(
input('Species: '),
input('Name: '),
input('Breed: ')
)
# Dictionary
pets = {}
# Function to add pet to dictionary
def createpet():
for _ in range(10):
pets.update = Animal.from_input()
if pets.name in pets:
raise ValueError('duplicate ID')
# Calling the function
createpet()
I have tried to change it to a list and use the 'append' tool and that didn't work. I am sure there is a lot wrong with this code, but I am not even sure what to do anymore. I have looked into the 'collections' module, but couldn't understand it well enough to know if that would help or not. What I am looking for is where I can run the 'createpet()' function and each time add in a new pet with the species, name, and breed. I have looked into the sqlite3 and wonder if that might be a better option. If it would be, where would I go to learn and better understand the module (aka good beginner tutorials). Any help would be appreciated. Thanks!
(First of all, you have to check for a duplicate before you add it to the dictionary.)
The way you add items to a dictionary x is
x[y] = z
This sets the value with the key y equal to z or, if there is no key with that name, creates a new key y with the value z.
Updated code:
(I defined this as a classmethod because the from_input method is one as well and from what I understand of this, this will keep things working when it comes to inheriting classes, for further information you might want to look at this)
#classmethod
def createpet(cls):
pet = cls.from_input()
if pet.name in cls.pets:
raise ValueError("duplicate ID")
else:
cls.pets[pet.name] = pet

Getting attribute error on non-attribute variable

Im working on a game and getting a strange error where instance variable isn't saved properly (as far as I can tell). This happens when i try to access self.game from the RunGame instance. By the way the classes are in separate modules, and im not showing all code. The game runs fine, but when switching level it just crashes
class RunGame(object):
def __init__(self):
self.makeTk()
self.currentLevel = 0
self.bricksLayout = [ #for debugging: a layout of bricks. 3d array with each level
[
[0,1,0,1,1,1,1,1],
[0,0,0,0,4,1,1,1],
[4,4,4,4,4,4,4,4]
],
[
[4,0,0,1,0,1,0,1],
[0,0,0,0,0,1,0,1],
[4,4,4,4,4,4,4,4]
]
]
self.game = GameInstance(self.bricksLayout,self)
self.game.run = False #this does nothing for some reason, no error though
def switchLevel(self):
print("switching level")
self.game.run = False #calling this will give no attribute error
#self.game.clearCanvas()
#self.game.canvas.destroy()
self.currentLevel+=1
#self.game = Game(self.bricksLayout,self)
def makeTk(self):
self.root = Tk()
self.root.title("PrakeOut")
self.screen_width = self.root.winfo_screenwidth(); #monitor size
self.screen_height = self.root.winfo_screenheight();
#root.wm_attributes("-fullscreen",True) #this gives fullscreen, but removes the menu
self.root.resizable(0,0) #cant be resized
self.root.configure(background="Black") #bg color of root windw
#root.geometry("%ix%i+0+0" % (SCREEN_WIDTH, SCREEN_HEIGHT)) #maximizes screen. First two are width and height, other two are x1 and y1
#root.wm_attributes("-topmost",1); #places window in foreground
run = RunGame()
class GameInstance(object):
def __init__(self, bricksLayout,gameHandler):
self.bricksLayout = bricksLayout
self.gameHandler = gameHandler
self.run = True #game loop
self.makeCanvas()
self.brickList = [] #the list of all da created bricks
self.makeBricks()
self.makeBallAndPaddle()
self.gameLoop()
self.root.mainloop(); #needs to run main loop otherwise windows doesnt show
It gives this error:
File "C:\Users\Bollen\Desktop\python projects\breakout\PythonApplication1\PythonApplication1\GameHandler.py", line 30, in switchLevel
self.game.run = False #calling this will give no attribute error
AttributeError: 'RunGame' object has no attribute 'game'
Press any key to continue . . .
We can't use your code to reproduce the problem, but there is one very obvious logic error in your code. The problem is that neither of your classes is allowed to be fully created before they are being used.
Take a look at GameInstance: because you call mainloop within the initializer, that class will never be fully instantiated until after the root window has been created and then destroyed. Therefore, any other classes which try to work with this instance will be working with a not-fully-formed instance.
Likewise, with GameRunner you are creating an instance of GameInstance. Because GameInstance calls mainloop, the creation of the GameRunner object cannot be finished before GameInstance has been created, and GameInstance won't be finished until the window is destroyed.
The first step is to remove the call to mainloop from GameInstance.__init__. Instead, move that into a method that GameRunner can call once it is fully created.
You should also separate the creation of the two objects into two steps. Your main logic would then look something like the following./ I'm not sure if you should create the runner first or the game first, but either way is acceptable depending on how you define the classes.
game = GameInstance(...)
runner = GameRunner(..., game)
runner.run()
In the above, runner.run() would look something like this:
class GameRunner(...):
def run(self):
self.game.run()
... and game.run would look like this:
class GameInstance(...):
def run(self):
self.gameLoop()
self.root.mainloop()

Resources