I dont know why i get this error and it's really annoying... anyone see the problem?
I get this error:
line 66, in <module>
ting.movefigure(ting, "up", 20)
AttributeError: 'int' object has no attribute 'movefigure'
Here is my code:
from tkinter import * import time
def movefigure(self, direction, ammount):
x = 0
y = 0
ammount2 = 0
if direction == "up":
print("Direction = " + ammount)
y = ammount
elif direction == "down":
print("Direction = " + ammount)
ammount2 = ammount - (ammount * 2)
y = ammount2
elif direction == "right" + ammount:
print("Direction = " + ammount)
x = ammount
elif direction == "left":
print("Direction = " + ammount)
ammount2 = ammount - (ammount * 2)
y = ammount2
canvas.move(self, x, y)
root = Tk()
root.title('Canvas')
tingx = 100
tingy = 100
tingxMove = 1
tingyMove = 1
canvas = Canvas(root, width=400, height=400)
ting = canvas.create_rectangle(205, 10, tingx, tingy, tags="Ting", outline='black', fill='gray50')
canvas.pack()
ting.movefigure(ting, "up", 20)
root.mainloop()
You're mixing up functions and methods.
A method is a function defined in a class; it takes a self argument, and you call it on an instance of that class. Like this:
class Spam(object):
def __init__(self, eggs):
self.eggs = eggs
def method(self, beans):
return self.eggs + beans
spam = Spam(20)
print(spam.method(10))
This will print out 30.
But your movefigure is not a method of any class, it's just a regular function. That means it doesn't take a self parameter, and you don't call it with dot syntax. (Of course there's nothing stopping you from calling any parameter self if you want, just like there's nothing stopping you from writing a function called print_with_color that erases a file named /kernel, but it's not a good idea…)
So, you wanted to do this:
def movefigure(rect, direction, ammount):
# all of your existing code, but using rect instead of self
movefigure(ting, "up", 20)
Related
I was trying to make some kind of Boxel Rebound game for the micro:bit, and I was coding at the online web editor. It all worked fine, until I tried to implement the jumping. When I start the program, it works fine, and I get my debugging messages in the REPL:
Updating...
Isn't jumping
Updating...
Isn't jumping
Updating...
Isn't jumping
...
But when I press button A, I get
Traceback (most recent call last):
File "main.py", line 57, in <module>
TypeError: 'int' object isn't callable
This is my code:
from microbit import *
def scroll(*args, **kwargs):
for arg in args:
print(arg, **kwargs)
display.scroll(arg)
#scroll('Boxel rebound')
WIDTH = 4
HEIGHT = 4
class Player:
b = 9
def __init__(self):
self.x = 1
self.y = HEIGHT
self.is_jumping = False
self.jump = 0
def update(self):
print('Updating...')
if self.is_jumping:
print(' Is jumping')
self.jump += 1
self.x += 1
else:
print(' Isn\'t jumping')
if self.y > HEIGHT:
self.y += 1
if self.jump >= 2:
self.is_jumping = False
def show(self):
display.set_pixel(
self.x,
self.y,
self.__class__.b
)
def jump(self):
if not self.is_jumping:
self.is_jumping = True
player = Player()
while True:
display.clear()
player.update()
player.show()
if button_b.get_presses() > 0:
break
elif button_a.get_presses() > 0:#button_a.is_pressed():
player.jump() # This raises the error
sleep(200)
display.clear()
In class Player you defined member variable and function named jump. When calling jump method you are trying to call an integer which is not callable type. Just carefully rename one of those two members.
Your Player Object has both an attribute and a method called jump (in your __init__ you have self.jump = 0). This is what your player.jump() is using (while you expect it to use the method) and you obviously cannot call an int as a method.
Change the name of one of the two (attribute or method) and it should work.
While practicing OOP with inheritance in my second class I have problems adding my parameters, as you can see I have: (self, name, tred, PM, PM2, ra, ra2). But when run the program it tells me that I can not multiply Nonetype, I print them to see what's wrong and i get that some of the parameters are incorrect.
The first class works fine (Atomic_d), I just need to understand how does it work the variables in the second class: Molecular_d
How can I fix this?
This is the complete code picture
import math
class Atomic_d():
def __init__(self,name="",red="",PM=None,ra=None):
self.name = name
self.red = red
self.PM = PM
self.ra = ra
def density(self):
redes = {"BCC":2,"FCC":4,"HCP":6}
self.red = self.red.upper()
nred = redes.get(self.red)
nav = round(6.022*(10**23),3)
if nred == 2:
a = (4*(self.ra))/((3)**0.5)
elif nred == 4:
a = (4*(self.ra))/((2)**0.5)
else:
per = round(12 * self.ra,3)
hipoc = round((2*self.ra)**2,3)
basec = round(self.ra**2,3)
apo = round(math.sqrt(hipoc - basec),3)
a = round((per * apo / 2),3)
if nred == 2 or nred == 4:
vol = a**3
elif nred == 6:
vol = round(a * 3.266 * self.ra,3)
density = round((((nred*self.PM)/(nav*vol))*10**21),3)
return "{} : {} g/cc".format(self.name,density)
class Molecular_d(Atomic_d):
def __init__(self,name="",tred="",PM=None,ra=None,PM2=None,ra2=None):
super().__init__(name,PM,ra)
self.PM2 = PM2
self.ra2 = ra2
self.tred = tred
def density(self):
tredes = {"NACL":8}
self.tred = self.tred.upper()
nred = tredes.get(self.tred)
nav = round(6.022*(10**23),3)
if nred == 8:
l = round(((2*self.ra)*(2*self.ra2)),3)
vol = l**3
density = ((8*(self.PM + self.PM2))/(nav*vol))
return "{}: {} g/cc".format(self.name,density)
This is the error that happens when I try to debug
I print every variable to see what is the problem
print("Hi I'm name",self.name)
print("Hi I'm ra",self.ra)
print("Hi I'm ra2",self.ra2)
print("Hi I'm PM",self.PM)
print("Hi I'm PM2",self.PM2)
Hi I'm name Ox de magnesio
Hi I'm ra None
Hi I'm ra2 0.14
Hi I'm PM 16.0
Hi I'm PM2 0.072
Traceback:
TypeError Traceback (most recent call last)
<ipython-input-21-bb7a69690a34> in <module>
1 magnesium_ox = Molecular_d("Ox de magnesio","NaCl",24.31,16.0,0.072,0.14)
2
----> 3 magnesium_ox.density()
<ipython-input-19-064f60b8cfce> in density(self)
52
53 if nred == 8:
---> 54 l = round(((2*self.ra)*(2*self.ra2)),3)
55 vol = l**3
56
TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'
When you make the call to super()_init(), you leave out the red argument. Python assumes that the three arguments you are passing are name, red, and pa, even though that's seems not to be what you intended.
When you don't attach parameter= to an argument, Python assumes you are giving them from left to right. You need to write:
super().__init__(name=name, PM=PM, ra=ra)
You need to be using keyword arguments if you are not going to put them same order as the class. Try changing the Molecular_d to this below:
class Molecular_d(Atomic_d):
def __init__(self,name="",tred="",PM=None,ra=None,PM2=None,ra2=None):
super().__init__(name=name,PM=PM,ra=ra)
self.PM2 = PM2
self.ra2 = ra2
self.tred = tred
def density(self):
tredes = {"NACL":8}
self.tred = self.tred.upper()
nred = tredes.get(self.tred)
nav = round(6.022*(10**23),3)
if nred == 8:
l = round(((2*self.ra)*(2*self.ra2)),3)
vol = l**3
else:
vol = 10
density = ((8*(self.PM + self.PM2))/(nav*vol))
return "{}: {} g/cc".format(self.name,density)
mag = Molecular_d(name="a", tred="as", PM=1.1, ra=0.2, PM2=2.3, ra2=40.1)
result = mag.density()
print(result)
<< 'a: 4.5167718365991366e-24 g/cc'
I added in a default value of vol, because i'm not sure
You have that:
class Atomic_d():
def __init__(self,name="",red="",PM=None,ra=None):
But, initialization is:
class Molecular_d(Atomic_d):
def __init__(self,name="",tred="",PM=None,ra=None,PM2=None,ra2=None):
super().__init__(name,PM,ra)
it:
super().__init__(name,PM,ra)
goes to:
def __init__(self,name="",red="",PM=None,ra=None):
as
__init__(self,name=name,red=PM,PM=ra,ra=None):
So, ra param was not initialised.
I recently started doing python. The course I was on ended with an introduction to testing with doctest. I have written a program that uses Tkinter to display widgets and it works :-) . I am using version 3.7. However, testing it is another matter. I can test simple functions and methods, but I hit difficulties when I have a function inside a method. I am pasting below a stripped-down version of what I am trying to achieve. I tried first with doctest and it threw up an error:
"AttributeError: 'function' object has no attribute 'c_square'".
# counter.py
from tkinter import *
import doctest
count = 0
delay = 1000
class MyClass:
def __init__(self, master):
master.geometry("1000x500")
master.resizable(0, 0)
master.title("Display a counter")
frame1 = Frame(master)
frame1.pack()
label1 = Label(frame1, font = ('Courier', 15 , 'bold'))
label1.grid(row = 0, column = 0)
self.my_counter(label1)
label2 = Label(frame1, font = ('Courier', 15 , 'bold'))
label2.grid(row = 0, column = 1)
self.square_of_count(label2)
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text = string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_c_square(number):
"""
>>> test_c_square(2)
4
"""
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font = ('Courier', 15 , 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
""" # main body commented out for test purposes.
root = Tk()
a = MyClass(root)
root.mainloop()
"""
doctest.testmod(verbose=True)
if __name__ == "__main__":
main()
I am using a separate test function, so that I can initialise my counter.
Then someone suggested that I try unittest, so I wrote this :
import unittest
import counter
class TestCounter(unittest.TestCase):
counter.count = 2
print("count = ", counter.count)
def square_of_count(self):
result = counter.c_square()
self.assertEqual(result, 4)
result = counter.c_square()
self.assertNotEqual(result, 3)
if __name__ == '__main__':
unittest.main()
This runs without throwing up any errors, the purpose of it is to set a value to the variable 'count' and read back the result. But I get the same response whatever value I test for, so I do not believe it is working right. I also tried variations on a theme, but I just got error messages.
Can someone please point out what I am doing wrong, I have looked about various forums and tutorials but have not seen this question asked before.
I would appreciate an answer that is easy to follow, I am asperger / dyslexic and find it difficult to learn new material. A correction with explanation would be most helpful. Thank you.
First of all, avoid this kind of nesting the functions. In your particular case I would highly suggest refactoring of a code in manner of creating some help private methods which you will call from the main ones, or even create whole new utility class:
class Util:
def _init_(self):
self.name = "Utility"
def add_two_numbers(self, first, second):
if(isinstance(first, int) and isinstance(second, int)):
return first+second
class SomeFancyClass:
def __init__(self):
self.util = Util()
self.constant = 4
# This method recursively increments a counter and displays the count.
def my_fancy_math(self, first, second):
return self.constant * self.util.add_two_numbers(first, second)
FancyVar = SomeFancyClass()
print(FancyVar.my_fancy_math(5, 6))
In case you dont want to change your code (for some reason), there is extremely dirty way to access your inner function. Again, a bit stupidly modified example made from your code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# counter.py
from tkinter import *
import doctest
import types
count = 0
delay = 1000
class MyClass:
def __init__(self, smth1):
self.something = smth1
# This method recursively increments a counter and displays the count.
def my_counter(self, lbl):
def increment_count():
global count
global delay
count += 1
string = str(count)
lbl.config(text=string)
lbl.after(delay, increment_count)
increment_count()
# This method takes the square of the counter and displays the result.
def square_of_count(self, lbl):
def test_function1(self, first, second):
return first+second
def c_square():
global count
squ = count * count
string = str(squ)
lbl.config(text=string)
lbl.after(delay, c_square)
return squ
c_square()
def test_function(self, st1):
print(st1)
def test_c_square(number):
global count
count = number
master = Tk()
frame1 = Frame(master)
label = Label(frame1, font=('Courier', 15, 'bold'))
return MyClass.square_of_count.c_square(MyClass.square_of_count.c_square)
def main():
doctest.testmod(verbose=True)
if __name__ == '__main__':
# main()
print('done')
test_function = types.FunctionType(MyClass.square_of_count.__code__.co_consts[1],
{}, None, (), ())
obj = MyClass("Hi")
sum1 = test_function("", 1, 2)
print(sum1)
Tcard.attack(self.players[self.opponent])
AttributeError: 'int' object has no attribute 'attack'
This is the error I get from calling attack().
Tcard = self.players[self.turn].returnCard()
Tcard.attack(self.players[self.opponent])
For some odd reason when Tcard.attack() calls with the parameters self.players[self.opponent], the list returns an int ranther than a Player object. Can someone please explain why it is returning an int rather than an object?
Here is the code for the whole file:
class Game():
def __init__(self):
self.players = []
self.turn = 0
self.opponent = 1
def prepare_game(self):
AI_1 = AI("AI_1", 1000)
AI_1.generate_inventory()
AI_2 = AI("AI_2", 1000)
AI_2.generate_inventory()
self.players.append(AI_1)
self.players.append(AI_2)
def start(self):
p1 = self.players[self.turn]
p2 = self.players[self.opponent]
Tcard = self.players[self.turn].returnCard()
print "Battle time"
print "%s attacked %s" % (p1.Name, p2.Name)
Tcard.attack(self.players[self.opponent])
#switch
if self.turn == 0:
self.turn = 1
self.opponent = 0
self.start()
else:
self.turn = 0
self.opponent = 1
self.start()
Here is where the function returnCard is at:
class AI():
def __init__(self, Name, Health):
self.Name = Name
self.Health = Health
self.inventory = []
def generate_inventory(self):
#Generate 6 Cards and 3 Power-ups
#rand_powerups = random.randint(min(len(powerup)), max(len(powerup)))
rand_cards = random.randint(0, 4)
#self.inventory.append(rand_powerups)
while len(self.inventory) != 4:
self.inventory.append(rand_cards)
if len(self.inventory) == 4:
break
def returnCard(self):
return self.inventory[random.randrange(0, 4)]
def returnCard(self):
return self.inventory[random.randrange(0, 4)]
returnCard returns a random item of self.inventory.
And self.inventory is filled by generate_inventory which does this:
# generate a random *INT*
rand_cards = random.randint(0, 4)
while len(self.inventory) != 4:
# append that *INT*
self.inventory.append(rand_cards)
# (note that this keeps adding the same number over and over)
So, of course, returnCard will return an int here:
Tcard = self.players[self.turn].returnCard()
So when you try to call attack you try to call it on an int:
Tcard.attack(self.players[self.opponent])
self.inventory = [] # a list
rand_cards = random.randint(0, 4)
self.inventory.append(rand_cards) # you add ints to the list
# you return an int
return self.inventory[random.randrange(0, 4)]
# you set Tcard equal to an int returned from ^^
Tcard = self.players[self.turn].returnCard()
On another note you should use range to add the random ints and keep calling randint or you will just get the same number added to your list:
def generate_inventory(self):
for _ in range(4):
self.inventory.append(random.randint(0, 4))
If you want to use the methods in your class, create an instance. I could give you an example but I have no idea where attack comes from.
First of all, Tcard becomes a variable due to this line:
Tcard = self.players[self.turn].returnCard()
By assigning Tcard the result of .returnCard() which will always be an integer since you made returnCard() to return an integer with:
return self.inventory[random.randrange(0, 4)]
So since an integer can't have any attributes, that will be an error. Thus the raised error saying that an int has no attribute.
Second, Tcard is not even a function. Only functions can have attributes thus adding more to the error. You need to create a function for Tcard to be able to work. Add something like:
class Tcard:
def attack():
#Do something
I have some code in main.py:
import pygame, char
def move(char):
#movement code
#friction
if char.xaccel == 0:
if abs(char.xvel) < char.xvelfalloff: char.xvel = 0
elif abs(char.xvel) == char.xvel: char.xvel -= char.xvelfalloff
elif abs(char.xvel) != char.xvel: char.xvel += char.xvelfalloff
#acceleration
char.xvel += char.xaccel
#max speed
if abs(char.xvel) > char.xmaxvel: char.xvel = math.copysign(char.xmaxvel,char.xvel)
#position/collision detection
char.x += char.xvel
char.xaccel = 0
char.yaccel = char.ygravity
char.yvel += char.yaccel
char.y += char.yvel
if char.y < 0: #TODO: more collision detection
char.yvel = 0
char.y = 0
char.onground = True
if char.jumping:
char.yvel = char.jumpstrength
char.jumping = False
char.onground = False
#no more movement code
charObj = char.Char()
charObj = move(charObj)
screen.blit(char.currentanimation, pygame.Rect(char.x, (screen_height-char.y)-char.height, char.width, char.height))
pygame.display.flip()
and some code in char.py:
import pygame
class Char():
spritesheet = pygame.image.load("images/spritesheet.png")
walkanim = []
for i in range(7):
spritesheet.set_clip(pygame.Rect(((sprite_width-7)*i)+3,12,sprite_width,sprite_height))
spritesheetsubsurface = spritesheet.subsurface(spritesheet.get_clip())
walkanim.append(pygame.transform.scale(spritesheetsubsurface, (width, height)))
spritesheet.set_clip(pygame.Rect(0,577,sprite_width,sprite_height))
spritesheetsubsurface = spritesheet.subsurface(spritesheet.get_clip())
idleanim = pygame.transform.scale(spritesheetsubsurface, (width, height))
lastanim = "right"
currentanimation = idleanim
animationframeindex = 0
animationframepause = 6 #how many frames go by between animation frames
animationframetime = 0 #how many frames we have been on the same animation frame
Note that I've cut out everything unrelated here.
So, I get an error when I run this code that says:
Traceback (most recent call last):
File "C:\Users\spng453\scripts\super smash feminist\main.py", line 90, in <module>
screen.blit(char.currentanimation, pygame.Rect(char_x, (screen_height-char_y)-char_height, char_width, char_height))
AttributeError: 'module' object has no attribute 'currentanimation'
I literally have no idea where I could have gone wrong here.
Any help with understanding where this problem stems from would be appreciated.
If you define a class to have an attribute (ie, self.currentanimation), you can access it like so:
charObj = char.Char()
charObj.currentanimation
What you're doing in your code is looking inside the module char, not inside your instance of Char (charObj). The char module has no attribute/variable/etc named currentanimation. But instances of Char do – or, rather, they will once you define an __init__() method in your class definition, and start using self :-)
For more on setting and accessing attributes, take a look at this section of the docs.