trouble to specify the self variable in if __name__ == '__main__': block - python

when i run my program i want it to run start_game(self). For that, the constructor has to be run. Without that, the objects don't exist and therefore their methods can't be run. So far, so clear. Basically, i struggle to correctly "start" that process.
from Surface import Surface
from Pellet import Pellet
from Pacman import Pacman
from Ghost import Ghost
from Timer import Timer
class Controls:
def __init__(self):
global the_surface
the_surface = Surface(self)
the_pellets = []
for y in range(0, 8):
for x in range(0, 14):
pellet = Pellet(x, y)
the_pellets.append(pellet)
global the_pacman
the_pacman = Pacman(the_pellets)
the_ghosts = []
for ghost in range(0, 3):
the_ghosts.append(Ghost())
global the_timer
the_timer = Timer(self, 200)
# [...]
def start_game(self):
self.__init_game_objects()
Timer.start(the_timer)
return
def tick_timer(self):
Pacman.move(the_pacman)
return
# http://stackoverflow.com/a/419185
if __name__ == '__main__':
# need to run start_game()
What I've tried (all of the following is after the if __name__ [...] line, every bullet point represents one trial.)
first attempt:
the_controls = Controls()
the_controls.start_game(the_controls)
Traceback (most recent call last):
File "Controls.py", line 8, in <module>
class Controls:
File "Controls.py", line 53, in Controls
the_controls = Controls()
NameError: name 'Controls' is not defined
second attempt:
__init__('Controls')
self.start_game(self)
Traceback (most recent call last):
File "Controls.py", line 8, in <module>
class Controls:
File "Controls.py", line 54, in Controls
self.start_game(self)
NameError: name 'self' is not defined
third attempt(as suggested by #TigerhawkT3)
the_controls = Controls()
the_controls.start_game()
Traceback (most recent call last):
File "Controls.py", line 8, in <module>
class Controls:
File "Controls.py", line 53, in Controls
the_controls = Controls()
NameError: name 'Controls' is not defined

It seems like you have an indentation error in your code: The if __name__ == '__main__': is defined in your class. You need to define it outside the class in the global namespace of this file/module (meaning: without indentation) if you want it to be executed while importing the file/module.

The instance itself is automatically passed. Use the following:
the_controls = Controls()
the_controls.start_game()
This is similar to other object methods you may be familiar with:
'hello world'.upper()
You could also write it like this:
the_controls = Controls()
Controls.start_game(the_controls)
Or this:
str.upper('hello world')
But the former style is preferred over the latter.

Related

How to add optional arguments in a python class?

I am trying to call different functions based on the value for rb_selection, calling func1 if rb_selection value is 0 and calling func2 if rb_selection value is 1. Both functions take a different set of arguments.
I do not need folder argument(func2 values) when I call func1 and similarly I do not need batch, term arguments(func1 values) when I call func2
It throws me the below error when I try to call the second function, as the values for batch, term are not passed.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\Himajak\Anaconda3\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "<ipython-input-13-02b5f954b815>", line 122, in tb_click
ThreadedTask(self.queue,self.batch_name,self.term_name,self.course,self.rb_selection,self.folder).start()
AttributeError: 'GUI' object has no attribute 'batch_name'
Code looks similar to this:
class class1():
def def1(self):
self.queue = queue.Queue()
ThreadedTask(self.queue,self.rb_selection,self.batch_name,self.folder).start()
#self.master.after(10, self.process_queue)
class class2():
def __init__(self, queue,rb_selection, batch_name ,term_name, folder):
threading.Thread.__init__(self)
self.queue = queue
self.rb_selection = rb_selection
self.batch = batch_name
self.term = term_name
self.folder = folder
def func1(self,batch,term):
time.sleep(5)
print("Fucntion 1 reached")
print(self.batch,self.term)
def func2(self,folder):
time.sleep(5)
print("Function 2 reached")
print(self.folder)
def run(self):
time.sleep(0) # Simulate long running process
if self.rb_selection == '0':
self.func1(self.batch,self.term)
elif self.rb_selection == '1':
self.func2(self.folder)
self.queue.put("Task finished")
Please suggest on how to resolve this issue, thanks in advance!
There is no concept of optional arguments, you can give default value when creating the function like
def __init__(self, queue,rb_selection ,term_name, folder, batch_name="default batch name"):
So that you need not pass batch_name while creating the Instance.

dictionary changed size during iteration in multithreading app

I do not know how to solve this problem:
Traceback (most recent call last): File
"/usr/local/cabinet_dev/cabinet/lib/python3.4/site-packages/eventlet/hubs/hub.py",
line 458, in fire_timers
timer() File "/usr/local/cabinet_dev/cabinet/lib/python3.4/site-packages/eventlet/hubs/timer.py",
line 58, in call
cb(*args, **kw) File "/usr/local/cabinet_dev/cabinet/lib/python3.4/site-packages/eventlet/greenthread.py",
line 218, in main
result = function(*args, **kwargs) File "./monitor.py", line 148, in caughtBridge
for call in self.active.keys(): RuntimeError: dictionary changed size during iteration
In the code below:
def caughtBridge(self):
while True:
event = self.bridgeQueue.get()
uniqueid1 = str(event.headers.get('Uniqueid1'))
uniqueid2 = str(event.headers.get('Uniqueid2'))
for call in self.active.keys():
if self.active[call]['uniqueid'] == uniqueid1:
self.active[call]['uniqueid2'] = uniqueid2
if self.active[call]['uniqueid'] == uniqueid1:
for listener in self.listeners:
for number in listener.getNumbers():
if number == self.active[call]['exten']:
if not self.active[call]['answered']:
self.sendEvent({"status": "bridge", "id": self.active[call]['uniqueid'],
"number": self.active[call]['exten']},
listener.getRoom())
self.__callInfo(self.active[call], listener.getRoom())
self.active[call]['answered'] = True
self.bridgeQueue.task_done()
Use a copy of self.active.keys(), for example:
for call in list(self.active.keys()):
Didn't see if you add or remove dict Entries?
In case of adding, the other Threads will not see the added dict Entries.
In case of removing, the current Thread will fail with Key Error,
you have to catch these.
For example:
for call in list(self.active.keys()):
<Lock that call to prevent removing>
if call in self.active:
...
self.active[call]['answered'] = True
else:
# call removed do nothing
<Unlocked that call to do whatever in other Thread>
self.bridgeQueue.task_done()
Read about Python ยป 3.6.2 Documentation: threading.html#lock-objects
Basicly implement Pair Methods self.lock(call) and self.unlock(call), for instance:
Untested Code:
To prevent Deadlocks you have to guarantee self.unlock(call) will be reached!
class xxx
def __init__....
self_lock = threading.Lock
# Init all self.active[call]['lock'] = False
def lock(self, call):
# self._lock ist class threading.Lock
# self._lock has to be the same for all Threads
with self._lock:
if call in self.active and not self.active[call]['lock']:
self.active[call]['lock'] = True
return True
else:
return False
def unlock(self, call):
with self._lock:
self.active[call]['lock'] = False
# Usage:
for call in list(self.active.keys()):
if self.lock(call):
...
self.active[call]['answered'] = True
self.unlock(call)
else:
# call removed do nothing
self.bridgeQueue.task_done()

Python get 'object is not callable' with 2 threads

When i run the code below, i got an exception
# System
import time
import logging
import sys
import os
import threading
# cv2 and helper:
import cv2
class inic_thread(threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print "Starting " + self.name
if self.counter == 1: capture_continuos()
elif self.counter == 2: face_search()
def capture_continuos():
#os.system('python capture_continuos.py')
while(1):
print 'a'
def face_search():
# atributes
pool = []
path_pool = './pool/'
while(1):
pool_get = os.listdir(path_pool)
if len(pool_get) > 0:
#print(str(len(pool_get))+' images in the pool')
for image in pool_get:
print(image)
os.system('python face_search.py -i '+str(image))
else:
print('Empty Pool')
try:
capture_continuos = inic_thread(1, "capture_continuos_1", 1)
face_search_2 = inic_thread(2, "face_search_2", 2)
capture_continuos.start()
face_search_2.start()
except:
print("Error: unable to start thread")
But it don't make sense to me, because one of the threads run normal, (face_search) but the other one give this exception.
Starting capture_continuos_1
Exception in thread capture_continuos_1:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
self.run()
File "main.py", line 44, in run
if self.counter == 1: capture_continuos()
TypeError: 'inic_thread' object is not callable
What i'm doing wrong?
I run in a Raspberry Pi 3 model B with Ubuntu MATE 14.04; Python 2.7.12
At the bottom of your script you redefine variable capture_continuos assigning thread object to it.
Also as was mentioned to terminate thread it's better to call os._exit() instead of sys.exit().

How to access global variables from a thread in Python

Consider the following code:
from threading import Thread
def main():
number = 5
class my_thread(Thread):
def __init__(self, range):
Thread.__init__(self)
self.range = range
def run(self):
global number
for i in self.range:
number += 1
t1 = my_thread(range(4))
t1.start()
t1.join()
print number
main()
The output from this program is
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Tools\Python27\lib\threading.py", line 801, in __bootstrap_inner
self.run()
File "C:\Dev\Workspace\Hello World\Hello.py", line 14, in run
number += 1
NameError: global name 'number' is not defined
5
Evidently, my_thread does not have access to number. Why is this, and how can I access it correctly?
You need to make number a global at its first definition, like this:
def main():
global number
number = 5
...etc...

gearman function in worker remains undefined

I have pretty simple code of worker, might be doing some silly mistake.
class BingWorker(object):
def __init__(self):
self.gm_worker = gearman.GearmanWorker(['localhost:4730'])
completed_job_request = self.gm_worker.register_task('bingmedia', callBing)
def callBing(self, gearman_worker, gearman_job):
print "In worker ", gearman_job.data
return "Kools"
def run(self):
self.gm_worker.work()
if __name__ == '__main__':
BingWorker().run()
gives
Traceback (most recent call last):
File "worker.py", line 16, in <module>
BingWorker().run()
File "worker.py", line 6, in __init__
completed_job_request = self.gm_worker.register_task('bingmedia', callBing)
NameError: global name 'callBing' is not defined
any hints? example is very similar to python example at http://gearman.org/examples/reverse/. just put in class structure
Improved code:
class BingWorker(object):
def __init__(self):
self.gm_worker = gearman.GearmanWorker(['localhost:4730'])
def callBing(self, gearman_worker, gearman_job):
print "In worker ", gearman_job.data
return "Kools"
def run(self):
completed_job_request = self.gm_worker.register_task('bingmedia', self.callBing)
self.gm_worker.work()
if __name__ == '__main__':
BingWorker().run()
You need to change callBing to self.callBing and it might be better to move the registration to the first line of the run method rather than the __init__ method.
The fist is because callBing is a reference to a missing global while self.callBing is a reference to the classes method. The second is because potentially you could get a call to self.callBing before init has finished which would be bad news.

Categories