blob8108 wrote:
is there a difference between lists/arrays and sets?
Yes — sets are unordered lists which can only contain unique values. They're optimised so that testing a set to see if it contains a value (using the "in" operator) is much faster. You can test this thus:
Code:
In [15]: import time In [16]: def timeit(x): start = time.time() x() end = time.time() return end - start ....: In [17]: big_list = range(2560000) In [18]: big_set = set(big_list) In [19]: timeit(lambda: 'x' in big_list) Out[19]: 0.20299482345581055 In [20]: timeit(lambda: 'x' in big_set) Out[20]: 3.0994415283203125e-06You can also do set operations, too, like union and intersection. They're pretty cool.
And symmetric_difference.
Offline
Very cool!
Offline
laser314 wrote:
Is bit art back up?
If you look at the first post, it'll answer your question.
Offline
laser314 wrote:
Then why were you talking about LSTC 2.0?
It's the old Chat.PY 2.0 server, I never built Bit Art for the old server.
Offline
blob8108: Could you add support for 'peer-name' as well..? It's format is:
peer-name anonymous
There aren't any quotes or anything. I have no idea how I haven't encountered yet (since the original Chat.py), but now it's giving me problems and I have no idea how your parser works, so I can't really do it myself (I have no idea what even yield is).
Offline
Magnie wrote:
I have no idea what even yield is
Oh good, so I'm not the only one.
Offline
ohaiderstudios wrote:
Magnie wrote:
I have no idea what even yield is
Oh good, so I'm not the only one.
Yield is how you write generators.
Rather than building and returning a list:
def get_words(sent): words = [] word = '' for char in sent: if char == ' ': words.append(word) word = '' else: word += char if word: words.append(word) return words In [6]: get_words('cheese is nice') Out[6]: ['cheese', 'is', 'nice']
...you can instead use the yield command.
def get_words(sent): word = '' for char in sent: if char == ' ': yield word word = '' else: word += char if word: yield word
Note that we no longer need the `words` list, or to explicitly return anything. When we call the function, we get back a generator, which is an iterator.
In [8]: get_words('cheese is nice')
Out[8]: <generator object get_words at 0x1053679b0>
We can treat it the same way as an iterable:
In [9]: for word in get_words('cheese is nice'):
...: print word
...:
cheese
is
nice
The difference is that the yield statement passes control back to the calling function.
def get_numbers(): print "Generator starting" for i in range(3): print "Yielding", i yield i print "Finished" print "Calling the generator" numbers = get_numbers() # returns a generator print "About to print the numbers!" for num in numbers: print "Printing", num # Outputs: Calling the generator About to print the numbers! Generator starting Yielding 0 Printing 0 Yielding 1 Printing 1 Yielding 2 Printing 2 Finished
Do you see? When you call the generator using get_numbers(), nothing actually happens yet. You see how "About to print the numbers" comes before "Generator starting" in the output? If you were building a list and returning it, the output would look more like this:
def get_numbers(): numbers = [] print "Function starting" for i in range(3): print "Appending", i numbers.append(i) print "Finished" return numbers print "Calling the function" numbers = get_numbers() # returns a generator print "About to print the numbers!" for num in numbers: print "Printing", num # Output: Calling the function Function starting Appending 0 Appending 1 Appending 2 Finished About to print the numbers! Printing 0 Printing 1 Printing 2
So as you iterate over the generator: the first time, the function will run until the first "yield" statement. Control then returns to the caller, the consumer of the generator, and it does whatever it wants with the value returned from "yield".
You can make this explicit by using .next() on the generator:
In [33]: numbers = get_numbers() In [34]: numbers.next() Generator starting Yielding 0 Out[34]: 0 In [35]: numbers.next() Yielding 1 Out[35]: 1 In [36]: numbers.next() Yielding 2 Out[36]: 2 In [37]: numbers.next() Finished --------------------------------------------------------------------------- StopIteration Traceback (most recent call last) <ipython-input-37-faef0c45dd75> in <module>() ----> 1 numbers.next() StopIteration:
As you can see, calling .next() on the generator gives you the next item each time, running the function until the next yield statement. If the function returns, you get a StopIteration exception (which is trivial to catch with a try/except).
You can make an iterator from any iterable using iter():
In [39]: iter("chicken") Out[39]: <iterator at 0x104bd0110> In [40]: chars = iter("chicken") In [41]: chars.next() Out[41]: 'c' In [42]: chars.next() Out[42]: 'h'
In fact, I think this may be something like what Python is doing internally when you use a for loop: getting an iterator from the iterable using it's __iter__() function and calling next on the iterator on each loop cycle to get the next item.
Generators are cool because they use less memory, as well as giving you slightly shorter and easier to read code (you don't have to build and return a list). And sometimes it's useful to do something with the result immediately, rather than have to wait until all of the values have been found.
If you actually want a list from your generator, not an iterable, you can just wrap the output in a call to list(): eg.
list(get_numbers()) -> [0, 1, 2]
— or whatever:
set(get_numbers())
' '.join(get_words("cheese is nice")) -> "cheese is nice"
Hopefully that makes sense — feel free to ask for further explanation
Offline
Magnie wrote:
blob8108: Could you add support for 'peer-name' as well..? It's format is:
Code:
peer-name anonymousThere aren't any quotes or anything...and I have no idea how your parser works, so I can't really do it myself
All my parser does, really, is split the input into parts. Some of the parts are quoted, and some of them are unquoted.
In [7]: thing.parse('broadcast "name with spaces" unquoted "another spacey name" short boring')
Out[7]: ['name with spaces', 'unquoted', 'another spacey name', 'short', 'boring']
The first part determines the type of the message, and then it calls the function with the name `parse_type(self, parts)`, and returns the result.
So to add a new message type, all you need to do is:
1) add it to the MSG_TYPES list; and
2) create the corresponding function (in this case, `parse_peer_name`)
Incidentally, you probably want to modify `parse_broadcast`, `parse_sensor_update`, and `parse_peer_name` to return the type of the message as well as its value. You might return `("broadcast", list(parts))`, for example, or perhaps have custom Message classes: `Broadcast(parts)`, or something. I'm not sure how you want to do this, so I've left it up to you. (Note that `parts` is a generator...)
Anyway, updated to add peer-name.
Edit: whoops, posted the private codr link
Last edited by blob8108 (2012-11-11 07:24:28)
Offline
@blob about yield:
You just confused me about the terms iterators and generators. I thought generator was like [i**2 for i in [1,2,3]] => [1,4,9], and iterator was that yield thing, whose wrapper function was __iter__().
Offline
Hardmath123 wrote:
@blob about yield:
You just confused me about the terms iterators and generators. I thought generator was like [i**2 for i in [1,2,3]] => [1,4,9], and iterator was that yield thing, whose wrapper function was __iter__().
[i**2 for it in [1, 2, 3]] is a list comprehension, whereas yield makes a generator
Last edited by nXIII (2012-11-11 10:24:14)
Offline
Hardmath123 wrote:
You just confused me about the terms iterators and generators. I thought generator was like [i**2 for i in [1,2,3]] => [1,4,9], and iterator was that yield thing, whose wrapper function was __iter__().
A generator is an iterator. A generator is a function containing yield statements.
Quoting from Stackoverflow: "iterator is a more general concept: any object whose class has a `next` method and an `__iter__` method that does `return self`."
I believe [i**2 for i in [1,2,3]] is called a "list comprehension", and returns a list. You can get a generator object back instead if you use normal brackets () rather than square ones []:
>>> (i**2 for i in [1,2,3])
<generator object <genexpr> at 0x101ba9500>
Edit: gah, beaten to it
Last edited by blob8108 (2012-11-11 10:47:45)
Offline
Ah. Thanks, guys.
Offline
Yes, thank you blob8108 and nXIII.
Offline
DigiTechs wrote:
I just finished making my bot and made my Panther crash - Do not power random exessively long numbers.
Well, I decided to swap it over to BYOB, it's a LOT better now. anyway, Is there a problem with PM? My bot can't PM people for some weird reason. It's got the % symbol, so it should be able to. Can you only PM to people who have more than a - or + symbol?
Offline
DigiTechs wrote:
DigiTechs wrote:
I just finished making my bot and made my Panther crash - Do not power random exessively long numbers.
Well, I decided to swap it over to BYOB, it's a LOT better now. anyway, Is there a problem with PM? My bot can't PM people for some weird reason. It's got the % symbol, so it should be able to. Can you only PM to people who have more than a - or + symbol?
It should be able to, though I'm afraid 2.0 is no longer really supported. :p
Offline
Magnie wrote:
DigiTechs wrote:
DigiTechs wrote:
I just finished making my bot and made my Panther crash - Do not power random exessively long numbers.
Well, I decided to swap it over to BYOB, it's a LOT better now. anyway, Is there a problem with PM? My bot can't PM people for some weird reason. It's got the % symbol, so it should be able to. Can you only PM to people who have more than a - or + symbol?
It should be able to, though I'm afraid 2.0 is no longer really supported. :p
But I thought 3.0 was broken
Offline
Magnie, just a question, how does the server handle the messages (aka broadcasts)? I'm wondering how, because I'm rebuilding my Chatbot (yet again ) in Lua (Here, if you want to look) and I have managed to connect, but not to send broadcasts.
EDIT: Just a tiny bit of re-wording - and I missed out an ending of the URL tag lol.
Last edited by DigiTechs (2012-11-23 17:52:18)
Offline
Hrmmm.. luaCURL is confusing... Here's a piece of code I use to connect to the server - I can't send and receive messages with it, though..
require( "luacurl" ) c = curl.new() c:setopt( curl.OPT_NOPROGRESS, false ) c:setopt( curl.OPT_URL, "69.164.193.192:42001" ) c:setopt( curl.OPT_CONNECTTIMEOUT, 15 ) c:setopt( curl.OPT_PROGRESSFUNCTION, function ( _, dltotal, dlnow, uptotal, upnow ) print( dltotal, dlnow, uptotal, upnow ) end) c:perform() c:close()
Kinda confusing, huh? Well, that's Lua for you
Offline
When you send a message (whether a broadcast or sensor-update) you need to add the length of the message to the beginning of the actual message.
<size: 4 bytes><msg: size bytes>
So if the message is 32 bytes long, you would put three zero bytes and then the ascii character for 32 (which is a space).
It's kind of hard to explain, but basically you are representing the length of the message in base 255.
Also: I'm working on LSTC "Green" which is why I won't be working on 2.0.
Last edited by Magnie (2012-11-23 18:32:38)
Offline
Magnie wrote:
When you send a message (whether a broadcast or sensor-update) you need to add the length of the message to the beginning of the actual message.
Code:
<size: 4 bytes><msg: size bytes>So if the message is 32 bytes long, you would put three zero bytes and then the ascii character for 32 (which is a space).
It's kind of hard to explain, but basically you are representing the length of the message in base 255.
Also: I'm working on LSTC "Green" which is why I won't be working on 2.0.
Ok. And I suppose I don't need LuaCURL anymore - as I found luasocket.
And I keep getting a 'malformed number error' when I try and use the connect function I made... Weird.
Offline
What method should I use for sending messages to the server? POST or GET? I know GET is to 'GET' somthing, but I don't really know.. And you said the messages are sent in base255? That's not good.. because I don't have a base255 plugin in my Lua installation, only Base64...
Offline