<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet href="/templates/default/atom.css" type="text/css" ?>

<feed 
   xmlns="http://www.w3.org/2005/Atom"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:admin="http://webns.net/mvcb/"
   xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
   xmlns:wfw="http://wellformedweb.org/CommentAPI/">
    <link href="http://www.luochunhui.com/feeds/atom.xml" rel="self" title="大罗-PHP/Python博客" type="application/atom+xml" />
    <link href="http://www.luochunhui.com/"                        rel="alternate"    title="大罗-PHP/Python博客" type="text/html" />
    <link href="http://www.luochunhui.com/rss.php?version=2.0"     rel="alternate"    title="大罗-PHP/Python博客" type="application/rss+xml" />
    <title type="html">大罗-PHP/Python博客</title>
    <subtitle type="html">标准的八零年代青年，充分的自信，追求自由。在真实的上海，虚拟的网络中拼搏，为了自己人生的目标，追求着，永不松懈 </subtitle>
    
    <id>http://www.luochunhui.com/</id>
    <updated>2010-07-26T02:35:22Z</updated>
    <generator uri="http://www.s9y.org/" version="1.5.1">Serendipity 1.5.1 - http://www.s9y.org/</generator>
    <dc:language>en</dc:language>

    <entry>
        <link href="http://www.luochunhui.com/id/548" rel="alternate" title="一道google topcoder真题" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2010-07-25T06:39:17Z</published>
        <updated>2010-07-26T02:35:22Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=548</wfw:comment>
    
        <slash:comments>3</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=548</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/548</id>
        <title type="html">一道google topcoder真题</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                题目：<br />
<blockquote>Problem Statement<br />
????<br />
We have a sequence of integers, and we would like to remove all duplicate elements from this sequence. There may be multiple ways to perform this task. For example, given the sequence { 1, 2, 1, 3 }, we could end up with either { 1, 2, 3 } or { 2, 1, 3 } as the remaining sequence, depending on which duplicate 1 we remove from the original sequence. For this problem, we want to return the lexicographically first of of all possible remaining sequences. A sequence S1 comes before sequence S2 lexicographically if and only if S1 has a smaller value than S2 at the lowest index at which the two sequences differ (so, for example, { 1, 2, 3 } comes before { 2, 3, 1 }).<br />
You will be given a int[] sequence. Return a int[] containing the sequence after all the duplicates are removed. See the examples for further clarification.<br />
Definition<br />
????<br />
Class:<br />
HardDuplicateRemover<br />
Method:<br />
process<br />
Parameters:<br />
int[]<br />
Returns:<br />
int[]<br />
Method signature:<br />
int[] process(int[] sequence)<br />
(be sure your method is public)<br />
????<br />
<br />
Constraints<br />
-<br />
sequence will have between 1 and 50 elements, inclusive.<br />
-<br />
Each element of sequence will be between 1 and 1000, inclusive.<br />
Examples<br />
0)<br />
<br />
????<br />
{5, 6, 5, 1, 6, 5}<br />
Returns: {1, 6, 5 }<br />
There are six different ways to remove duplicates (remaining numbers are marked by '*'): <br />
{ *5, *6,  5, *1,  6,  5},<br />
{ *5,  6,  5, *1, *6,  5},<br />
{  5, *6, *5, *1,  6,  5},<br />
{  5,  6, *5, *1, *6,  5},<br />
{  5, *6,  5, *1,  6, *5},<br />
{  5,  6,  5, *1, *6, *5}.<br />
<br />
The last variant is the lexicographically first.<br />
1)<br />
<br />
????<br />
{3, 2, 4, 2, 4, 4}<br />
Returns: {3, 2, 4 }<br />
<br />
2)<br />
<br />
????<br />
{6, 6, 6, 6, 6, 6}<br />
Returns: {6 }<br />
<br />
3)<br />
<br />
????<br />
{1, 3, 2, 4, 2, 3}<br />
Returns: {1, 2, 4, 3 }<br />
<br />
4)<br />
<br />
????<br />
{5, 4, 1, 5}<br />
Returns: {4, 1, 5 }<br />
<br />
This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.<br />
<br />
</blockquote><br />
<br />
C++练习了一下，写了个答案如下：<br />
<pre name="code" class="cpp"> 
/* 
 * File:   main.cpp
 * Author: luo
 *
 * Created on June 24, 2010, 11:10 PM
 */

#include &lt;cstdlib&gt;
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;fstream&gt;
#include "testhead.h"

using namespace std;

std::vector&lt;int&gt;::const_iterator vector_index(const std::vector&lt;int&gt; &iv, int token ) {
    for(std::vector&lt;int&gt;::const_iterator it=iv.begin(); it&lt;iv.end(); it++) {
        if(token == *it) {
            return it;
        }
    }
    return iv.end()+1;

}
class HardDuplicateRemover
{
public:
   std::vector&lt;int&gt; process(const std::vector&lt;int&gt; &amp; iv) {
       std::vector&lt;int&gt; result;       
       for(
               std::vector&lt;int&gt;::const_iterator it=iv.begin();
               it!=iv.end();
               ++it
       ) {
           std::vector&lt;int&gt;::const_iterator index_at = vector_index(result, *it);

           if (index_at &gt; result.end() ) {
               result.push_back(*it);
           }
           else if(index_at &lt; result.end()) {
               if(*index_at &gt; *(index_at+1)) {
                   int b = index_at - result.begin();
                   result.erase(result.begin() + b);
                   result.push_back(*it);
               }
           }
           else { // ==
               
           }
       }
       return result;
  }
};

/*
 * 
 */
int main(int argc, char** argv) {
    HardDuplicateRemover h;
    int arr[] ={5, 4, 1, 5};
    std::vector&lt;int&gt; iv(arr, arr + 4);

    cout &lt;&lt; "{";
    for(std::vector&lt;int&gt;::const_iterator i = iv.begin();
            i&lt;iv.end();
            ++i) {
        cout &lt;&lt; *i &lt;&lt; ",";
    }
    cout &lt;&lt; "}" &lt;&lt; endl;
    
    std::vector&lt;int&gt; rs = h.process(iv);
    cout &lt;&lt; endl &lt;&lt; "{";
    for(std::vector&lt;int&gt;::const_iterator i = rs.begin();
            i&lt;rs.end();
            ++i) {
        cout &lt;&lt; *i &lt;&lt; ",";
    }
    cout &lt;&lt; "}" &lt;&lt; endl;
    return 0;
}


</pre> 
            </div>
        </content>
        <dc:subject>c++</dc:subject>

    </entry>
    <entry>
        <link href="http://www.luochunhui.com/id/546" rel="alternate" title="【翻译】Thinking in Python (四) 隐藏实现细节" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2010-07-07T06:19:04Z</published>
        <updated>2010-07-21T18:00:43Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=546</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=546</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/546</id>
        <title type="html">【翻译】Thinking in Python (四) 隐藏实现细节</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                隐藏实现<br />
<br />
代理模式（Proxy）和状态模式（State）都提供一个代理类，用来隐藏真正的实现过程。在调用代理类时，他简单的将请求转发给实际类去处理，并返回其结果。这两种设计模式比较相似，代理模式可以看做是一种特殊的状态模式，他只有一个状态。一个观点是将这两者合并，称之为代理模式（Surrogate）。但Proxy这个词汇使用的太久了，概念被固化了。因此，这两个模式并没有被合并。<br />
<br />
最开始的想法很简单，通过代理类，以实际类做支持，来完成实际的实现功能。<br />
<!-- s9ymdb:79 --><img class="serendipity_image_center" width="450" height="187" src="http://www.luochunhui.com/uploads/TIPyth00.gif" alt=""  /><br />
<br />
<br />
代理对象被建立后，他可以提供一个应用接口，将所有的调用转发给实际类。<br />
<br />
在结构上，代理模式和状态模式很容易区分：代理模式只有一个应用，状态模式则有多个。《设计模式》一书的看法不同：代理模式用来控制对类的访问权限，状态模式这用来在运行过程中动态的改变类。<br />
<br />
代理<br />
<br />
我们来为上图的代理模式写些代码：<br />
<br />
<pre name="code" class="python"> 
#: c04:ProxyDemo.py 
# Simple demonstration of the Proxy pattern. 
 
