Passing functions as arguments - python

I know that something very basic is wrong here which I just fail to see. I'd really appreciate if somebody more experienced in Python could point out where I misunderstood things here. I post a simplified version of my code below. To trace back where the problems start, have an eye on the following:
The MainProgram, instanciated as Main = MainProgram(), has a menu (self.menu = Startmenu()) which is an instance of the Menu class. This Menu class has a list of buttons (self.buttons = [...]) - in this case only one. They are an instance of the Button class. I now need to pass the function to be triggered when the button is clicked to that instance of the Button class, so I can actually use it.
I would really be thankful to any more experienced user having a quick glance at it. I'm sure I'm failing to see something very basic. I bet I'm too tired to see it... Had only some 2 hours sleep since there's a baby in the house now :D
My code:
class MainProgram:
#Much much more code
def __init__(self):
#And so much more code here
self.menu = StartMenu()
class StartMenu:
def __init__(self):
#Much code which is not important to us here
self.buttons = [Button("d_bt_start", (100, 60)
, testfunc, "TEST-TEXT")]
class Button:
def __init__(self, image, pos = (0, 0), path = Paths.path_img
, alpha = False, func = None, args = None):
self.img_normal = helper.loadImage(path, image + "_normal.jpg", alpha)
self.img_hover = helper.loadImage(path, image + "_hover.jpg", alpha)
self.image = self.img_normal
self.pos = pos
self.x = pos[0]
self.y = pos[1]
self.width = self.x + self.image.get_width()
self.height = self.y + self.image.get_height()
self.mouseover = 0
self.func = func
self.args = args
def update(self, (mx, my)):
if (mx >= self.x and mx <= self.width and
my >= self.y and my <= self.height):
if self.mouseover == 0:
self.image = self.img_hover
self.mouseover = 1
else:
if self.mouseover == 1:
self.image = self.img_normal
self.mouseover = 0
def clicked(self, button):
if (mx >= self.x and mx <= self.width and
my >= self.y and my <= self.height):
if button == 1:
self.func(self.args)
What should happen: The main file creates an instance of the StartMenu class. In the StartMenu class we define one button as an instance of the Button class. That button should trigger the function testfunc(args) upon being clicked. This testfunction is so far just a print of the "TEST-TEXT" argument.
If I pass the function as
testfunc
then I get the following error Traceback:
Traceback (most recent call last):
File "D:\Python27\_RPG DEMO\DEMO\main.py", line 41, in <module>
Main = MainProgram()
File "D:\Python27\_RPG DEMO\DEMO\main.py", line 21, in __init__
self.menu = menus.StartMenu()
File "D:\Python27\_RPG DEMO\DEMO\menus.py", line 11, in __init__
, zztestfile.testfunc, "TESTEST")
File "D:\Python27\_RPG DEMO\DEMO\buttons.py", line 7, in __init__
self.img_normal = helper.loadImage(path, image + "_normal.jpg", alpha)
File "D:\Python27\_RPG DEMO\DEMO\helper.py", line 13, in loadImage
return pygame.image.load(os.path.join(folder, name)).convert_alpha()
File "D:\Python27\lib\ntpath.py", line 96, in join
assert len(path) > 0
TypeError: object of type 'function' has no len()
If I pass it as:
testfunc("TEST-TEXT")
it triggers but then causes the following Traceback:
TEST-TEXT
Traceback (most recent call last):
File "D:\Python27\_RPG DEMO\DEMO\main.py", line 41, in <module>
Main = MainProgram()
File "D:\Python27\_RPG DEMO\DEMO\main.py", line 21, in __init__
self.menu = menus.StartMenu()
File "D:\Python27\_RPG DEMO\DEMO\menus.py", line 11, in __init__
, testfunc("TEST-TEXT"))
File "D:\Python27\_RPG DEMO\DEMO\buttons.py", line 7, in __init__
self.img_normal = helper.loadImage(path, image + "_normal.jpg", alpha)
File "D:\Python27\_RPG DEMO\DEMO\helper.py", line 15, in loadImage
return pygame.image.load(os.path.join(folder, name)).convert()
File "D:\Python27\lib\ntpath.py", line 96, in join
assert len(path) > 0
TypeError: object of type 'NoneType' has no len()
I've gone through a few tutorials so far, but I really can't figure out where I'm misunderstanding them. I'd really appreciate any help in this!

