Code Snippets of Python

strsplit

slice version

# split string/sequences in same size.
# ex, strsplit('AABBCCDD',2) -> ['AA','BB','CC','DD']
strsplit = lambda seq, size: [seq[i:i+size] for i in range(0, len(seq), size)

iter version

ref How does zip iter work in Python?

strsplit = lambda seq, size: map ( ''.join, zip( *([iter(seq)]*size) ) )

Function

static variable

>>> def foo():
    if 'a' not in foo.__dict__:
        foo.a = 0
    print foo.a
    foo.a += 1
 
>>> foo()
0
>>> foo()
1
>>> foo.a
2
>>> foo.__dict__
{'a': 2}
>>> dir(foo)
['__call__', '__class__', '__delattr__', '__dict__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'a', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']

YAML

Turning-off the Boolean interpretation

>>>  import yaml
>>> yaml.load('On')
True
>>> yaml.load('On', yaml.SafeLoader)
True
>>> yaml.load('On', yaml.BaseLoader)
u'On'

The Fraction from a Decimal

Source code:

"""
File: fract.py
Converts a decimal into an equivalent fraction.
"""
__author__ = "Jiang Yu-Kuan, yukuan.jiang(at)gmail.com"
__date__ = "2008/05/17"
__revision__ = "1.2"
 
def fract(x, bits=8, deduced=False):
    """Find p, q such that p/q ~= x and p, q < 2**bits
    """
    p, q = x, 1
    while p < 2**bits:
        if deduced:
            print "%f = %d/%d" % (round(p)/float(q), round(p), q)
        p *= 2
        q *= 2
    return int(p/2+0.5), q/2
 
if __name__ == "__main__":
    p, q = fract(3.1415926535, deduced=True)
    print "p=%d, q=%d" % (p, q)

Usage:

J:\trial\python>python -i fract.py
3.000000 = 6/2
3.250000 = 13/4
3.125000 = 25/8
3.125000 = 50/16
3.156250 = 101/32
3.140625 = 201/64
p=201, q=64
>>> from math import e, pi
>>> e
2.7182818284590451
>>> fract(e)
(174, 64)
>>> 174/64.
2.71875
>>> pi
3.1415926535897931
>>> fract(pi)
(201, 64)
>>> 201/64.
3.140625
>>>

log2 tables

log2 的 lookup tables 常用於程式最佳化,例如這篇 Super Simple Tasker 筆記 就有提到。這種表格,很適合以程式自動產生:

>>> u = [0]
>>> for x in range(8):
    u.extend([x+1]*(2**x))
 
>>> u
[0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8]

For an Analog Clock

最近(May 2008)正為手邊的消費性電子產品添加一個類比鐘,為了效率,不但捨棄浮點運算,也把一些 routine 的運算,改成查表方式。例如,其中有兩個表格,是用來把時針所在的類極座標轉換成 LCD 的類卡式座標的:

The table of a scaled sin(minute)

>>> from numpy import *
>>> scale = 127
>>> array([round(x) for x in scale*sin(arange(0, 2*pi, 2*pi/60))], dtype=int)
array([   0,   13,   26,   39,   52,   63,   75,   85,   94,  103,  110,
        116,  121,  124,  126,  127,  126,  124,  121,  116,  110,  103,
         94,   85,   75,   64,   52,   39,   26,   13,    0,  -13,  -26,
        -39,  -52,  -63,  -75,  -85,  -94, -103, -110, -116, -121, -124,
       -126, -127, -126, -124, -121, -116, -110, -103,  -94,  -85,  -75,
        -64,  -52,  -39,  -26,  -13])

The table of a scaled cos(minute)

>>> from numpy import *
>>> scale = 127
>>> array([round(x) for x in scale*cos(arange(0, 2*pi, 2*pi/60))], dtype=int)
array([ 127,  126,  124,  121,  116,  110,  103,   94,   85,   75,   64,
         52,   39,   26,   13,    0,  -13,  -26,  -39,  -52,  -63,  -75,
        -85,  -94, -103, -110, -116, -121, -124, -126, -127, -126, -124,
       -121, -116, -110, -103,  -94,  -85,  -75,  -64,  -52,  -39,  -26,
        -13,    0,   13,   26,   39,   52,   63,   75,   85,   94,  103,
        110,  116,  121,  124,  126])

Unicode

Conversion from Unicode to an encoded Latin-1

前陣子(April 2008)為了讓手邊的消費性電子產品支援多國語言,又由於市場規劃,只需要支援西歐語系,於是我就把原先的英文 OSD 訊息都抽取出來,改成依據語系來查表,並寫了個 Python 程式來把 Unicode 文字檔轉換成編碼過的 Latin-1 格式,以下是其中關鍵的幾行:

def cumsum(X):
    Y = []
    y = 0
    for x in X:
        y += x
        Y += [y]
    return Y
 
def convert(infile, outfile):
    chars = infile.read().decode("utf-8")
 
    lines = [x.rstrip() for x in chars.splitlines()]
    lines = [x for x in lines if len(x)>0 and not x.startswith('#')]
 
    #from numpy import cumsum
    ns = [0,] + [len(x) for x in lines]
    #cs = cumsum(ns) + len(lines) + 1
    cs = [x+len(lines)+1 for x in cumsum(ns)]
 
    head = "".join([chr(x) for x in cs])
    latin1 = "".join(lines).encode("Latin-1")
    padding = "\xFF"*(256-len(head)-len(latin1))
    outfile.write(head + latin1 + padding)

To swap col and row values from a file

曾有同學問我 Python 怎麼把 excel 這種表格資料的行列互換,一開始我沒想到漂亮的解法。後來才驚覺這根本是在求轉置矩陣,而在 Python 中,矩陣的轉置,可以用 zip 來達成。

Non-pythonic version:

import sys, string
lines = sys.stdin.readlines()
wordlists = []
 
for line in lines:
    words = string.split(line)
    wordlists.append(words)
 
for row in range(len(wordlists[0])):
    for col in range(len(wordlists)):
       print wordlists[col][row] + '\t',
    print

Pythonic version:

import sys, string
lines = sys.stdin.readlines()
wordlists = []
 
for line in lines:
    words = string.split(line)
    wordlists.append(words)
 
zip(*wordlists)
#map(None, *wordlists)

The struct module

import struct
data = open('bindat.dat').read()
start, stop = 0, struct.calcsize('fl')
version_number, num_bytes = struct.unpack('fl', data[start:stop])
start, stop = stop, start + struct.calcsize('B'*num_bytes)
bytes = struct.unpack('B'*num_bytes, data[start:stop])
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License