class Implementation: 
  def f(self):  
    print "Implementation.f()" 
  def g(self):  
    print "Implementation.g()"  
  def h(self):  
    print "Implementation.h()"  
 
class Proxy: 
  def __init__(self):  
    self.__implementation = Implementation()  
  # Pass method calls to the implementation:
  def f(self): self.__implementation.f()  
  def g(self): self.__implementation.g()  
  def h(self): self.__implementation.h()  
 
p = Proxy() 
p.f(); p.g(); p.h() 
#:~ 
</pre><br />
Proxy类的接口并不需要和Implementation类的接口保持完全一致，代理可以以任何方式来“代言”实际类。一般来讲，将代理类和实际类保持一致的接口会更为通用和方便，也能够保证实际类完全支持代理类的所有调用。<br />
<br />
当然，在python中，我们可以使用内置的代理机制。简化后的代码像这样：<br />
<br />
<pre name="code" class="python"> 
#: c04:ProxyDemo2.py 
# Simple demonstration of the Proxy pattern. 
 
class Implementation2: 
  def f(self):  
    print "Implementation.f()" 
  def g(self):  
    print "Implementation.g()"  
  def h(self):  
    print "Implementation.h()"  
 
class Proxy2: 
  def __init__(self):  
    self.__implementation = Implementation2()  
  def __getattr__(self, name): 
    return getattr(self.__implementation, name) 
 
p = Proxy2() 
p.f(); p.g(); p.h(); 
#:~ 
</pre><br />
Proxy2使用__getattr__( )方法，这看起来更为优雅，他不依赖于任何的实施细节。<br />
<br />
<br />
状态模式<br />
<br />
和代理模式相比，状态模式中存在多个实现类，并提供了在实现类中动态切换的接口。<br />
<br />
<pre name="code" class="python"> 
#: c04:StateDemo.py 
# Simple demonstration of the State pattern. 
 
class State_d: 
  def __init__(self, imp):  
    self.__implementation = imp  
  def changeImp(self, newImp): 
    self.__implementation = newImp 
  # Delegate calls to the implementation: 
  def __getattr__(self, name): 
    return getattr(self.__implementation, name) 
 
class Implementation1: 
  def f(self):  
    print "Fiddle de dum, Fiddle de dee,"  
  def g(self):  
    print "Eric the half a bee."  
  def h(self):  
    print "Ho ho ho, tee hee hee,"  
 
class Implementation2: 
  def f(self):  
    print "We're Knights of the Round Table."  
  def g(self):  
    print "We dance whene'er we're able."  
  def h(self):  
    print "We do routines and chorus scenes"  
 
def run(b): 
  b.f() 
  b.g() 
  b.h() 
  b.g() 
 
b = State_d(Implementation1()) 
run(b) 
b.changeImp(Implementation2()) 
run(b) 
#:~
</pre><br />
<br />
在程序中，我们先构造了一个实现类，并将其封装到State_d。运行一段时间后，程序又被切换给另一个实现类。<br />
<br />
<br />
代理模式和状态模式有不同的使用场景。《设计模式》描述了代理模式的主要场景：<br />
<br />
1. 远程代理 <br />
2. 虚拟代理，提供“惰性类”<br />
3. 保护代理 用于限制客户端对被代理对象的完全访问。<br />
4. 转发 建立代理时，增加一些额外的操作，用来对调用进行跟踪。<br />
<br />
在pyhton引用中，使用了不少的保护代理，用来阻止对真实对象的访问。比如，你无法建立使用一个对NULL的引用。<br />
<br />
<br />
状态机模式<br />
<br />
状态模式允许客户端程序在运行过程中修改其实现过程，我们可以在实现过程中，将一个实施自动的转变为另一个实施，这样的实现，我们称之为状态机模式。当前的运行状态代表系统当前的状态，而状态可以由系统自动的切换。最基本的状态机模式是对象状态。<br />
<br />
切换系统状态一般可以使用上述模板方法中所介绍的代码。<br />
<br />
每一个状态都使用run（）接口实现其具体行为，或者你也可以传入一个input参数，以便告诉系统，你应该切换的下一个状态是什么。这两种设计的主要不同点是由谁来决定下一个状态是什么。我们可以传入一个input参数，标示下一个状态，或者，在状态类中定义一个表（或者定一个全局表），定义当前状态的下一个状态是什么。<br />
<pre name="code" class="python"> 
#: c04:statemachine:State.py
# A State has an operation, and can be moved
# into the next State given an Input:
class State:
	def run(self):
		assert 1, "run not implemented"
	def next(self, input):
		assert 1, "next not implemented"
#:~
</pre><br />
这个类并不是很完整，但他足以说明状态类的代码结构，如果其子类没有重构其所有方法时，他也可以给出一个简短的错误提示。更简单，我们可以直接定义为：<br />
<pre name="code" class="python"> 
class State: pass
</pre><br />
因为如果run或next没有被实现，系统同样也会抛出异常。<br />
<br />
<br />
状态机保存了状态的轨迹，这些轨迹一般定义在状态机的构造函数中。runAll方法将对所有的input对象实施状态操作及变更。run方法则只执行其特定的对象的状态操作及变更。<br />
<pre name="code" class="python"> 
#: c04:statemachine:StateMachine.py
# Takes a list of Inputs to move from State to
# State using a template method.
class StateMachine:
	def __init__(self, initialState):
		self.currentState = initialState
		self.currentState.run()
	# Template method:
	def runAll(self, inputs):
		for i in inputs:
			print i
			self.currentState = self.currentState.next(i)
			self.currentState.run()
#:~
</pre><br />
我将runAll方法也写作成了模板方法同样的形式，尽管这并不是必须的。<br />
<br />
目前，状态机模式的基本框架已经完成了。下面我们将使用捕鼠器做为示例来惊醒一个演示（放心，没有哪只老鼠会收到伤害）。我们可以操作捕鼠器的各个状态，老鼠类及其星系将放到mouse这个包中，主要包括老鼠的移动行为，他将作为状态机的输入参数。<br />
<pre name="code" class="python"> 
#: c04:mouse:MouseAction.py
class MouseAction:
	def __init__(self, action):
		self.action = action
	def __str__(self): return self.action

	def __cmp__(self, other):
		return cmp(self.action, other.action)
	# Necessary when __cmp__ or __eq__ is defined
	# in order to make this class usable as a
	# dictionary key:
	def __hash__(self):
		return hash(self.action)

# Static fields; an enumeration of instances:
MouseAction.appears = MouseAction("mouse appears")
MouseAction.runsAway = MouseAction("mouse runs away")
MouseAction.enters = MouseAction("mouse enters trap")
MouseAction.escapes = MouseAction("mouse escapes")
MouseAction.trapped = MouseAction("mouse trapped")
MouseAction.removed = MouseAction("mouse removed")
#:~
</pre><br />
我们注意到__cmp__( )被重构了，用来比较两个action对象的值。每一种移动行为都被定义在MouseAction对象中，成为该对象的一个属性。<br />
<br />
为此，我们再建立一个测试用例，创建一个老鼠的行为队列：<br />
<pre name="code" class="python"> 
#:! c04:mouse:MouseMoves.txt
mouse appears
mouse runs away
mouse appears
mouse enters trap
mouse escapes
mouse appears
mouse enters trap
mouse trapped
mouse removed
mouse appears
mouse runs away
mouse appears
mouse enters trap
mouse trapped
mouse removed
#:~
</pre><br />
<br />
有了以上的这些基础，我们现在可以开始编写老鼠夹的代码了。每一个状态子类都定义了run的方法。也有if语句用来选择下一个状态是什么。<br />
<br />
<pre name="code" class="python"> 
#: c04:mousetrap1:MouseTrapTest.py 
# State Machine pattern using 'if' statements 
# to determine the next state. 
import string, sys 
sys.path += ['../statemachine', '../mouse'] 
from State import State 
from StateMachine import StateMachine 
from MouseAction import MouseAction 
# A different subclass for each state: 
 
class Waiting(State): 
  def run(self):  
    print "Waiting: Broadcasting cheese smell" 
 
  def next(self, input): 
    if input == MouseAction.appears: 
      return MouseTrap.luring 
    return MouseTrap.waiting 
 