You are passing your test function to the path argument of your Button class:
self.buttons = [Button("d_bt_start", (100, 60)
, testfunc, "TEST-TEXT")]
That's the 3rd positional argument there:
def __init__(self, image, pos = (0, 0), path = Paths.path_img
, alpha = False, func = None, args = None):
matching up with path. Use keyword arguments instead:
self.buttons = [Button("d_bt_start", (100, 60)
, func=testfunc, args="TEST-TEXT")]

Related

I am getting error while I'm creating game with Ursina(python). How can I fix it?

I'm creating FPS game with Ursina Engine (python). But I started to get a error whenever I tried to play it.
I just started coding so I don't know what I should do.
Code:
from ursina import *
from ursina.prefabs.first_person_controller import *
class Player(Entity):
def __init__(self, **kwargs):
self.controller = FirstPersonController(**kwargs)
super().__init__(parent=self.controller)
self.hand_gun = Entity(parent=self.controller.camera_pivot, scale=0.1, position=Vec3(0.7, -1, 1.5), rotation=Vec3(0, 170, 0), model='gun', Texture='M1911-RIGHT', visible=False)
self.knife = Entity(parent=self.controller.camera_pivot, scale=0.4, position=Vec3(0.7, -1, 1.5), rotation=Vec3(0, 170, 0), model='knife', Texture='knife', visible=False)
self.weapons = [self.hand_gun, self.knife]
self.current_weapon = 0
self.switch_weapons()
def switch_weapon(self):
for i, v in enumerate(self.weapons):
if i == self.current_weapon:
v.visible = True
else:
v.visible = False
def input(self, key):
try:
self.current_weapon = int(key) - 1
self.switch_weapon()
except ValueError:
pass
if key == 'scroll up':
self.current_weapon = (self.current_weapon + 1) % len(self.weapons)
self.switch_weapon()
if key == 'scroll down':
self.current_weapon = (self.current_weapon - 1) % len(self.weapons)
self.switch_weapon()
if key == 'left_mouse_down' and self.current_weapon == 0:
Bullet(model='sphere', color=color.black, scale=0.2, position=self.controller.camera_pivot.world_position, rotation=self.controller.camera_pivot.world_rotation)
def update(self):
self.controller.camera_pivot.y = 2 - held_keys['left control']
class Bullet(Entity):
def __init__(self, speed=50, lifetime = 10, **kwargs):
super().__init__(**kwargs)
self.speed = speed
self.lifetime = lifetime
self.start = time.time()
def update(self):
ray = raycast(self.world_position, self.forward, distance=self.speed*time.dt)
if not ray.hit and time.time() - self.start < self.lifetime:
self.world_position += self.forward * self.speed * time.daylight
else:
destroy(self)
app = Ursina
ground = Entity(model='plane', scale=20, texture='white_cube', texture_scale='mesh')
player = Player(position=(0,10,0))
app.run()
It's just small shooting game that I made for learning Ursina Engine
and the error message I got was:
package_folder: C:\Users\Yunwoo Chang\AppData\Roaming\Python\Python310\site-packages\ursina
asset_folder: c:\Users\Yunwoo Chang\Desktop\Tetris\Ursina Engine
Exception ignored in: <function Texture.__del__ at 0x000001E55A5129E0>
Traceback (most recent call last):
File "C:\Users\Yunwoo Chang\AppData\Roaming\Python\Python310\site-packages\ursina\texture.py", line 185, in __del__ del self._cached_image
AttributeError: _cached_image
Traceback (most recent call last):
File "c:\Users\Yunwoo Chang\Desktop\Tetris\Ursina Engine\03 - Weapons.py", line 71, in <module>
player = Player(position=(0,10,0))
File "c:\Users\Yunwoo Chang\Desktop\Tetris\Ursina Engine\03 - Weapons.py", line 6, in __init__
self.controller = FirstPersonController(**kwargs)
File "C:\Users\Yunwoo Chang\AppData\Roaming\Python\Python310\site-packages\ursina\prefabs\first_person_controller.py", line 32, in __init__
ray = raycast(self.world_position+(0,self.height,0), self.down, ignore=(self,))
File "C:\Users\Yunwoo Chang\AppData\Roaming\Python\Python310\site-packages\ursina\entity.py", line 433, in world_position
return Vec3(self.get_position(render))
NameError: name 'render' is not defined
How can I fix it?
I think it's some kind of attribute error but I don't know what to do.
You should instantiate Ursina with app = Ursina() before instantiating Entities. You're missing the ().

