無為閣

不及格學士後研究

Binding and Assignment

所謂的 Functional Language 的變數不可改其實是不精確的。實際上它只是將變數分的更嚴謹,可修改,與不可修改。

先來說說什麼是 Binding. Binding 指的是將一個符號綁定在一個值,綁定後就不可修改,這個符號稱之為變數。以自然語言來理解的話,其實就是代名詞。

favonia: 一個變數沒有指到一個值。一個變數可以被一個值取代,但不會儲存什麼內容在裡面。

所以說下面這個例子, 必須理解為3.14的另一個稱呼叫做 PI, 而不是 PI 這個容器的值是 3.14。而 1 + PI 這個式子的另一個稱呼是 result, 而不是 1 + PI 運算後,將值放到 result 這個容器裡。 不管是PI,還是 result 都只是個代稱,而不是容器。

1
2
PI = 3.14
result = 1.0 + PI

接下來搭配 SML 來解釋什麼是 Assignment。 下面這段 code 是說 PI 是 3.14的binding, result 是 1 + PI 的binding。 程式執行時(runtime) 會把 PI 這個變數代換成3.14。

1
2
val PI = 3.14
val result = 1.0 + PI

那如果需要可修改的變數怎麼辦,SML 可以讓變數綁在值的的指標上, ref 3.14 指的是 3.14 這個值得指標指標。而因為指標指定的值是可以變的,所以現在 PI 可以當成是可以修改的。 PI := 4 只是讓 PI 的值(也就是指標) 從 3.14 指到 4,並不會產生新的binding。

1
2
3
val PI = ref 3.14 # binding
val result = 1.0 + PI # binding
val PI := 4 # assign

因此,在所有的 imperative language 裡,不管是Python, Ruby, C, Java, 變數其實都是被綁在指標上,這樣變數指到的值才能被修改。

所以說,變數只是個值的代稱,如果值是指標,那麼就可以修改指標要指到哪個 值,反之則不行。 但不管怎麼說,變數都不應該被當成是一個容器。

台南SA10月份 - Be Pythonic

好幾年答應CYJ在SA講一場,結果到了他退伍後我都沒講過一次 XD 這次透過CYJ,而有機會在台南SA分享, 簡報呢,一樣是依照慣例在演講前晚開 始趕工, 結果大綱跟之前宣傳的完全不一樣。

為什麼會這樣呢? 我想主要是之前列的大綱還是太過highlevel, 所以我很難將 他轉成簡報, 後來我在網路上找到一份CC license 的投影片,便以之為基底製 作.

由於沒講過3小時的Talk, 所以很怕講不到三小時,因此投影片弄到快100張,結 果當天講到2/3,且第二段的decorator幾乎是用帶過去的。

後來Jserv 跟我分享了一下演講的技巧,其實我簡報可以不用這麼多,只需要列 出當天要講的大綱,之後在臨場發揮就可以了。

anyway, 附上投影片,這次的主題是 Be Pythonic, 主要是說明寫python時,怎 樣會比較像在寫python,而不是其他語言。

PyCon.JP 2012

今年一樣又投了(PyCon.JP 2012)1,跟往年不一樣這次比較偏重Python本身的 特性,而非介紹自己的專案這類應用性質比較高的主題。

這次去的台灣人不少,大概有11個人吧,包括我在內則有3個人有給Talk。 地點則跟去年一樣,還是在品川大,議程跟參加人數都較往年多,甚至多了一軌 專門給英文演講。

還滿喜歡這種邊演講邊旅行的生活,但是好累啊 XD

最後附上投影片, 主要是說明Python 的 Type 跟 Object

Coscup 2012 簡報檔釋出

因為看錯時間把30分鐘要講得東西在20分鐘內說完,所以前20分鐘很多東西都快速帶過, 後10分鐘都在補講。 節奏被打亂得亂七八糟。 然後,下台後馬上就被 Thinker 說我塞太多東西在30分鐘內了。

用來說明概念的素材

Create a new instance of an object

Python