class Luring(State): 
  def run(self): 
    print "Luring: Presenting Cheese, door open" 
 
  def next(self, input): 
    if input == MouseAction.runsAway: 
      return MouseTrap.waiting 
    if input == MouseAction.enters: 
      return MouseTrap.trapping 
    return MouseTrap.luring 
 
class Trapping(State): 
  def run(self): 
    print "Trapping: Closing door" 
 
  def next(self, input): 
    if input == MouseAction.escapes: 
      return MouseTrap.waiting 
    if input == MouseAction.trapped: 
      return MouseTrap.holding 
    return MouseTrap.trapping 
 
class Holding(State): 
  def run(self): 
    print "Holding: Mouse caught"  
  def next(self, input): 
    if input == MouseAction.removed: 
      return MouseTrap.waiting 
    return MouseTrap.holding 
 
class MouseTrap(StateMachine): 
  def __init__(self):  
    # Initial state 
    StateMachine.__init__(self, MouseTrap.waiting) 
 
# Static variable initialization: 
MouseTrap.waiting = Waiting() 
MouseTrap.luring = Luring() 
MouseTrap.trapping = Trapping() 
MouseTrap.holding = Holding() 
 
moves = map(string.strip,  
  open("../mouse/MouseMoves.txt").readlines()) 
MouseTrap().runAll(map(MouseAction, moves)) 
#:~
</pre><br />
<br />
状态机类的定义了所有可能的状态类型，并建立了初始状态。单元测试程序建立了一个老鼠夹，并运行了我们刚刚建立的老鼠行为队列。<br />
<br />
在next（）方法中使用if方法是可行的，但是在状态比较多的时候，使用if则会变得很难维护。一个更好的办法是在每个状态内部建立一个表，并基于传入参数进行自动判断。<br />
<br />
这乍看起来很容易，我们可以在每一个子状态中建立一个静态表，定义其下一个状态元素。但是，这将造成各个状态类之间的循环依赖关系。为了解决这个问题，我们只能在调用next方法时，才惰性得再加载这个状态表。因为这个原因，next的写法看起来会有些怪。<br />
<br />
我们重新定义了上述的State类，并将其命名围StateT，他增加了一个Map并将其初始化为一个二位数组。next方法定义了一个基本实现逻辑，StateT子类的next也必须调用该方法。<br />
<pre name="code" class="python"> 
#: c04:mousetrap2:MouseTrap2Test.py 
# A better mousetrap using tables 
import string, sys 
sys.path += ['../statemachine', '../mouse'] 
from State import State 
from StateMachine import StateMachine 
from MouseAction import MouseAction 
 
class StateT(State): 
  def __init__(self): 
    self.transitions = None 
  def next(self, input): 
    if self.transitions.has_key(input): 
      return self.transitions[input] 
    else: 
      raise "Input not supported for current state" 
 
class Waiting(StateT): 
  def run(self):  
    print "Waiting: Broadcasting cheese smell" 
  def next(self, input): 
    # Lazy initialization: 
    if not self.transitions: 
      self.transitions = {  
        MouseAction.appears : MouseTrap.luring  
      } 
    return StateT.next(self, input) 
 
class Luring(StateT): 
  def run(self): 
    print "Luring: Presenting Cheese, door open" 
  def next(self, input): 
    # Lazy initialization: 
    if not self.transitions: 
      self.transitions = { 
        MouseAction.enters : MouseTrap.trapping, 
        MouseAction.runsAway : MouseTrap.waiting 
      } 
    return StateT.next(self, input) 
 
class Trapping(StateT): 
  def run(self):     print "Trapping: Closing door" 
  def next(self, input): 
    # Lazy initialization: 
    if not self.transitions: 
      self.transitions = { 
        MouseAction.escapes : MouseTrap.waiting, 
        MouseAction.trapped : MouseTrap.holding 
      } 
    return StateT.next(self, input) 
 
class Holding(StateT): 
  def run(self): 
    print "Holding: Mouse caught" 
  def next(self, input): 
    # Lazy initialization: 
    if not self.transitions: 
      self.transitions = { 
        MouseAction.removed : MouseTrap.waiting 
      } 
    return StateT.next(self, input) 
 
class MouseTrap(StateMachine): 
  def __init__(self):  
    # Initial state 
    StateMachine.__init__(self, MouseTrap.waiting) 
 
# Static variable initialization: 
MouseTrap.waiting = Waiting() 
MouseTrap.luring = Luring() 
MouseTrap.trapping = Trapping() 
MouseTrap.holding = Holding() 
 
moves = map(string.strip,  
  open("../mouse/MouseMoves.txt").readlines()) 
mouseMoves = map(MouseAction, moves) 
MouseTrap().runAll(mouseMoves) 
#:~
</pre><br />
<br />
其他的代码也是一样的，不同的只在于StateT的类名和next方法的具体实现上。<br />
<br />
当你不得不建立或维护大量的状态时，使用这样的方式无疑是必要的。通过查看状态表，将很容易阅读并理解这些状态。<br />
<br />
 
            </div>
        </content>
        <dc:subject>python</dc:subject>
<dc:subject>Thinking In Python</dc:subject>
<dc:subject>翻译</dc:subject>
<dc:subject>设计模式</dc:subject>

    </entry>
    <entry>
        <link href="http://www.luochunhui.com/id/543" rel="alternate" title="【翻译】Thinking in Python (一) 快速了解Python" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2010-07-01T05:28:06Z</published>
        <updated>2010-07-21T17:59:59Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=543</wfw:comment>
    
        <slash:comments>3</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=543</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/543</id>
        <title type="html">【翻译】Thinking in Python (一) 快速了解Python</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                本书假定读者是一个有经验的程序员，最好是已经阅读过其他python相关书籍的人。本章将对python做一个快速的介绍。<br />
<br />
python概要<br />
<br />
本概要针对有经验的程序员。建议你先参考python官方文档，特别推荐Python快速参考. 或者其他的一些python书籍，比如 Mark Lutz 和 David Ascher 的著作：<Learning Python>， O'reilly出版，1999.<br />
<br />
Python一般被认为是一种脚本语言，但事实并非仅仅如此。不像普通脚本语言，Python并不局限于某一特殊领域，更准确的说，Python应该被看作是一种提供脚本语言形式的编程语言。在实现脚本语言的之外，你会发现，Python可以替代你的任何批处理操作、shell脚本以及一些简单程序。Python的使用范围，已经超过了传统意义上脚本语言的使用范围。<br />
<br />
<br />
Python语言易于书写和阅读。及时在很长一段时间后，你仍旧可以很快的阅读你之前的代码。阅读其他人的代码也是很容易的。Python语法十分的简洁，扼要。主要的一个原因是他使用了缩进来标示代码块。例如：<br />
<br />
<pre name="code" class="python"> 
#: c01:if.py
response = "yes"
if response == "yes":
  print "affirmative"
  val = 1
print "continuing..."
#:~
</pre><br />
<br />
"#"符号标示注释，和C++.Java中的//相同。<br />
<br />
首先，我们来看If的语法，其基本语法于C相似。但在C中，If的条件式需要使用圆括号括起来，但在python中，圆括号并不是必需的（当然，加上也是可接受的）。<br />
<br />
Python中的条件式使用冒号来结束。其下的代码块使用缩进来标示，类似于then的作用法。在本例中，print语句用来输出信息到标准输出，其下是一个赋值语句。接下来的语句没有缩进，已然，他不再属于if的代码块了。缩进是可嵌套的，和C++，Java中的花括号相似。一点不同是，Python中的缩进是不可省略的。编译器强制每一处代码都必须使用缩进格式。这就是为什么Python能够保持很好的可读性的原因。<br />
<br />
通常，Python一行只写一个语句（虽然你可以使用分号来写多个语句），一行语句结尾的分号也不是必须的。在上述示例代码中，你可以看到，python语法被设计的尽可能的简单，而且具备充分的代码可读性.<br />
<br />
<br />
基本容器<br />
在C++和Java中，容器类型以组件的方式被引入，他们并非语言所必须的。在Python中，几种重要的容器类型将作为基本类型内置在核心中，比如列表list，关联数组map（别名：映射，字典，哈希表）。这使得Python语法更加优雅。<br />
<br />
另外，for语法使用自动迭代器，而不是通过下标访问。使用for循环来遍历一个数组或容器显得非常的方便。以下代码暂时了如何使用Python的自动迭代器来访问列表：<br />
<br />
<pre name="code" class="python"> 
#: c01:list.py
list = [ 1, 3, 5, 7, 9, 11 ]
print list
list.append(13)
for x in list:
  print x