TypeError: unhashable type: 'list' In pyglet

So after getting inspired by code bullet to try out pyglet. Recently I have been creating many small games and simulations with it. The current one being a game is a flappy bird(Pretty sure you've all played that). So my mission is to code flappybird with pyglet today. But as usual, I fell into a problem, and even though there were many questions and answers for this problem as I was using pyglet all of the other answers weren't working.
The code I have written for the flappy bird is pretty straightforward. I have 2 classes the bird and the pipe and I render all of them using batches and groups. here:
import math, sys
import pyglet, random
from pyglet.window import key, mouse
window = pyglet.window.Window(width=335, height=540, caption="FLAPPY BIRD!")
batch = pyglet.graphics.Batch()
background = pyglet.graphics.OrderedGroup(0)
pipes = pyglet.graphics.OrderedGroup(1)
foreground = pyglet.graphics.OrderedGroup(2)
player = pyglet.graphics.OrderedGroup(3)
bg = pyglet.image.load("background.png")
background_1 = pyglet.sprite.Sprite(bg, 0, 0, batch=batch, group=background)
background_2 = pyglet.sprite.Sprite(bg, bg.width, 0, batch=batch, group=background)
base = pyglet.image.load("base.png")
base_1 = pyglet.sprite.Sprite(base, 0, 0, batch=batch, group=foreground)
base_2 = pyglet.sprite.Sprite(base, base.width, 0, batch=batch, group=foreground)
bird_image = pyglet.image.load("yellowbird-midflap.png")
bird_image.anchor_x = bird_image.width // 2
bird_image.anchor_y = bird_image.height // 2
class Bird:
def __init__(self):
self.charector = \
pyglet.sprite.Sprite(bird_image, window.width * 0.2, window.height/2, batch=batch, group=player)
self.y_speed = 0
self.rotation_vel = 0
self.alive = True
def update(self):
self.y_speed -= 0.6
self.rotation_vel += 1
self.charector.y += self.y_speed
self.charector.rotation = min(self.rotation_vel, 90)
def jump(self):
self.y_speed = 7 * 1.5
self.rotation_vel = -35
bird_image = pyglet.image.load("yellowbird-midflap.png")
class Pipe:
tp = pyglet.image.load("down-pipe.png")
bp = pyglet.image.load("pipe.png")
def __init__(self):
self.top_pipe = pyglet.sprite.Sprite(self.tp, x = window.width + 100, y = random.randint(325, 484), batch=batch, group=pipes)
self.bottom_pipe = pyglet.sprite.Sprite(self.bp, x = window.width + 100, y = self.top_pipe.y - 125 - self.bp.height, batch=batch, group=pipes)
def update(self):
self.top_pipe.x -= 3
self.bottom_pipe.x -= 3
bird = Bird()
pipes = [Pipe()]
time_created_pipe = 50
def update_char(dt):
global time_created_pipe, pipes
if bird.alive:
bird.update()
for pipe in pipes:
pipe.update()
if pipe.top_pipe.x <= -100:
pipes.remove(pipe)
if time_created_pipe <= 0:
time_created_pipe = 50
pipes.append(Pipe())
time_created_pipe -= 1
def update_bg(dt):
if bird.alive:
background_1.x -= 0.5
background_2.x -= 0.5
if background_1.x <= -bg.width:
background_1.x = bg.width
if background_2.x <= -bg.width:
background_2.x = bg.width
base_1.x -= 1.5
base_2.x -= 1.5
if base_1.x <= -base.width:
base_1.x = base.width
if base_2.x <= -base.width:
base_2.x = base.width
#window.event
def on_mouse_press(x, y, button, modifiers):
if button == mouse.LEFT:
bird.jump()
#window.event
def on_draw():
window.clear()
batch.draw()
pyglet.clock.schedule_interval(update_char, 1/60)
pyglet.clock.schedule_interval(update_bg, 1/60)
pyglet.app.run()
But the second I run the code this happens:
back (most recent call last):
File "c:\Users\Tejas&Shiva\OneDrive\Desktop\HTCODEATHON PYTHON PRACTICE\Day4\flappy bird.py", line 105, in <module>
pyglet.app.run()
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\app\__init__.py", line 107, in run
event_loop.run()
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\app\base.py", line 169, in run
timeout = self.idle()
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\app\base.py", line 239, in idle
redraw_all = self.clock.call_scheduled_functions(dt)
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\clock.py", line 292, in call_scheduled_functions
item.func(now - item.last_ts, *item.args, **item.kwargs)
File "c:\Users\Tejas&Shiva\OneDrive\Desktop\HTCODEATHON PYTHON PRACTICE\Day4\flappy bird.py", line 73, in update_char
pipes.append(Pipe())
File "c:\Users\Tejas&Shiva\OneDrive\Desktop\HTCODEATHON PYTHON PRACTICE\Day4\flappy bird.py", line 50, in __init__
self.top_pipe = pyglet.sprite.Sprite(self.tp, x = window.width + 100, y = random.randint(325, 484), batch=batch, group=pipes)
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\sprite.py", line 246, in __init__
self._create_vertex_list()
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\sprite.py", line 391, in _create_vertex_list
self._vertex_list = self._batch.add(
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\graphics\__init__.py", line 366, in add
domain = self._get_domain(False, mode, group, formats)
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\graphics\__init__.py", line 443, in _get_domain
self._add_group(group)
File "C:\Users\Tejas&Shiva\AppData\Local\Programs\Python\Python310\lib\site-packages\pyglet\graphics\__init__.py", line 468, in _add_group
if group.parent not in self.group_map:
TypeError: unhashable type: 'list'
My guess is there is a problem with the pipes list but I'm not sure why. Is there any solution to this?
The problem is that the name pipes is used twice. First is used for the OrderedGroup of pipes. In this group, the initial pipe batches are added:
pipes = pyglet.graphics.OrderedGroup(1)
However, it is then used for a list of pipes. The original group pipes is shadowed by the list of pipes and creating a new Pipe object fails:
pipes = [Pipe()]
Use different names for the group and the list. Rename list:
pipes_list = [Pipe()]
time_created_pipe = 50
def update_char(dt):
global time_created_pipe, pipes_list
if bird.alive:
bird.update()
for pipe in pipes_list:
pipe.update()
if pipe.top_pipe.x <= -100:
pipes_list.remove(pipe)
if time_created_pipe <= 0:
time_created_pipe = 50
pipes_list.append(Pipe())
time_created_pipe -= 1

Box2D. b2Body object has no attribute 'GetLinearVelocity'

I want to make a simple physical game with balls on Python using pygame and Box2D, but when I try to get the speed of the ball using a well-known method, I get this error. What might be the problem?
class Ball:
def __init__(self, x, y, radius, world, color, fric=0.3, maxspeed=20, density=0.01, restitution=0.5):
self.x = x
self.y = y
self.radius = radius
self.fric = fric
self.maxspeed = maxspeed
self.density = density
self.restitution = restitution
self.color = color
#body
self.bodyDef = box2d.b2BodyDef()
self.bodyDef.type = box2d.b2_dynamicBody
self.bodyDef.position = (x, y)
self.body = world.CreateBody(self.bodyDef)
#shape
self.sd = box2d.b2CircleShape()
self.sd.radius = radius
#fixture
self.fd = box2d.b2FixtureDef()
self.fd.shape = self.sd
#phys params
self.fd.density = density
self.fd.friction = fric
self.fd.restitution = restitution
self.body.CreateFixture(self.fd)
player = Ball(width / 3, height / 2, 30, world, (150, 150, 150))
v = player.body.GetLinearVelocity()
The Error:
Traceback (most recent call last):
File "D:\projs\box2d\bonk\main.py", line 60, in <module>
keyIsDown(pygame.key.get_pressed())
File "D:\projs\box2d\bonk\main.py", line 35, in keyIsDomn
v = player.body.GetLinearVelocity()
AttributeError: 'b2Body' Object has no attribute 'GetLinearVelocity'
screenshot of error
It looks like the GetLinearVelocity method is only available in the C library. The Python wrapper just uses linearVelocity:
v = player.body.linearVelocity
For the future, if you want to know what the variable type is and what methods\properties are available, you can use the type and dir functions:
print(type(player.body)) # class name # <class 'Box2D.Box2D.b2Body'>
print(dir(player.body)) # all methods and properties # ['ApplyAngularImpulse', 'ApplyForce',....,'linearVelocity',...]

"ValueError: Expected 2D array, got 1D array instead" when fitting data into model

I've viewed some questions regarding the same issue but none of them could help me. The problem is as it says, I'm unable to fit data into learning model.
This is the main file, which calls out the class regarding the data i use to fit in the model:
def main():
action = input(
"Choose an action:\n A - Create LinearSVC classifier\n B - Create Random Forest Classifier\n C - Create K Nearest Neighbor classifier\n -> ").upper()
loader = ImageLoader()
if action == "A":
lsvc = LinearSVC(random_state=0, tol=1e-5)
lsvc.fit(loader.hogArray(), loader.labelArray())
joblib.dump(lsvc, './LSVCmodel.pkl')
elif action == "B":
rfc = RandomForestClassifier(n_estimators=100)
rfc.fit(loader.hogArray(), loader.labelArray())
joblib.dump(rfc, './RFmodel.pkl')
elif action == "C":
knc = KNeighborsClassifier(n_neighbors=3)
knc.fit(loader.hogArray(), loader.labelArray())
joblib.dump(knc, './KNCmodel.pkl')
else:
print("That's not a valid answer")
main()
The same error occurs with all 3 models. The class that retrieves the data is written as following:
class ImageProcess:
def __init__(self, image, hog_data=None):
self.hog_data = hog_data
self.image = image
def hog_data_extractor(self):
self.hog_data = feature.hog(self.image) / 255.0
return self.hog_data
def normalize(self):
imageRead = cv2.resize(cv2.imread(self.image), (150, 150))
gaussImage = cv2.fastNlMeansDenoisingColored(imageRead, None, 10, 10, 7, 21)
self.image = cv2.Canny(gaussImage, 100, 200)
self.image = cv2.cvtColor(self.image, cv2.COLOR_GRAY2RGB)
self.image *= np.array((0, 0, 1), np.uint8)
return self.image
class ImageLoader:
def __init__(self):
self.sourcePath = "dataset/seg_train/"
self.labels = ['Buildings', 'Forest', 'Glacier', 'Mountain', 'Sea', 'Street']
self.x_train = []
self.y_train = []
def fillArray(self):
label_train = []
le = LabelEncoder()
run_time = time.time()
for scene in self.labels:
scene_path = os.path.join(self.sourcePath, scene.lower())
fileNumber = 0
scene_length = len([image for image in os.listdir(scene_path)])
for img in os.listdir(scene_path):
per = (file_number / scene_length)
arrow = '-' * int(round(per * 100) - 1) + '>'
spaces = ' ' * (100 - len(arrow))
sys.stdout.write(
"\rProgress: [{0}] {1}% -Ellapsed time: {2}".format(arrow + spaces, int(round(per * 100, 2)),
(int(time.time() - run_time))))
file_number += 1
img_path = os.path.join(scene_path, img)
process = ImageProcess(img_path)
self.x_train.append(process.hog_data_extractor())
label_train.append(str(scene_type))
self.y_train = le.fit_transform(label_train)
def hogArray(self):
return self.x_train
def labelArray(self):
return self.y_train
A side note: Previously I didn't have this ImageLoader class, and simply had the method fillArray() under main() on the previous code, and it didn't give back this error, all was working well. But due to some restrictions I have to follow I tried to transferred it into a class to be use in more other files.
Traceback (most recent call last):
File "main.py", line 35, in <module>
main()
File "main.py", line 19, in main
lsvc.fit(loader.hogArray(), loader.labelArray())
File "/home/filipe/Documents/NovaPasta/2019_20/LP_recuperacao/Trabalho_recuperacao/venv/lib/python3.6/site-packages/sklearn/svm/classes.py", line 229, in fit
accept_large_sparse=False)
File "/home/filipe/Documents/NovaPasta/2019_20/LP_recuperacao/Trabalho_recuperacao/venv/lib/python3.6/site-packages/sklearn/utils/validation.py", line 756, in check_X_y
estimator=estimator)
File "/home/filipe/Documents/NovaPasta/2019_20/LP_recuperacao/Trabalho_recuperacao/venv/lib/python3.6/site-packages/sklearn/utils/validation.py", line 552, in check_array
"if it contains a single sample.".format(array))
ValueError: Expected 2D array, got 1D array instead:
array=[].
Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample.
I've tried reshaping as its recommended in the error but it retrieves("AttributeError: 'list' object has no attribute 'reshape'") and since I didn't needed this reshape before I assumed this wasn't the solution.
Sorry if its poor coding but I'm not that much of an expert(not even close) and the time period I had to do this was very short so I just focused on getting it to work properly.
You are not calling fillArray. so the lists are empty. Try doing it at end of init function.
array=[] in error shows this.

