Sunday, May 31, 2009

Python type createion

Now I'm looking at Python3.0 source code.


PyTypeObject PyUnicode_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"str", /* tp_name */
sizeof(PyUnicodeObject), /* tp_size */
...(snip)...
&unicode_as_number, /* tp_as_number */
&unicode_as_sequence, /* tp_as_sequence */
&unicode_as_mapping, /* tp_as_mapping */
(hashfunc) unicode_hash, /* tp_hash*/
0, /* tp_call*/
(reprfunc) unicode_str, /* tp_str */
...(snip)...

This is a code snippet from Python3.01 unicode object implementation. tp_as_sequence is a behavior definition when the object is used as a sequence, tp_as_mapping is a behavior when used as a mapping object. unicode_as_sequence is defined like this.

static PySequenceMethods unicode_as_sequence = {
(lenfunc) unicode_length, /* sq_length */
PyUnicode_Concat, /* sq_concat */
(ssizeargfunc) unicode_repeat, /* sq_repeat */
(ssizeargfunc) unicode_getitem, /* sq_item */
0, /* sq_slice */
0, /* sq_ass_item */
0, /* sq_ass_slice */
PyUnicode_Contains, /* sq_contains */
};

unicode_repeat etc. are just a simple C function.

Another code snippet taken from bool object implementation. bool is a subtype of int. It is specified by setting PyLong_Type(i.e. int) to tp_base entry.

PyTypeObject PyBool_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"bool",
...(snip)...
&PyLong_Type, /* tp_base */
...(snip)...
};

Simple enough.


(Above code snippets are Python licensed)

Wednesday, May 27, 2009

Sunday, May 24, 2009

NRiHook

I haven't added an entry for a while so this is just a copy&paste from my hidden blog which tells you how to use Shake's NRiHook. This entry is just for telling you that I'm not dead ;)


class TamHook : public NRiHook
{
public:
TamHook(NRiNode *hNode, const NRiName &hName):NRiHook(hNode, hName){}
virtual void notify (Event e, void *n);
};

void TamHook::notify(Event e, void *n)
{
NRiSys::error("TamHook::notify called.\n");
}

TamHook* t;
NRiNode* node = NRiNode::findNode("NRiScript1.foo");
t = new TamHook(node, "tamtam");


You can see what has happened to "foo" by looking at the 'Event' object passed as an argument. Take care of memory management (Make sure you delete a hook which is not used any more) when you use it.

I tried to show an working example from one of my plugins but it was way way too complicated to copy it here. Please let me know if you happen to be interested.

Saturday, May 16, 2009

Emacs Lisp newbie

I studied (Emacs) Lisp a little bit and I got some concept of it. 'symbol' is one of them that fascinated me. It's like a Python variable, you can get its value by evaluating it, but it can also be stored in another symbol as a value. Interesting, isn't it?

While studying Lisp, I found there were some which didn't sound natural to me. 1) Dynamic scope is confusing. 2) I don't like macro. Though I understand the necessity of it, it can let you write a counter intuitive code too easily just like C. 3) And there are too many special forms, which doesn't look elegant. Do we really need setq? Maybe Having set is enough, isn't it?. Lisp is so different between variants (*) so I don't know if they are specific to Emacs lisp or common to all lisps.

(*)
They are so different that some variants have lazy evaluation and others don't!


I don't like a symbol having two values, function and value. A function is not just a value in Emacs Lisp and Common Lisp. Language designers are quite careful so there must be a reason but I don't know why they have made such a decision. In Scheme a function is just a value, which is not at all different from other values such as integer or string. If this type of simplicity is what Scheme attaches importance to, I prefer Scheme to Emacs Lisp. Simplicity rocks!

Now I can read the source code of basic Emacs major modes. But I'm still not good at writing a code yet (Is there a function in ELisp which is equivalent to range() in Python? I still don't know) I remember those days when I was a Python newbie.

If you are a Lisp master and notice I wrote something wrong please leave a comment.

Friday, May 8, 2009

Python FizzBuzz oneliner

From a comment on this blog via this blog


for i in range(1,101):print"FizzBuzz"[i*i%3*4:8--i**4%5]or i

This is mine (May, 17, 18 modified)

print '\n'.join(['Fizz'*(not i%3) + 'Buzz'*(not i%5) or str(i) for i in range(1, 101)])

I post this topic on a Python forum and a guy posted this, nice.

for x in range(100): print x%3/2*'Fizz'+x%5/4*'Buzz' or x+1

Passing more than 65536 arguments to a function

Creating a simple function with 4 arguments and it works.


>>> cmd1 = 'def f('
>>> cmd2 = cmd2[:-3]
>>> cmd2 = 'print '
>>> for i in range(0, 4):
... cmd1 += 'p' + str(i) + ', '
... cmd2 += 'p' + str(i) + ' + '
...
>>> cmd = cmd1[:-2] + "):" + cmd2[:-3]
>>> cmd
'def f(p0, p1, p2, p3):print p0 + p1 + p2 + p3'
>>> exec cmd
>>> f(1,1,1,1)
4

Let's discompile it.

>>> dis.dis(f)
1 0 LOAD_FAST 0 (p0)
3 LOAD_FAST 1 (p1)
6 BINARY_ADD
7 LOAD_FAST 2 (p2)
10 BINARY_ADD
11 LOAD_FAST 3 (p3)
14 BINARY_ADD
15 PRINT_ITEM
16 PRINT_NEWLINE
17 LOAD_CONST 0 (None)
20 RETURN_VALUE

The first number of each line is the address of the instruction(see this). You'll see LOAD_FAST takes three bytes, which means an argument is indexed in two bytes (LOAD_FAST instruction itself is one byte). So Python should be confused if we pass more than 65536 arguments. Let's create 100000 arguments and confuse it :p

>>> cmd1 = 'def f('
>>> cmd2 = 'print '
>>> for i in range(0, 100000):
... cmd1 += 'p' + str(i) + ', '
... cmd2 += 'p' + str(i) + ' + '
...
>>> cmd = cmd1[:-2] + "):" + cmd2[:-3]
>>> exec cmd
>>> f(*(1,)*100000)
100000

Why did it work? It's me who is confused...

>>> dis.dis(f)
1 0 LOAD_FAST 0 (p0)
3 LOAD_FAST 1 (p1)
6 BINARY_ADD
7 LOAD_FAST 2 (p2)
10 BINARY_ADD
11 LOAD_FAST 3 (p3)
...
262135 LOAD_FAST 65534 (p65534)
262138 BINARY_ADD
262139 LOAD_FAST 65535 (p65535)
262142 BINARY_ADD
262143 EXTENDED_ARG 1
262146 LOAD_FAST 65536L (p65536)
262149 BINARY_ADD
262150 EXTENDED_ARG 1
262153 LOAD_FAST 65537L (p65537)
262156 BINARY_ADD
262157 EXTENDED_ARG 1
...

Whoa! Python is prepared for the mean test. So clever!

May 11 added:
EXTENDED_ARG n is an instruction to tell the interpreter that it should add n*65536 to the next LOAD_FAST argument.
Related code snippet from ceval.c

case EXTENDED_ARG:
opcode = NEXTOP();
oparg = oparg<<16 | NEXTARG();
goto dispatch_opcode;

Tuesday, May 5, 2009

A wolf loves pork

Nice idea!