#:~
</pre><br />
<br />
第一行建立了一个列表。你可以直接print输出一个列表，其结果和你输入的形式看起来很相似（相反的，在Thinking in Java的例子中，为了打印一个数组，我不得不建立一个图书的Arrays2类）。队列和java中的容器相似，你可以给他添加新元素（这里使用了append），他们会自动的增加队列长度。后面的for语句建立了一个迭代器x，其值为列表中的每一个元素值。<br />
<br />
<br />
你可以使用range（）来建立一个连续数字列表。你可以利用该特性来模仿C中的for语法<br />
例如：<br />
<br />
<pre name="code" class="python"> 
#: c02:list.py
list = [ 1, 3, 5, 7, 9, 11 ]
print list
list.append(13)
for i in range(len(list)):
  print list[i]
</pre><br />
<br />
注意，python不需要进行变量类型定义，对象名字随时可以在需要的时候出现。Python将自动推断他们的类型。<br />
Python的语法，将让你感觉到，你只需敲你必须敲入的字符。在使用python一段时间后，你会发现，在非python语言中，必须键入大量的括号，花括号，分号以及其他一些多余的和程序意图不相干的符号是一件相当烦人的事情。<br />
<br />
<br />
函数<br />
<br />
Python中使用def关键字来建立函数，其后紧跟这函数名称和参数列表。冒号之后，是函数主体。<br />
以下是定义函数的第一个例子：<br />
<br />
<pre name="code" class="python"> 
#: c01:myFunction.py
def myFunction(response):
	val = 0
	if response == "yes":
		print "affirmative"
		val = 1
	print "continuing..."
	return val
print myFunction("no")
print myFunction("yes")
#:~
</pre><br />
<br />
函数声明中，只有函数名称和参数列表，没有类型申明，也不需要返回值类型和参数类型定义。Python是弱类型语言，你不需要为此敲入额外的类型定义代码。你也可以在函数中传入或返回不同类型的值。如以下示例：<br />
<br />
<pre name="code" class="python"> 
#: c01:differentReturns.py
def differentReturns(arg):
  if arg == 1:
    return "one"
  if arg == "one":
    return 1
print differentReturns(1)
print differentReturns("one")
#:~
</pre><br />
<br />
唯一一个强制性要求是，你传入函数中的参数必须能够被函数所正确执行，其他的，他不做限制。下面的例子，将使用了+的方法操作数字或字符串：<br />
<br />
<pre name="code" class="python"> 
#: c01:sum.py
def sum(arg1, arg2):
  return arg1 + arg2

print sum(42, 47)
print sum('spam ', "eggs")
#:~
</pre><br />
<br />
当操作符+号被用作字符串时，他的意义是连接（肯定的，Python支持操作符重载，而且它能够很漂亮的完成）<br />
<br />
<br />
字符串<br />
<br />
上面的例子也提到了一点点字符串的处理方式，他是我所见过的语言中最好的。你可以使用单引号或双引号来表示一个字符串。如果你使用双引号，其內你可以插入一个单引号字符，反之亦然：<br />
<pre name="code" class="python"> 
#: c01:strings.py
print "That isn't a horse"
print 'You are not a "Viking"'
print """You're just pounding two
coconut halves together."""
print '''"Oh no!" He exclaimed.
"It's the blemange!"'''
print r'c:\python\lib\utils'
#:~
</pre><br />
<br />
注：Python并不是来源于蛇的名字，而是来源于一个马戏团。上面的例子就是来自于Python-esque马戏团的一些场景<br />
<br />
三引号将对其间所有部分进行引用，包括换行。这对于生成web页面等特别有用（Python是一个很好的CGI程序），你可以使用三引号的方式来输出整个页面。<br />
<br />
在r标记符右侧的字符串表示不需要进行反斜杠转义，当你需要插入反斜杠时，你不需要输入额外的反斜杠。<br />
<br />
对字符串进行替换是非常简单的事情。Python使用了C的printf语法。在字符串后跟一个%号即可使用：<br />
<pre name="code" class="python"> 
#: c01:stringFormatting.py
val = 47
print "The number is %d" % val
val2 = 63.4
s = "val: %d, val2: %f" % (val, val2)
print s
#:~
</pre><br />
<br />
看第二个例子，当你需要输出不止一个参数的时候，你需要使用圆括号将它们括起来（这里的术语是“元组”，用来表示一个不可被修改的列表。你也可以使用常规的列表，但元组这种形式更为常见）。<br />
<br />
Python支持C中所有的printf参数，包括数字千分号及对齐等。<br />
Python也非常完美的支持正则表达式。<br />
<br />
<br />
类<br />
<br />
和Python其他的语法相似，只需要很少的代码就可以定义一个类。类的定义只需要使用class关键字，类主体中使用def关键字定义方法。以下是一个简单类：<br />
<br />
<pre name="code" class="python"> 
#: c01:SimpleClass.py
class Simple:
	def __init__(self, str):
		print "Inside the Simple constructor"
		self.s = str
	# Two methods:
	def show(self):
		print self.s
	def showMsg(self, msg):
		print msg + ':',
		self.show() # Calling another method
if __name__ == "__main__":
	# Create an object:
	x = Simple("constructor argument")
	x.show()
	x.showMsg("A message")
#:~
</pre><br />
<br />
上面两个方法都将self作为了其第一个参数，C++, Java则隐藏了他们。这一参数指向对象实例本身，类方法可以使用关键字this来代表实例本身。Python方法需要显式的将实例自身作为方法的第一参数。一般的，参数名字使用self，你也可以改变成其他的变量名，但这会给其他的人造成困惑。当你需要访问实例的属性或方法时，你需要在表达式中使用self.语法。在做实例的方法调用时，如x.show()，不需要传递self参数，系统已经为你做好了。<br />
<br />
这里，第一个方法比较特殊，它以两个下划线开始，并以两个下划线结束。在这个例子中，它表示构造函数，在建立对象时，本函数将被自动调用。这和C++,Java的构造函数相似。在示例底部，我们可以看到类的实例化操作，其语法与一个函数调用并无差异。这里不需要new关键字。这和C++, java不同。<br />
<br />
底部的一些代码被放置在一个if语句的代码块中。他用来检查__name__变量是否和"__main__"相等。由两个双下划线包含的变量是一类特殊的变量。这里的IF语句用来判断这个文件是否是被系统直接调用。在本例中，只有当你直接运行这个文件时，底部if代码块类的代码才会被执行，否则该文件只是完成了类的定义操作。你可以这样调用执行IF语句中的代码块：<br />
<pre name="code" class="bash"> 
python SimpleClass.py
</pre><br />
<br />
当你在其他模块中对这个类进行import操作时，if代码块中的内容则不会被执行。<br />
<br />
<br />
有时，新手常常会很惊讶，在pyton中类属性的定义是直接在方法中完成的。而不是像C++或Java，需要在方法外进行独立的类属性定义。建立一个属性，你只需要在方法中使用self加变量名称就可以了。通常会在构造函数中进行定义，但并非总是如此。类属性所需要的存储空间将在运行时被分配。在C++和Java程序员看来，这看起来很怪，他们总是习惯在类的头部就定义好属性，这样可以确定一个实例需要使用多少存储空间。<br />
<br />
<br />
继承<br />
<br />
由于Python是弱类型语言，因此它并不关心接口的概念。它唯一关心的，就是在运行时的操作能够成功的作用于对象（事实上，Java中的Interface关键字在Python中是不存在的）。这样，类继承的使用场景不太相同了。C++和Java中使用继承，往往希望获得其接口，而在Python中，使用继承的目的和代码实现密切相关，继承的目的是希望重用父类的代码。<br />
<br />
使用继承时需要先指示出其父类的位置。在建立一个文件时，Python都隐式的建立一个模块（这个概念和JAVA中“包”概念相似），模块名称和文件名相同。不需要package关键字。当需要引入一个模块时，使用import关键字和其模块名称即可。 Python会在PYTHONPATH目录中搜索模块名称，这和Java在CLASSPATH中进行搜索是相似的。一个好处是,Python没有Java中的import陷阱。若只需要局部引入模块中的一个方法或类时，可以使用模块名称，分隔符，和方法名或类名。语法如下：<br />
<pre name="code" class="python"> 
from module import name(s)
</pre><br />
<br />
name(s)是由逗号分隔的一系列函数名或类名。<br />
<br />
我们回到使用继承上来，继承的语法是：在子类名后面加上（），中见填上父类的类名。我们现看上面的Simple类，他所在文件名，即模块名称为SompleClass。因此，我们先需要使用import引入它：<br />
<br />
<pre name="code" class="python"> 
#: c01:Simple2.py
from SimpleClass import Simple

