I was hacking up a grotty (but neat!) python plugin for gdb last night, and ran into a quirk I didn’t really understand. I had a list of numbers, and was using struct to make a suitable memory buffer for gdb.selected_inferior().write_memory. Except, it wasn’t quite working….
import struct
q = [1,2,3,4]
x = struct.pack("<4H", q)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
struct.error: pack requires exactly 4 arguments |
import struct
q = [1,2,3,4]
x = struct.pack("<4H", q)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
struct.error: pack requires exactly 4 arguments
I wasn’t really expecting this, normally things “just work” and python “does the right thing” (Computer! Do as I want, not as I say!) StackOverflow gave me the gem of using the * operator.
import struct
q = [1,2,3,4]
struct.pack("<4H", *q)
'\x01\x00\x02\x00\x03\x00\x04\x00' |
import struct
q = [1,2,3,4]
struct.pack("<4H", *q)
'\x01\x00\x02\x00\x03\x00\x04\x00'
OK, well and good, but WTF?! Where did that come from? Turns out it’s not an operator per se, but part of the call syntax. So * turns a list into a string of positional arguments, and ** turns a dict into a set of keyword arguments, like so.
def gofish(where, when):
print(where, when)
gofish("lake", "tomorrow")
('lake', 'tomorrow')
gofish({"where" : "a river", "when": "next weekend"})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: gofish() takes exactly 2 arguments (1 given)
gofish(**{"where" : "a river", "when": "next weekend"})
('a river', 'next weekend') |
def gofish(where, when):
print(where, when)
gofish("lake", "tomorrow")
('lake', 'tomorrow')
gofish({"where" : "a river", "when": "next weekend"})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: gofish() takes exactly 2 arguments (1 given)
gofish(**{"where" : "a river", "when": "next weekend"})
('a river', 'next weekend')
So there, a rather esoteric corner of python I’d never seen before.