(coscup2012_new_instance.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

# To define a class object
class MyClass(object):

  def __init__(self, instance_attr):
      self.attr = instance_attr;   

# MyClass's constructor
print MyClass.__init__

# MyClass's Class is type
print type(MyClass)

# To create a new instance of 
# MyClass 
obj = MyClass.__new__(MyClass)

# To initial the new instance 
MyClass.__init__(obj, 'Attr bound on the instance')

# The result is Attr bound on the instance
print obj.attr

# The base class of MyClass is <type 'object'>
print MyClass.__base__


obj = MyClass('hi')
print obj.attr

JavaScript

(coscup2012_new_instance.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*                                                                                                                                                                                             
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
*/

// To define a function object as a Class
function MyClass(instance_attr){
  this.attr = instance_attr;
}

// To bind this to new instance and then execute MyClass
// function.
obj = new MyClass('Attr Bound on the instance');

// The output is Attr Bound on the instance
console.log(obj.attr);

// create a new instance of MyClass prototype
// run MyClass to initial obj
obj2 = Object.create(MyClass);

// The output is No!!!
MyClass.call(obj2, 'No!!!');

// The output is Attr Bound on the instance
console.log(obj2.attr);

// MyClass's constructor is [Function: MyClass]
console.log(MyClass.constructor);

// MyClass's prototype is Object
console.log(typeof(MyClass));

// The prototype of function object is {}, so
// the prototype of MyClass and instances of MyClass
// is also {}
console.log(MyClass.prototype);
console.log(obj.__proto__);

Base Object

Python

(coscup2012_base_obj.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
class NewBase(object):
  pass

class MyClass(object):
  pass

obj = MyClass()

# Use NewBase class to instead of object class, 
# but __base__ is readonly 
MyClass.__base__ = NewBase

obj2 = MyClass()

JavaScript

(coscup2012_base_obj.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*                                                                                                                                                                                         # Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
*/
function MyClass(){
}

obj = new MyClass();

// undefined
console.log(obj.name);

// change prototype to another object 
MyClass.prototype = {'name':'hello'}

obj2 = new MyClass();

// The result is still undefiend
console.log(obj.name);

// But this attribute of new instance is redirect to new prototype
console.log(obj2.name);

Trace Object Creation

JavaScript

(coscup2012_traceObj.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* 
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
*/

// Add logger function to functions of prototype
function logged(proto){
  for(prop in proto){
      var fn = proto[prop];
      proto[prop] = function(){
          console.log('-> Enter ' + prop);
          show_args(arguments);
          var ret = fn(arguments[0]);
          console.log('   Return: ' + ret);
          console.log('-> Exit ' + prop);
          return ret;
      };
  }
  return proto;
}

function show_args(args){
  for(var i=0; i<args.length;i++){
      console.log('      args:' + args[i]);
  }
}

function tail(list){
  var ret = new Array();
  for(var i=1;i<list.length;i++){
      ret[i-1] = list[i];
  }
  return ret;
}

// create traceable object based on a object
function new_traced_obj(base_obj){
  myargs = tail(arguments);
  console.log(base_obj.name);
  // create new function object
  var traced_obj = function(){
      console.log('-> Enter constructor');
      show_args(myargs);
      // execute base object constructor
      // on new instance of traced object.
      console.log('     -> Enter ' + base_obj.name);
      base_obj.call(this, myargs[0]);
      console.log('     -> Exit  ' + base_obj.name);
      console.log('<- Exit constructor');
  };
  // set new object's prototype is the base object 
  // prototype
  traced_obj.prototype = logged(base_obj.prototype);
  console.log('-> Enter - create new instance');
  // create new instance of sub object
  var new_inst = new traced_obj();
  console.log('<- Exit  - create new instance');
  return new_inst;
};

// To define a MyClass Function
function MyClass(name){
  this.name = name;
}

// Add add5 function to MyClass's prototype
MyClass.prototype.add5 = function(num){return num+5;};

// Main
instance = new_traced_obj(MyClass, 'M');
console.log('instance.name:'+instance.name);
console.log('=============================');
console.log('instance.add5(3,4): '+instance.add5(3,4));

My Slide ‘What Can Meta Class Do for You’ in PyCon Taiwan 2012

I had a chance to sharing my study notes of meta class in PyCon Taiwan 2012. It is a 30 minuts talk. The topic is roughly to introduce 5 examples to show meta class is useful and also to gave a conculution that why we use/don’t use it.

the slide is here:

Example Codes

Singleton

(metaclass_Singleton.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env python
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
# -*- encoding=utf8 -*-
#
# Author 2012 Hsin-Yi Chen
class Singleton(type):
    def __init__(cls,name,bases,dic):
        super(Singleton,cls).__init__(name,bases,dic)
        cls.instance=None

    def __call__(cls, *args, **kwargs):
            print "please use get_instance function to get the instance"

    def get_instance(cls,*args,**kw):
        if cls.instance is None:
            cls.instance=super(Singleton,cls).__call__(*args,**kw)
        return cls.instance

class _db(object):
    """
    >>> obj=_db()
    please use get_instance function to get the instance
    >>> obj is None
    True
    >>> obj1 = _db.get_instance()
    connecting to 0
    >>> obj2 = _db.get_instance()
    >>> id(obj1) == id(obj2)
    True
    """
    __metaclass__ = Singleton
    session_max = 0

    def __init__(self):
        print 'connecting to {0}'.format(self.session_max)

class MySQL(_db):
    """
    >>> obj1 = MySQL.get_instance()
    connecting to 1000
    >>> obj2 = MySQL.get_instance()
    >>> id(obj1) == id(obj2)
    True
    """
    session_max = 1000

import doctest
doctest.testmod()

Countable

(metaclass_countable.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

# Goal: Class knows the count of its instances.

# metaclass
class Countable(type):

    def __new__(mbs, name, bases, dct):
        cls = type.__new__(mbs, name, bases, dct)
        cls.count = 0
        return cls

    def __call__(cls, *args, **kwargs):
        cls.count += 1
        type.__call__(cls, *args, **kwargs)


# class
class Book(object):
    __metaclass__ = Countable

    def __init__(self, title):
        self.title = title

# run
print 'I have {} books'.format(Book.count)
a=Book('A1')
b=Book('A2')
c=Book('A3')
d=Book('A4')
print 'I have {} books'.format(Book.count)

Class Verification

(metaclass_verification.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
def check(cls, inf):
    for attrname in inf.__dict__:
        if attrname.startswith('__'):
            continue
        if not attrname in cls.__dict__.keys():
            msg = 'ERROR: Can not find {} in {}'.format(attrname,
                                                cls.__name__)
            msg = msg.format(cls.__name__, inf.__name__, attrname)
            print msg

class JokeRequirement(object):
    HaHaPoint = None

class HasInterface(type):
    def __new__(mbs, name, bases, dct):
        interface = dct['__implemented__']
        cls = type.__new__(mbs, name, bases, dct)
        check(cls, interface)
        return cls

class JokeRequirement(object):
    HaHaPoint = None

class JokeInPTT(object):
    __metaclass__ = HasInterface
    __implemented__ = JokeRequirement

Delegation

(metaclass_delegation.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
class Delegated(type):

    def __new__(mbs, name, bases, dct):
        cls = type.__new__(mbs, name, bases, dct)
        def myget(self, k):
                return getattr(self.context, k)
        def myset(self, k, v):
            if not hasattr(self, 'context'):
                self.__dict__['context'] = v
            if k != 'context':
                setattr(self.context, k, v)
        cls.__getattr__ = myget
        cls.__setattr__ = myset
        return cls

class Wrapper(object):
    __metaclass__ = Delegated
    def __init__(self, context):
        self.context = context

    def dump(self):
        print 'the data is ' + repr(self.data)

class Result(object):
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

result = Result(title='man ages', data=[1,2,3,4,5])
wrap_result = Wrapper(result)
wrap_result.dump()
wrap_result.title = 'girl args'
print result.title

Logged

(metaclass_logged.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (C) 2012  Hsin-Yi Chen

# Author(s): Hsin-Yi Chen <ossug.hychen@gmail.com>

# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

# Goal: Log informations to other places.
def info(msg):
    print 'info:'+msg
def error(msg):
    print 'error:'+msg

import functools

# To create a wrapped function
def log(name, fn):
    @functools.wraps(fn)
    def wrap_fn(*args, **kwargs):
        info('Enter func:{}'.format(name))
        try:
            ret = fn(*args, **kwargs)
        except Exception, e:
            error('Raised exception: {}'.format(e.message))
            raise e
        info('Got return value:{}'.format(ret))
        info('Exit func:{}'.format(name))
        return ret
    return wrap_fn

# Add logger decorator for each attr
def add_logger(name, val):
    return callable(val) and log(name, val) or val

# Metaclass
class Logged(type):

    def __new__(mbs, name, bases, dct):
        # if attr is callable log it.
        dct = {k:add_logger(k, v) for k,v in dct.items()}
        cls = type.__new__(mbs, name, bases, dct)
        return cls

# Class
class Person(object):
    __metaclass__ = Logged

    def get(self):
        return "I am get method"

# Run!
if __name__ == '__main__':
    obj =  Person()
    obj.get()

Serialized Python Function Object

想法

利用marshal把python bytecode轉成string, 就可以pickled.

把Function轉成Pickled string

1
2
3
4
5
6
7
8
import pickle
import marshal
maintask_bytecode = marshal.dumps(maintask_callback.func_code)
output = {
  'maintask_bytecode': maintask_bytecode,
  'maintask_defaults': maintask_defaults,
  'maintask_args': maintask_args}
print pickle.dumps(output)

把Pickled string轉成function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import sys
import types
import marshal
import pickle
## \brief reconstruct function from bytecode
#  \param func_bytecode str marshaled bytecode of func_code
#  \param func_default dict func_defaults
#  \return Function
def reconstruct_function(func_bytecode, func_defaults):
    func_code = marshal.loads(func_bytecode)
    return types.FunctionType(func_code, globals(), func_code.co_name,
                             func_defaults)
string = sys.stdin.read()
received = pickle.loads(string)
callback = reconstruct_function(received['maintask_bytecode'],
      received['maintask_defaults'])
print callback(maintask_args)

Fix Chromium Can Not Play Mp4

I found my chromium in Ubuntu 11.10 can not play mp4 video. after I googling, the solution is to install chromium-codecs-ffmpeg-extra to solve these problems.

$ apt-get install chromium-codecs-ffmpeg-extra

How to Create a Custom Launchpad Bugs Report

I already use lp-cli to generate reports about one month and think this may benefit someone has the same requirmentation. so here you are.

This document will show

  • howto collected bugs data with custom search conditions
  • combine collected bugs data and report template

comments are welcome.

Metaclass in Python (1) - Singleton

Singleton 這東西大家想必不陌生,在Python裡實做的方式滿多, 這邊用這個當例子介紹 Metaclass 可以做什麼。

概念上很簡當, 讓Class的建構子不能產生Instance, 然後再提供一個 Classmethod 能夠取得Instance(而且只能有一個), 在Python你可以用id來檢查兩個物件 是不是相同的。

原則上Singleton我只會用在不用花腦袋就會覺得這個class建出來的instance這個程式執行 時只能有一個。

Singleton 的源碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Singleton(type):
    def __init__(cls,name,bases,dic):
        super(Singleton,cls).__init__(name,bases,dic)
        cls.instance=None

    def __call__(cls, *args, **kwargs):
      # 這裡不raise Exception, 是因為doctest比較好寫
            print "please use get_instance function to get the instance"
            # 你也可讓cls()直接傳回instance, 讓class user不用在意他用的class
      # 是不是Singleton, 他只要注意class的主功能即可
            # return cls.get_instance(*args, *kw)

    def get_instance(cls,*args,**kw):
        if cls.instance is None:
            cls.instance=super(Singleton,cls).__call__(*args,**kw)
        return cls.instance

用法

把你想變成Singleton class 的 metaclass 設成 Singleton 就可以了, 後悔的話,把那一行註解起來,這個class就不是Singleton。

要注意的地方是這class的Singleton特性是可以被繼承的,但這也是為什麼我喜歡用 這種方式的原因,另一個好處是Class的功能跟Design Pattern的耦合度會比較低。 缺點就是會遇到metaclass衝突的狀況,但也不是不能解決。

1
2
class _db(object):
  __metaclass__ = Singleton

完整的源碼加測試

(metaclass_Singleton.py) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env python
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
# -*- encoding=utf8 -*-
#
# Author 2012 Hsin-Yi Chen
class Singleton(type):
    def __init__(cls,name,bases,dic):
        super(Singleton,cls).__init__(name,bases,dic)
        cls.instance=None

    def __call__(cls, *args, **kwargs):
            print "please use get_instance function to get the instance"

    def get_instance(cls,*args,**kw):
        if cls.instance is None:
            cls.instance=super(Singleton,cls).__call__(*args,**kw)
        return cls.instance

class _db(object):
    """
    >>> obj=_db()
    please use get_instance function to get the instance
    >>> obj is None
    True
    >>> obj1 = _db.get_instance()
    connecting to 0
    >>> obj2 = _db.get_instance()
    >>> id(obj1) == id(obj2)
    True
    """
    __metaclass__ = Singleton
    session_max = 0

    def __init__(self):
        print 'connecting to {0}'.format(self.session_max)

class MySQL(_db):
    """
    >>> obj1 = MySQL.get_instance()
    connecting to 1000
    >>> obj2 = MySQL.get_instance()
    >>> id(obj1) == id(obj2)
    True
    """
    session_max = 1000

import doctest
doctest.testmod()

Will You Attend PyCon TW 2012?

從兩三年前開始,就不斷有人在喊”那會有Python Conference 嗎”?

尤其是去年有Ruby Con TW 2011, PHP Conf TW 2011

終於,前陣子PyCon TW 2012 官方網站公佈啦! 活動預計在2012 年 6月9日(六)及10日(日) 假中研院人文館舉辦, 目前正在統計可能參與人數, 請幫忙填問卷

  • 有興趣提供講題的人,請到這裡
  • 有興趣發表論文的人,請到這裡
  • 有興趣提供贊助的公司,請到這裡

用Python的人應該是不少才對, 大家不要在潛水了!