class Simple2(Simple):
	def __init__(self, str):
		print "Inside Simple2 constructor"
		# You must explicitly call
		# the base-class constructor:
		Simple.__init__(self, str)
	def display(self):
		self.showMsg("Called from display()")
		# Overriding a base-class method
	def show(self):
		print "Overridden show() method"
		# Calling a base-class method from inside
		# the overridden method:
		Simple.show(self)

class Different:
	def show(self):
		print "Not derived from Simple"

if __name__ == "__main__":
	x = Simple2("Simple2 constructor argument")
	x.display()
	x.show()
	x.showMsg("Inside main")
	def f(obj): obj.show() # One-line definition
	f(x)
	f(Different())
#:~
</pre><br />
<br />
Simple2继承自Simple， 在其构造函数中，父类的构造函数也被调用了。display( ), showMsg( ) 方法可以直接通过self进行调用。当子类和父类有相同的方法时，子类的方法将被重载。在构造函数中，你必须将所有参数全部传入，包括将self作为第一参数。上面还可以看到show方法被重载了。<br />
<br />
在__main__代码块中，可以看到基类的构造函数也被调用了，基本的方法showMsg在父类中同样可以使用，<br />
<br />
Different类也实现了show方法，但这个类并非Simple类的子类。__main__代码块中定义的f函数演示了弱类型语法。f函数关心的是obj参数是否支持show方法，而不关心obj的类型。因此Simple类和非Simple类都是可接受的。C++实现这样的方法需要使用template语法。Python作为一种弱类型语言，他天生就具备template能力。<br />
<br />
<br />
 
            </div>
        </content>
        <dc:subject>python</dc:subject>
<dc:subject>Thinking In Python</dc:subject>

    </entry>
    <entry>
        <link href="http://www.luochunhui.com/id/545" rel="alternate" title="【翻译】Thinking in Python (三) 建立应用框架" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2010-07-05T00:11:30Z</published>
        <updated>2010-07-21T17:59:55Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=545</wfw:comment>
    
        <slash:comments>2</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=545</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/545</id>
        <title type="html">【翻译】Thinking in Python (三) 建立应用框架</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                应用框架提供一个或一组类，通过继承的方式可以方便的建立一个应用。你可以根据需求，重用框架中的代码，或者根据自己的需求重载他们。我们通过模板方法（Template Method）来对应用框架做一个基本概念的认识。它在基类中隐藏了底层的逻辑驱动方法，只提供了几个公开的具体的实现接口（其中一部分你必须重载他们，以实现自己的需求）。<br />
<br />
比如，当你需要建立一个java小应用时，你就必须使用到应用框架。从JApplet继承，并重载init()方法。applet机制（他是一种模板方法）将完成屏幕输出，事件处理，大小适应等。<br />
<br />
<br />
模板方法<br />
<br />
模板方法中很重要的一个特性是几哦定义一个基础类，这个类不能够被改变。一般，他包括一个私有或final方法。在执行过程中，由这个私有方法，通常用作初始化，去调用其他的一些内部方法，<br />
<br />
<pre name="code" class="python"> 
#: c03:TemplateMethod.py 
# Simple demonstration of Template Method. 
 
class ApplicationFramework: 
  def __init__(self): 
    self.__templateMethod() 
  def __templateMethod(self): 
    for i in range(5): 
      self.customize1() 
      self.customize2() 
 
# Create a "application": 
class MyApp(ApplicationFramework): 
  def customize1(self): 
    print "Nudge, nudge, wink, wink! ", 
  def customize2(self):  
    print "Say no more, Say no more!" 
 
MyApp() 
#:~
</pre><br />
<br />
基类的构造函数在一些必要的初始化过程之后，开始执行应用引擎（模板方法）。终端开发者只需要简单的提供customize1( ) 和 customize2( )两个方法，应用程序就可以运行了。<br />
<br />
贯穿本书，我们会多次看到模板方法。<br />
 
            </div>
        </content>
        <dc:subject>python</dc:subject>
<dc:subject>Thinking In Python</dc:subject>

    </entry>
    <entry>
        <link href="http://www.luochunhui.com/id/547" rel="alternate" title="alias rm='mv --target-directory ~/.Trash'" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2010-07-08T01:13:48Z</published>
        <updated>2010-07-08T02:40:10Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=547</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=547</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/547</id>
        <title type="html">alias rm='mv --target-directory ~/.Trash'</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                RT，功能：将rm操作转化为mv操作<br />
<br />
再高级一点，mv的时候如果遇到同名，就自动加上数字后缀。<br />
<br />
<pre name="code" class="python"> 
alias rm='mv --verbose -f --backup=numbered --target-directory ~/.Trash/'
</pre><br />
<br />
<br />
唉。。这篇BLOG包含了血泪啊。。 
            </div>
        </content>
        
    </entry>
    <entry>
        <link href="http://www.luochunhui.com/id/544" rel="alternate" title="【翻译】Thinking in Python (二) 设计模式概念介绍" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2010-07-03T23:25:57Z</published>
        <updated>2010-07-08T01:14:21Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=544</wfw:comment>
    
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=544</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/544</id>
        <title type="html">【翻译】Thinking in Python (二) 设计模式概念介绍</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                设计模式能帮助你获得别人的成功经验，减少自己在摸索过程中的错误。 --Mark Johnson.<br />
