Wednesday, May 18, 2011

__class__ is special

>>> class Classless(object):
...    def __getattr__(self, name): raise AttributeError(name)
...
>>> Classless().__class__
<class '__main__.Classless'>
>>> c = Classless()
>>> c.__class__ = None
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __class__ must be set to new-style class, not 'NoneType' object

Monday, May 16, 2011

the keys to the kingdom

Most of the low-level guts of an operating system are only exposed to C.  Enter ctypes, part of the python standard library which allows python to call C code natively.

For example, say you are trying to access some function of open-ssl that is not exposed through the ssl module.

>>> import ctypes
>>> libssl = ctypes.cdll.LoadLibrary('libssl.so')
>>> libssl.PEM_read_bio_PrivateKey
<_FuncPtr object at 0x7fc001ba3a10>

With ctypes, your code is a full peer of C/C++ in how it can interact with the OS.

Thursday, May 5, 2011

reloading a module does not regenerate the module object

When a module is reloaded, the module object is not removed from memory.  Old data which is not overwritten will stick around.

>>> import json
>>> oldjson = json
>>> reload(json)
<module 'json' from 'C:\Python26\lib\json\__init__.pyc'>
>>> json is oldjson
True

To truly clean up modules in memory is a tricky process.

Wednesday, April 20, 2011

making dict(myobject) do something useful

>>> class T(object):
...    def __iter__(self):
...       return self.__dict__.items().__iter__()
...
>>> t = T()
>>> t.a = "cat"; t.b = "dog"
>>> dict(t)
{'a': 'cat', 'b': 'dog'}

Thursday, March 31, 2011

every string is an iterable of strings

>>> 'a'[0][0][0][0][0]
'a'
Python does not actually create a bunch of string objects when you do this.

>>> a = 'a'
>>> id(a) == id(a[0][0][0][0])
True

Thursday, March 17, 2011

Negative Integer Gotchas (mod and div)

Quick!  What are the values of these expressions: -5%100, -5/100?
If you said -5 and 0, you'd be right... if this was C or Java.
>>> print -5%100, -5/100
95 -1
Some more fun with negative modulos.
>>> 3%-1
0
>>> 3%-2
-1
>>> 3%-3
0
>>> 3%-4
-1
>>> 3%-5
-2
>>> 3%-6
-3
>>> 3%-7
-4
Why does Python have a different behavior than C, Java, Fortran et al?
The decree of the Benevolent Dictator For Life!

Monday, March 14, 2011

Local Variable Performance & dis

Local variables are faster in python.  They are accessed as offsets from a stack, rather than looked up in a hashmap.

Here is an example showing the use of local variables as a performance optimization.  http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Local_Variables

Using the dis module, we can investigate this behavior.  Note LOAD_FAST versus LOAD_DEREF.

>>> import dis
>>> def foo():
...   a = 1
...   def bar():
...      return a
...   return bar
...
>>> b = foo()
>>> dis.dis(b)
  4           0 LOAD_DEREF               0 (a)
              3 RETURN_VALUE
>>> def loc():
...    a = 1
...    return a
...
>>> dis.dis(loc)
  2           0 LOAD_CONST               1 (1)
              3 STORE_FAST               0 (a)


  3           6 LOAD_FAST                0 (a)
              9 RETURN_VALUE