How to convert some code Python2 to Python3.x?

I'm working with animation in my game, but I've got an error.. Can you help me pls?)
Or do I need to add all of my code?
class Animation:
def __init__(self, x, y, sprites=None, time=100):
self.x = x
self.y = y
self.sprites = sprites
self.time = time
self.work_time = 0
self.skip_frame = 0
self.frame = 0
def update(self, dt):
self.work_time += dt
self.skip_frame = self.work_time // self.time
if self.skip_frame > 0:
self.work_time = self.work_time % self.time
self.frame += self.skip_frame
if self.frame >= len(self.sprites):
self.frame = 0
def get_sprite(self):
return self.sprites[self.frame]
Traceback (most recent call last):
File "C:\Users\Zyzz\Desktop\game\bin.py", line 210, in <module>
target.update(dt)
File "C:\Users\Zyzz\Desktop\game\bin.py", line 98, in update
self.skip_frame = self.work_time // self.time
TypeError: unsupported operand type(s) for //: 'int' and 'module'
What I can see in your code it is nothing related to code in python2/python3.
Here self.time = time , time seems to be the imported module.
You are trying self.skip_frame = self.work_time // self.time where self.work_time is initialized with 0 earlier in def __init__(...)
It is trying to do operation between int(0) and a module(time) which is not acceptable.
But as per your question header if you want your code to migrate from python2.x to python3.x compatible there is a package available 2to3
You can install 2to3 using python-tools
$ 2to3 example.py
$ 2to3 -w example.py # -w for write the changes back to file

Categories

Resources