<br />
可以讲，面向对象设计的发展史，就是设计模式的发展史。《设计模式》一书是设计模式发展中的里程碑著作。它描述了23中不同的面向对象解决方案。在这本书中，主要的设计模式都附有示例。Gamma四人组的这本书绝对值得你去阅读。它是面向对象开发人员所必须的了解的。<br />
<br />
接下来本书将通过一些实例来介绍设计思想的分析过程，从开始状态，到理性思考，再到分析方法的改进，最终确定一种更合适的设计。这个流程经过了很长时间的提炼，你也可以将他作为一个参考原型，用来分析特殊问题和改进。<br />
<br />
<br />
什么是设计模式<br />
<br />
最开始，你可以将设计模式理解为一种用来组织类结构的聪明的有效的方法，它是许多人的的经验总结和归纳。一般他们都具有很好的的通用性和可扩展性。某一个设计模式可能能够解决你所遇到的问题，但并非和你的逻辑完全一致。<br />
<br />
虽然我们称它为“设计模式”，但他和设计并没有太多关系。一个设计模式和传统意义中的分析，设计，实施是不同的。设计模式体现的是一种思维模式，他时常出现在分析阶段或更高级别的设计阶段。但讽刺的是，设计模式通常描诉一些具体实现代码，它和底层设计或实施密切相关（而经常的，你只有在到达这一阶段才会意识到，你需要一个设计模式来帮助你解决问题）<br />
<br />
设计模式基本概念和程序设计的基本概念相当，只是在其基础之上，增加了一个抽象层概念而已。 任何的抽象都是建立在具体细节之上的，抽象的动力在于如何封装变化。或者说，当需要修改一处代码时，你不会影响到其他的功能。使用设计模式可以花很少的成本，来可以降低维护成本，也能提升代码的可理解性。<br />
<br />
通常，程序设计中最难的问题就是如何编写优雅而易于维护的代码。这样的代码成本我们称它为“线性变化”（这里的线性，是指一种增长曲线，而不是线性队列这一容器类型）。这意味着，找到未来最重要的变化，或者说找到最大的变化成本显得格外重要。一旦你找到了他们，你就需要考虑，如何设计你的代码结构，来减少这些变化风险。<br />
<br />
设计模式的目的是在代码中关联变化。通过这一个理解，上面的代码中已经体现了一些设计模式的思想。类继承可以看成是一种设计模式，他允许你在各个子类中编写独立的和父类不同的行为。组合也可以看成是一种设计模式，他允许你动态或静态的改变类中的组合对象行为，就像改变类本身行为一样。<br />
<br />
另一种设计模式是迭代器。在Python之初，你就可以隐晦的使用到它，在Python2.2，它作为一种重要的特性被提炼了出来。迭代器隐藏了容器内部的元素，通过迭代来逐个访问容器中的各个元素。同时，你可以写一些通用的代码来实现顺序访问，而不用关心该容器是队列的类型。你的通用方法能够被任何一个提供迭代器的队列调用。<br />
<br />
<br />
模式分类<br />
<br />
当前，大量的设计模式被提了出来，开发人员认为设计模式的就是“好”的，但另一部分人认为这是词汇爆炸，或者说是词汇污染。在反复思考后，我用几个阶段来定义模式：<br />
<br />
1. 惯用法： 在不同的语言中，我们通常有一些写代码的惯用习惯，比如在C中对数组的for循环遍历（特别是防止越界的方法）<br />
<br />
2. 特殊的设计： 为了解决一些特殊的问题，我们说采用的特殊的处理方式。它可能设计的很巧妙，但它并不通用。<br />
<br />
3. 标准设计： 它可以解决某一种问题。这种设计比较通用，而且考虑了重用。<br />
<br />
4. 设计模式： 它可以解决某一类相似的问题。在使用标准设计一段时间之后，它才又可能被抽象出来，用来解决这一类的相似问题。<br />
<br />
我发现这种透视图的方法很管用，他展示了哪一等级是最合适的。这并不说明，哪一种优于另一种。将所有问题都应用于设计模式是没有意义的，它只会浪费你的时间。设计模式不是被意外发现或研究出来的，而应该建立在对一些巧妙方法的使用经验和总结之上。<br />
<br />
还有一些设计模式分类方法，如设计模式分析或设计模式架构进行分类。<br />
<br />
<br />
设计结构<br />
<br />
我在设计模式分类上纠结了很久。我发现，GoF四人组提出的分类很晦涩，而且不是每次都管用。很明显的，构造模式这一分类可以告诉你如何建立一个对象。但它还不够明确，他还是一个设计模式组。它无法清晰的说明：“嗨，毫无疑问，你这里可以使用结构模式”。这样的分类方法，很难让我找到一种解决方案（我承认，我也许错过了某一些细节）。<br />
<br />
在这一问题上，一开始我显的十分吃力。首先我发现到GoF设计模式中有一些基础设计模式很相似，而且它们所针对的，也是一些相似的问题。经验告诉我，这些设计模式并没有产生多大的作用。一个有用的方法是分析问题，并找到问题和可能出现问题之间的联系。<br />
<br />
后来，我开始收集一些基本的设计结构，并试图找到这些设计结构和设计模式之间的联系，特别是在一些公认的优秀的系统中，他们是怎么设计的。目前我已经总结了一个列表（我以后可能会使用一些其他的方法，目前还并不成熟）<br />
<br />
以下是一个草案，它们并不会全部出现在最终终稿中。如果你有任何的建议，或者能够找到他们和设计模式之间的关系，请不吝指教。<br />
<br />
<ul>
<li>封装： 自我控制的一种模型，包含数据和行为</li>
<li>聚合</li>
<li>本地化</li>
<li>分离</li>
<li>隐藏</li>
<li>保护</li>
<li>连接</li>
<li>隔离</li>
<li>行为变化</li>
<li>通知</li>
<li>转化</li>
<li>镜像: “并行的实现方式”</li>
<li>映射  “跟踪变化，但有些许变化” (也可以理解为“代理”的一个变种).</li>
</ul><br />
<br />
设计准则<br />
<br />
当我把我的想法发布到我的新闻列表中时，我收到了不少的有用的反馈，但很多都超出了设计结构所讨论的范围。这让我觉得，一个设计准则列表也是相当有用的。但作用不同，在思考设计时，这些准则用来提出一些疑问，或者说，当作一个核查表。<br />
<br />
<ul>
<li>保持平常，不要让人感到惊讶</li>
<li>能够容易的应用于常用的场景，同时有可能应用于不常见的场景。</li>
<li>一致性 我非常肯定的需要做到这一点，特别是在Python中。随意的规则将打乱程序中的正常秩序，而且会使将死开发效率。效率的降低会随大量规则的引入和成指数级增长。</li>
<li>得墨忒耳定律： "不好和陌生人说话"，一个对象只应该访问自己，自己的属性和自己的方法。</li>
<li>减法原则： 一个好的设计完成之后，你应该不能够再从他内部移走什么。</li>
<li>在通用设计之前保持简单： （简单的就是最好的）。一个常见的问题是，一个框架常被设计的很通用，并不针对某一个特定的系统。它增加了大量的不常用，滥用甚至是不会用到的属性，这往往使人感到头晕。大部分开发都是针对特定的系统的，通用性对他们往往没有用。最好的通用型是建立在明确的需求文档之上的。这个规则和“封装并适应变化”又一定冲突。当然，有一条是可以实现的：越简单的解决方法也会越通用。</li>
<li>自反性： 一个抽象一个类，一个类一个抽象。这也被成为同质化</li>
<li>独立，或正交性： 他和隔离，封装和变化相关，也是低耦合高内聚的体现</li>
<li>有且仅有一次：避免复制逻辑代码或结果。</li>
<li>这些想法还在进行头脑风暴中，我希望你在你的分析过程中，能够提出一些有用的想法。其他的想法也在分析过程中作为核查表来使用。
</ul><br />
<br />
<br />
单例<br />
<br />
可能单例是最简单的设计模式了。他提供一种方式，用来构建并只构建一个实例。为了实现这一个目的，你需要对对象的构造函数加以调整。一个便捷的方式是使用通过代表的形式，使用递归的方式建立子类:<br />
<pre name="code" class="python">
#: c01:SingletonPattern.py
class OnlyOne:
	class __OnlyOne:
		def __init__(self, arg):
			self.val = arg
		def __str__(self):
			return `self` + self.val
	instance = None
	def __init__(self, arg):
		if not OnlyOne.instance:
			OnlyOne.instance = OnlyOne.__OnlyOne(arg)
		else:
			OnlyOne.instance.val = arg
	def __getattr__(self, name):
		return getattr(self.instance, name)

x = OnlyOne('sausage')
print x
y = OnlyOne('eggs')
print y
z = OnlyOne('spam')
print z
print x
print y
print `x`
print `y`
print `z`
output = '''
<__main__.__OnlyOne instance at 0076B7AC>sausage
<__main__.__OnlyOne instance at 0076B7AC>eggs
<__main__.__OnlyOne instance at 0076B7AC>spam
<__main__.__OnlyOne instance at 0076B7AC>spam
<__main__.__OnlyOne instance at 0076B7AC>spam
<__main__.OnlyOne instance at 0076C54C>
<__main__.OnlyOne instance at 0076DAAC>
<__main__.OnlyOne instance at 0076AA3C>
'''
#:~
</pre><br />
内联类以双下划线命名，代表私有类，这样用户无法直接访问到他。内联类应该实现所有你需要的功能，就像他不是一个内联类一样。外部封装类负责内联类的构建，第一次调用将建立一个OnlyOne类，它将初始化一个内联类的实例，再次调用他将忽略实例化操作。<br />
<br />
访问将通过委托的方式，使用__getattr__()的方法，来将调用委托给单例。在输出中你可以看到多个OnlyOne对象被建立了，但__OnleOne实例只有一个。虽然各个OnlyOne实例不同，但他们都委托给同一个__OnlyOne实例。<br />
<br />
上面的方法并没有限制你只能建立一个对象，这也是一种建立共享对象池的技术。然而共享对象池有时候会带来一些问题。你可以使用另一种当时来解决：<br />
<br />
注意这里的实现变化，类使用了__new__方法，该方法与Pyhton2.2被引入。<br />
<br />
<pre name="code" class="python">
#: c01:NewSingleton.py
class OnlyOne(object):
	class __OnlyOne:
		def __init__(self):
			self.val = None
		def __str__(self):
			return `self` + self.val

	instance = None
	def __new__(cls): # __new__ always a classmethod
		if not OnlyOne.instance:
			OnlyOne.instance = OnlyOne.__OnlyOne()
		return OnlyOne.instance

	def __getattr__(self, name):
		return getattr(self.instance, name)
	def __setattr__(self, name):
		return setattr(self.instance, name)

