# Python Threading question



## lme@ (Nov 20, 2008)

Not a specific FreeBSD question, but let's see what the people around here know about Python. 

I'd like to do some threaded ssh connections with threading.Thread() and system.
To do that I wrote a function1 which connects to one host via ssh and a function2 which loops through a list of hosts and starts a thread with function1 and one host at a time as the function1's argument.
Here is where the fun comes in:
Not the hostname is given as an argument but every single character of it. So I am getting the error message that there are 8 arguments passed on to function1 instead of 1.

You can find the code snippet and the error message here:

http://bsdpaste.bsdgroup.de/1016


Any ideas anyone?


----------



## vermaden (Nov 20, 2008)

maybe that:

```
-DB_HOSTS       = ('HOST1234', 'HOST5678')
+DB_HOSTS       = ("HOST1234", "HOST5678")
```


----------



## lme@ (Nov 20, 2008)

With "" it doesn't work either.
The funny thing is that when I extend check_zip_comp(host) to check_zip_comp(foo, host) and pass args=(foo, hosts) then it works and the host is parsed correctly.


----------



## dap (Nov 20, 2008)

Could you post a more complete code that we could test ? Maybe that would help.


----------



## lme@ (Nov 20, 2008)

Okay, here it is, just c&p and run it:


```
#!/usr/bin/env python

import os
import sys
from threading import Thread

HOSTS = ('FOOBAR', 'BLAH')

def my_func(host):
	print host
	return

my_threads = []
for host in HOSTS:
	t = Thread(target=my_func, args=host)
	my_threads.append(t)
	t.start()
for thread in my_threads:
    thread.join()

sys.exit(0)
```

With syntax highlighting: http://bsdpaste.bsdgroup.de/1017


----------



## tyson (Nov 21, 2008)

Im not very good in Python, but with little searching in documentation you could make smth liek :

```
my_threads = []
for host in HOSTS:
	t = Thread(target=my_func, args=[B](host,)[/B])
	my_threads.append(t)
	t.start()
```

This is because of :


> class threading.Thread(group=None, target=None, name=None, args=(), kwargs={})
> 
> This constructor should always be called with keyword arguments. Arguments are:
> 
> ...



and the * (host,)* create one element tuple.


----------



## lme@ (Nov 21, 2008)

tyson said:
			
		

> Im not very good in Python, but with little searching in documentation you could make smth liek :
> 
> ```
> my_threads = []
> ...



Thanks a lot for the explanation! It's working now. Now I even managed to get it working with *args=[host]*.

Python is a little strange.


----------



## roddierod (Nov 26, 2008)

lme@ said:
			
		

> Thanks a lot for the explanation! It's working now. Now I even managed to get it working with *args=[host]*.
> 
> Python is a little strange.



I believe this is because [] is syntax for a list and a tuple () is an immutable list.


----------



## Djn (Nov 26, 2008)

Basically, it expects something subscriptable with a length, and a string qualifies even though that's not quite what you meant.

In python, strings implement __getitem__, __getslice__, __setitem__, __setslice__, __len__ and  __iter__, so you can treat them like a list. A side effect is that when you pass a string to something that expects a tuple or list of strings, it acts just like if you passed a list of strings of length 1. Which is why you need to construct a one-element tuple or list with the string in it when passing it to a method like this.

It's perhaps a bit odd, but it makes sense. 
(It's also an example of duck typing in action: The argument is supposed to be a list; so try using whatever we got as one. If that works, fine.)


----------