x = OnlyOne()
x.val = 'sausage'
print x
y = OnlyOne()
y.val = 'eggs'
print y
z = OnlyOne()
z.val = 'spam'
print z
print x
print y
#<hr />
output = '''
<__main__.__OnlyOne instance at 0x00798900>sausage
<__main__.__OnlyOne instance at 0x00798900>eggs
<__main__.__OnlyOne instance at 0x00798900>spam
<__main__.__OnlyOne instance at 0x00798900>spam
<__main__.__OnlyOne instance at 0x00798900>spam
'''
#:~
</pre><br />
<br />
Alex Martelli发现，有时候我们确实需要建立一个单例，来存储一组状态信息。也就是说你可以建立根据需求，建立任意多个对象，但他们的状态信息都是一样的。他的实现代码如下，使用了__dict__技术来存储一个静态的共享存储区域。<br />
<pre name="code" class="python">
#: c01:BorgSingleton.py
# Alex Martelli's 'Borg'
class Borg:
	_shared_state = {}
	def __init__(self):
		self.__dict__ = self._shared_state

class Singleton(Borg):
	def __init__(self, arg):
		Borg.__init__(self)
		self.val = arg
	def __str__(self): return self.val

x = Singleton('sausage')
print x
y = Singleton('eggs')
print y
z = Singleton('spam')
print z
print x
print y
print `x`
print `y`
print `z`
output = '''
sausage
eggs
spam
spam
spam
<__main__.Singleton instance at 0079EF2C>
<__main__.Singleton instance at 0079E10C>
<__main__.Singleton instance at 00798F9C>
'''
#:~
</pre><br />
<br />
这和SingletonPattern.py文件的作用是一样的，但显得更加优雅。之前的例子中我们需要些一些代码将单例的行为和外部类关联起来，但这里Borg的代码使用了继承，更方便进行重用。<br />
<br />
通过包装或定义元类的方式也可以实现单例。首先我们来看看第一个方式，主类被另一个类所包装，他比较像类装饰模型（装饰将在本书后面继续讨论）：<br />
<pre name="code" class="python">
#: c01:SingletonDecorator.py
class SingletonDecorator:
	def __init__(self,klass):
		self.klass = klass
		self.instance = None
	def __call__(self,*args,**kwds):
		if self.instance == None:
			self.instance = self.klass(*args,**kwds)
		return self.instance

class foo: pass

foo = SingletonDecorator(foo)
x=foo()
y=foo()
z=foo()
x.val = 'sausage'
y.val = 'eggs'
z.val = 'spam'
print x.val
print y.val
print z.val
print x is y is z
#:~
</pre><br />
<br />
第二种方法是使用元类。这一章我还没有完全明白，但他看起来很有趣很强大。（注意，Python2.2改进和简化了元类的语法，因此，以下的列子可能需要改写了。）<br />
<br />
<pre name="code" class="python">
#: c01:SingletonMetaClass.py
class SingletonMetaClass(type):
	def __init__(cls,name,bases,dict):
		super(SingletonMetaClass,cls)\
			.__init__(name,bases,dict)
		original_new = cls.__new__

		def my_new(cls,*args,**kwds):
			if cls.instance == None:
				cls.instance = \
					original_new(cls,*args,**kwds)
				return cls.instance
			cls.instance = None
			cls.__new__ = staticmethod(my_new)

class bar(object):
	__metaclass__ = SingletonMetaClass
	def __init__(self,val):
		self.val = val
	def __str__(self):
		return `self` + self.val

x=bar('sausage')
y=bar('eggs')
z=bar('spam')
print x
print y
print z
print x is y is z
#:~
</pre><br />
<br />
练习:<br />
修改BorgSingleton.py,使其使用__new__方法<br />
<br />
 
            </div>
        </content>
        <dc:subject>Python</dc:subject>
<dc:subject>翻译</dc:subject>

    </entry>
    <entry>
        <link href="http://www.luochunhui.com/id/162" rel="alternate" title="在linux(Ubuntu)下安装subversion" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2007-01-15T22:13:54Z</published>
        <updated>2010-04-20T21:51:59Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=162</wfw:comment>
    
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=162</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/162</id>
        <title type="html">在linux(Ubuntu)下安装subversion</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                1。安装subversion和apache2的组件（已经认为您已经安装了apache2），<br />
<blockquote><br />
<pre name="code" class="bash"> sudo apt-get install subversion subversion-tools  libapache2-svn</pre><br />
</blockquote><br />
<br />
在/etc/apache2/mods-enabled中会多出来一下几个链接文件（实际文件在mods-available中，我们不需要去管，只需要关注enabled目录就成）：<br />
<blockquote><br />
dav_fs.load  dav_svn.conf dav_fs.conf  dav.load dav_svn.load <br />
</blockquote><br />
<br />
2。建立svn数据库<br />
<pre name="code" class="bash">sudo svnadmin create /var/svn </pre><br />
<br />
<pre name="code" class="bash">ls /var/svn</pre><br />
你将得到这样的结果，则说明建立成功<br />
<blockquote> conf  dav  db  format  hooks  locks  README.txt</blockquote><br />
<br />
3。配置apache<br />
<pre name="code" class="bash">
cd /etc/apache2/mods-enabled
sudo vi dav_svn.conf
</pre><br />
<br />
<br />
按照提示去掉一些文件注释，最终的文件看起来如下<br />
<pre name="code" class="bash">
# dav_svn.conf - Example Subversion/Apache configuration
#
# For details and further options see the Apache user manual and
# the Subversion book.

# <Location URL> ... </Location>
# URL controls how the repository appears to the outside world.
# In this example clients access the repository as http://hostname/svn/
<Location /svn>

  # Uncomment this to enable the repository,
    DAV svn

  # Set this to the path to your repository
    SVNPath /var/svn

  # The following allows for basic http authentication.  Basic authentication
  # should not be considered secure for any particularly rigorous definition of
  # secure.

  # to create a passwd file
  # # rm -f /etc/apache2/dav_svn.passwd
  # # htpasswd2 -c /etc/apache2/dav_svn.passwd dwhedon
  # New password:
  # Re-type new password:
  # Adding password for user dwhedon
  # #

  # Uncomment the following 3 lines to enable Basic Authentication
    AuthType Basic
    AuthName "Subversion Repository"
    AuthUserFile /etc/apache2/dav_svn.passwd

  # Uncomment the following line to enable Authz Authentication
  # AuthzSVNAccessFile /etc/apache2/dav_svn.authz

  # The following three lines allow anonymous read, but make
  # committers authenticate themselves.

  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require valid-user
  </LimitExcept>

</Location>
</pre><br />
<br />
或者象这样来实现独立的域名情况：<br />
<pre name="code" class="bash">
<VirtualHost 127.0.0.10>
        ServerName svn.luochunhui.com
        DocumentRoot /var/svn

      <Location />
                DAV svn
                SVNPath /var/svn
                AuthType Basic
                AuthName "Subversion Repository"
                AuthUserFile /etc/apache2/dav_svn.passwd
                <LimitExcept GET PROPFIND OPTIONS REPORT>
                        Require valid-user
                </LimitExcept>
        </Location>
</VirtualHost>
</pre><br />
<br />
<br />
4。建立密码文件<br />
建立第一个用户需要加-c参数<br />
<blockquote><br />
<pre name="code" class="bash">
sudo htpasswd2 -c /etc/apache2/dav_svn.passwd username
</pre><br />
</blockquote><br />
输入两次密码<br />
建立其他用户：<br />
<blockquote><br />
<pre name="code" class="bash">
sudo htpasswd2 /etc/apache2/dav_svn.passwd username2
</pre><br />
</blockquote><br />
注意没有加-c，加-c的话会清除掉以前存在的密码。<br />
如果username2为已存在用户，那这句命令的意义就是修改密码<br />
<br />
5.重启apache<br />
<blockquote><br />
<pre name="code" class="bash">sudo apache2 -k restart</pre><br />
</blockquote><br />
如果一切正常的话，使用浏览器打开http://127.0.0.1/svn 应该看到如下信息<br />
<blockquote>Revision 0: /<br />
Powered by Subversion version 1.3.1 (r19032).</blockquote><br />
<br />
OK,安装完成<br />
你可以对他进行一些import，commit等操作了<br />
<br />
导入版本的文件框架<br />
<pre name="code" class="bash">
mkdir -p tmp/lab.luochunhui.com/trunk tmp/eemap/trunk #如果你有其他已经写好的需要一起导入的文件，cp过来让在相应的trunk目录下，然后下一步。
svn import tmp http://127.0.0.10/ #更具提示输入message信息和用户，密码。
</pre><br />
我在实验时发现有权限问题，这是你可能需要修改/var/svn的权限为可读写<br />
<pre name="code" class="bash">
sudo chmod -R 777 /var/svn
</pre><br />
然后再继续执行上面的import操作。<br />
现在使用浏览器打开http://127.0.0.10,可以得到<br />
<blockquote><br />
Revision 1: /<br />
<br />
    * eemap/<br />
    * lab.luochunhui.com/<br />
</blockqote><br />
<br />
继续checkout和commit吧，祝你有一个愉快的subversion。 
            </div>
        </content>
        <dc:subject>subversion</dc:subject>
<dc:subject>Ubuntu</dc:subject>
<dc:subject>技术</dc:subject>

    </entry>
    <entry>
        <link href="http://www.luochunhui.com/id/540" rel="alternate" title="Ubuntu 9.10/10.4解决Eclipse按钮问题" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2010-04-15T04:27:42Z</published>
        <updated>2010-04-15T04:27:42Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=540</wfw:comment>
    
        <slash:comments>1</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=540</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/540</id>
        <title type="html">Ubuntu 9.10/10.4解决Eclipse按钮问题</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                Ubuntu 9.10及10.4之后，使用的新的GDK，导致部分使用老GDK的程序出现异常，主要包括Eclipse, QQ<br />
修改方式是将设置变量，支持原来的GDK模式<br />

1. 建立一个 ~/bin/eclipse<br />
文件内容：<br />
<pre name="code" class="bash"> 
export GDK_NATIVE_WINDOWS=true #设置GDK_NATIVE_WINDOW
/opt/eclipse/eclipse  #启动
</pre>

2. 使用 ~/bin/eclipse 来启动eclipse<br />

linux QQ的修改也是一样， 由于qq的启动文件是sh文本脚本，可以直接修改启动文件，<br />
修改：/usr/bin/qq <br />
在第二行加上： <br />
<pre name="code" class="bash"> 
export GDK_NATIVE_WINDOWS=true
</pre>

 
            </div>
        </content>
        <dc:subject>ubuntu</dc:subject>

    </entry>
    <entry>
        <link href="http://www.luochunhui.com/id/334" rel="alternate" title="在apache配置中修改php.ini中的变量" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2007-08-17T22:03:04Z</published>
        <updated>2010-04-07T06:22:33Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=334</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=334</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/334</id>
        <title type="html">在apache配置中修改php.ini中的变量</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                如果机器支持apache配置文件.htaccess（一般虚拟机都是支持的），但是并不容许你修改php.ini文件时，你可以使用以下代码来修改一些变量：<br />
<em>只适用于php做为apache的module的情况</em><br />
<pre name="code" class="xml">
<IfModule mod_php5.c>  
php_value include_path ".:/usr/local/lib/php;" 
</IfModule> 
<IfModule mod_php4.c>  
php_value include_path ".:/usr/local/lib/php" 
</IfModule> 
</pre>
但是，不要使用
<pre name="code" class="xml">
<IfModule mod_php5.c>  
php_value error_reporting   E_ALL
</IfModule> 
</pre>
这样的内容，因为E_ALL是php.ini中定义的常量，在apache中是无效的，任何没有定义的常量都被会解释为0或者空值。<br />
因此以上内容将被解释为不报告任何错误，而不是所有错误。<br />

如果php是做为cgi加载的，那么你可以通过ini_set来实现<br />
<pre name="code" class="php">
$include_path = ini_get('include_path');
ini_set('include_path', $include_path.':/home/rollenc/myphplib'); //注意Linux目录分割符是 : 和windows使用的 ; 不同
</pre> 
            </div>
        </content>
        <dc:subject>apache</dc:subject>
<dc:subject>PHP</dc:subject>

    </entry>
    <entry>
        <link href="http://www.luochunhui.com/id/516" rel="alternate" title="popen实现PHP并发方法" />
        <author>
            <name>rollenc</name>
                    </author>
    
        <published>2009-04-24T17:20:49Z</published>
        <updated>2010-04-07T06:19:46Z</updated>
        <wfw:comment>http://www.luochunhui.com/wfwcomment.php?cid=516</wfw:comment>
    
        <slash:comments>0</slash:comments>
        <wfw:commentRss>http://www.luochunhui.com/rss.php?version=atom1.0&amp;type=comments&amp;cid=516</wfw:commentRss>
    
            <category scheme="http://www.luochunhui.com/categories/38" label="技术" term="技术" />
    
        <id>http://www.luochunhui.com/id/516</id>
        <title type="html">popen实现PHP并发方法</title>
        <content type="xhtml" xml:base="http://www.luochunhui.com/">
            <div xmlns="http://www.w3.org/1999/xhtml">
                用途: 当业务需要调用一个比较耗时外部资源时使用， 最常见的是从外部API获取相关内容<br />
<br />
使用方法： <br />
1. 建立外部资源脚本。 如示例中使用t.sh。 当然， 也可以直接使用curl等命令行<br />
2. 准备好参数， 提供给pipe脚本<br />
2. 使用ｐｏｐｅｎ调用脚本。 调用之后，就不用关心了。<br />
3. 开始其他的和pipe不相关的逻辑处理<br />
4. 其他处理完成之后， 使用fgets等方式，获取ｐｏｐｅｎ的数据<br />
<br />
<br />
示例代码：<br />
<br />
php程序：<br />
<pre name="code" class="php">
# get argument for pipe here if it has.

#start pipe
echo 'call ｐｏｐｅｎ start: '. date("H:i:s"), "\n";
$pipe = ｐｏｐｅｎ(dirname(__FILE__) . '/t.sh', 'r');
echo 'call ｐｏｐｅｎ end: '. date("H:i:s"), "\n";

#Other code here
sleep(5);
echo "Here is my code. time: " . date("H:i:s"), "\n";

#read pipe result
while ($s = fgets($pipe,1024)) {
    echo $s;
}
</pre><br />
<br />
pipe脚本：<br />
<pre name="code" class="bash">
echo 1, `date +%T`;
sleep 1;
echo 2, `date +%T`;
sleep 10;
echo 3, `date +%T`;
</pre><br />
<br />
输出如下：<br />
<pre name="code" class="bash">
call ｐｏｐｅｎ start: 10:16:40
call ｐｏｐｅｎ end: 10:16:40
Here is my code. time: 10:16:45
1, 10:16:40
2, 10:16:41
3, 10:16:51
</pre><br />
<br />
代码方面， 我们有三个sleep。<br />
php中一个 sleep 5,<br />
sh中两个sleep， 10＋1<br />
如果使用串行的方式， 那么用时应该是10＋1＋5 ＝ 16秒。<br />
而使用pipe方式， 用时仅为：max(php, pipe) = max(5,11) = 11秒。<br />
<br />
PS:很抱歉，空间服务商看起来不喜欢ｐｏｐｅｎ这个字眼，　所以只能将起替换成全角的了。请在使用时，替换一下吧：）<br />
 
            </div>
        </content>
        <dc:subject>php</dc:subject>

    </entry>

</feed>