2008年11月8日星期六

Patterns in Python

site from http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html

Patterns in Python

Author: Duncan Booth
Contact: duncan@rcp.co.uk 

Abstract

What design patterns are applicable to Python? Some patterns are an intrinsic part of Python, other patterns require some careful coding to get the best from them. What new patterns appear in Python?

1   What is a pattern?

The definitive reference book Design Patterns [GoF] describes a set of patterns for object-oriented software design. This book is often referred to as the 'Gang of Four' book (or even GoF) after the four authors (Gamma, Helm, Johnson and Vlissides).

A design pattern describes a problem that occurs over and again and the core of a solution to that problem in such a way that it may be used in many different ways. That last point is important, when we talk about design patterns in software, we aren't talking about things that can be neatly tied up into a class or library implementation and just used, we are talking about techniques that are applied in different ways. Recognising when the same technique is being used in a different context allows us to apply our experiences across a much wider domain.

The GoF introduced a pattern vocabulary to the software community. Each pattern as they describe it has:

  1. pattern name which is a handle used to describe a design problem. Using a name lets us have a common vocabulary with other software developers.
  2. The problem describes when to apply a pattern.
  3. The solution describes the elements that make up the design, their relationships, responsibilities and collaborations.
  4. The consequences are the results and trade-offs of applying the pattern. Recognising the consequences of applying a pattern in one situation lets us better evaluate how appropriate the pattern may be in another.

Design Patterns gives outline implementions of patterns in C++ (and a supplementary book translated many of them into Smalltalk). However, it is apparent that while some patterns are largely independant of the language in which they are implemented, others either become inappropriate in another language, or virtually disappear.

This paper looks at a few of the common patterns, identifies what if anything is their equivalent in Python, and also considers whether Python has its own patterns different than the C++ patterns.

Others have looked at how Design Patterns relate to Python, most notably Vespe Savikko [VS], and Alex Martelli [AM], but as Python evolves, the ways you can implement these patterns are changing.

1.1   A word of warning

I was reading an article by Ron Jeffries [RJ] recently where he wrote:

Small Boy with a Patterns Book

After spending a bunch of time thinking about these ideas, over a few days now, I finally recognized in myself what I call "Small Boy with a Patterns Book". You can always tell when someone on your team is reading the Gang of Four book (Gamma, et al., Design Patterns). Every day or so, this person comes in with a great idea for a place in the system that is just crying out for the use of Composite, or whatever chapter he read last night.

There's an old saying: To a small boy with a hammer, everything looks like a nail. As programmers, we call into the same trap all too often. We learn about some new technology or solution, and we immediately begin seeing places to apply it.

Patterns are useful, they can also be addictive. Try not to overuse them.

2   Creational Patterns

The GoF identified several creational patterns. These patterns abstract the process of instantiating objects.

2.1   Factory

The most fundamental of patterns identified by the GoF are probably the Factory and Abstract Factory. The Factory pattern in a language such as C++ wraps the usual object creation syntax new someclass() in a function or method which can control the creation. The advantage of this is that the code using the class no longer needs to know all of the details of creation. It may not even know the exact type of object it has created. In other words it reduces the dependencies between modules.

A more advanced form of factory (Abstract Factory) provides the extra indirection to let the type of object created vary.

The factory pattern is fundamental in Python: where other languages use special syntax to indicate creation of an object, Python uses function call syntax as the (almost) only way to create any object: some of the builtin types such as int, str, list, and dict, have their own special syntax, but they all support factory construction as well.

Moreover, Python uses abstract factories for everything. The dynamic nature of the system means that any factory may be overridden.

For example, the following code:

 import random
  def listOfRandom(n):
         return [random.random() for i in range(n)] 

At first sight it looks as though this function will return a list of 10 pseudo-random numbers. However you can reassign random at the module level, and make it return anything you wish. Although at first this may sound like a crazy thing to do, in fact it is one of the reasons why Python is such a great language for writing unit tests. It is hard to write an automated test for a function with a pseudo-random result, but if you can temporarily replace the random number generator with a known, repeatable, sequence, you can have repeatable tests. Python makes this easy.

It is hard to say whether this really counts as a pattern in Python at all. At one level it is basic to the language, and does not involve actual code. On the other hand, the pattern is so well known that it is important to acknowledge that it corresponds to the Factory pattern.

Python 2.2 introduced a new way to control object creation. New-style objects (where object is the base class) allow a method __new__ to control the actual creation of the object. This may be seen as another form of the factory pattern, and one where there is actual Python code to implement it. We see more of this in the next section.

2.2   Singleton (and the Borg)

Intent

Ensure a class has only one instance and provide a global point of access to it.

One of the first patterns many programmers learn to identify as a pattern is the 'Singleton'. This is a pity, as in many ways it is rather more of an anti-pattern.

A singleton is an object which can only be instantiated once in a process. Not of course an object which you only happen to instantiate once, but rather an object which will resist all attempts to create multiple instances.

The singleton pattern is often used for a class controlling an application's access to a database, a network link to a server, a conection to the computer's registry and so on. This is a poor use of singleton. The application may only require a single database, but it isn't a requirement that there can only be one database connection. Maybe one day it will evolve into an application with two databases, so why write code to prevent that?

A more significant drawback of singleton is that it breaks testing. Unit tests often work by creating mock objects that look similar to real objects but have dummy implementations. If your code has built brick walls protecting that 'database' instance, then it becomes harder, or even impossible to temporarily stub it out (although very little is completely impossible in Python). Test driven development very quickly leads you to abandon large singletons.

Nevertheless, should you require it, it is easy to implement the singleton pattern in Python:

 >>> class Singleton(object):   
      _instance = None      
      def __new__(cls, *args, **kwargs):        
         if not cls._instance:         
            cls._instance = super(Singleton, cls).__new__(
                                    cls, *args, **kwargs) 
         return cls._instance   
>>> class C(Singleton):   
      pass  
 >>> class D(Singleton):    
     pass   
>>> c = C() 
>>> d = C() 
>>> id(c), id(d) 
(10049912, 10049912) 
>>> e = D() 
>>> f = D() 
>>> id(e) 
10113672 
>>> id(f) 
10113672 
>>> g = C() 
>>> id(g) 
10049912 
>>>  

This example creates a new mixin class Singleton. Each new subclass creates one instance and thereafter returns that instance. Further subclassing of C or D could be confusing, but by checking the type returned we can avoid the obvious errors.

It has been noted elsewhere [AM] that the requirement driving people to use the Singleton is not a requirement for a single instance at all. Rather it is a need for a shared state. This led Python Programmers to invent one of the few genuine Python Patterns with a name: The Borg.

The Borg pattern allows multiple class instances, but shares state between instances so the end user cannot tell them apart. Here is the Borg example from the Python Cookbook

 class Borg:
     __shared_state = {}
     def __init__(self):
         self.__dict__ = self.__shared_state
     # and whatever else you want in your class -- that's all! 

Problems with the Borg as a pattern start when you begin to write 'new style' classes. The __dict__ attribute is not always assignable, but worse any attributes defined within __slots__ will simply not be shared. The Borg is cool, but it isn't your friend.

There is another implementation of Singleton which is even simpler than the one given above. In fact, I'm sure every Python programmer has used this method, although many of them may have failed to recognise the Singleton pattern within it.

Consider this file (singleton.py):

"""This module implements the singleton pattern""" 

Simple, isn't it. You can access the singleton object using the import statement. You can set and access attributes on the object. Obviously in real life you might want a few methods, or some initial values, so just put them in the module.

Python modules are Singleton instances: another case of Python taking a design pattern and making it a fundamental part of the language.

3   Structural Patterns

3.1   Flyweight

Intent

Use sharing to support large numbers of fine-grained objects effeciently.

This is related to the singleton pattern. Whereas with singleton we wanted exactly one instance of an object, in some cases we need very many instances but not all of the objects need to be distinct.

For example, consider an application that handles stock market prices. Perhaps we have several portfolios, each of which contains a large number of underlying stock instruments. Each instrument holds some data (current and recent prices, daily high and low, etc.), but this data is common to the instrument wherever it is used. Each portfolio might record the amount of each instrument held, the date purchased, and the price at which it was purchased.

We have a choice here. We could store the portfolio specific data inside each instrument, but then instrument instances cannot be shared between portfolios. If we store them as part of the portfolio then we can have shared instrument classes:

# Model a financial instrument 
# The instrument class represents a financial instrument, 
# with updates arriving from some network source. 
# # N.B. As an example, this code is not threadsafe. 
# Real code might have to handle asynchronous updates to data. 
import weakref
  class Instrument(object):
     _InstrumentPool = weakref.WeakValueDictionary()
      def __new__(cls, name):
         '''Instrument(name)

         Create a new instrument object, or return an existing one'''
         obj = Instrument._InstrumentPool.get(name, None)
          if not obj:
             print "new",name
             obj = object.__new__(cls)
             Instrument._InstrumentPool[name] = obj
          return obj

      def __init__(self, name):
         '''Complete object construction'''
         self.name = name
         print "New instrument @%04x, %s" % (id(self), name)
          # ... connect instrument to datasource ...
  
  import unittest
  class InstrumentTests(unittest.TestCase):
     def testInstrument(self):
         ibm1 = Instrument("IBM")
         ms = Instrument("MS")
         ibm2 = Instrument("IBM")
         self.assertEquals(id(ibm1), id(ibm2))
         self.assertNotEquals(id(ibm1), id(ms))
         self.assertEquals(2, len(Instrument._InstrumentPool),
             "Total instruments allocated")
          # This bit assumes CPython memory allocation:
         del(ibm1)
         del(ibm2)
         self.assertEquals(1, len(Instrument._InstrumentPool),
             "Total instruments allocated")

  if __name__=='__main__':
     unittest.main() 

This code shows a simple way to create objects which share their state if they are created with compatible parameters. The two IBM objects are in fact only one object, but the MS object is separate.

If we run this code with the 'print' statements then we can see that although we only create two objects, the __init__ constructor is called all three times. This could be useful, for example, if we want the Instrument class to generate events to some Portfolio class further up the line.

D:\accu>instrument.py
 new IBM New instrument @7bd240, IBM new MS New instrument @7a80b8, MS New instrument @7bd240, IBM .
 ---------------------------------------------------------------------- 
Ran 1 tests in 0.020s  OK 

The weakref dictionary ensures that when nothing is actively using a particular instrument the storage for it may be automatically released. The actual behaviour of this may vary somewhat, for example the Java implementation of Python wouldn't actually release unused instruments until a garbage collection cycle.

4   Behavioural Patterns

4.1   Observer

Intent

Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Observer is one of the patterns I find myself using over and again, but until recently I never felt completely happy with my Python implementations of it.

You have two classes, the subject and an observer which registers itself with the subject and receives notification callbacks when data changes in the subject. I find the GoF form of this pattern somewhat limiting, because they describe a system where a subject class has a general 'notify' method used for everything (although they do suggest a mechanism for generating more selective events using aspects).

The implementation described here uses a more general, and I believe cleaner form of event generation which is based (loosely) on the event structure from Microsoft's .Net framework. It is best described starting with the intended use.

The actual example is taken from the GoF book, although of course the implementation is not. ClockTimer is a subject for storing and maintaining the time of day. It notifies its Observers every second.ClockTimer provides the interface for retrieving individual time units such as the hour, minute and second:

class ClockTimer:
         def GetHour(self):
                 return self._hour
         def GetMinute(self):
                 return self._minute
         def GetSecond(self):
                 return self._second
          TickEvent = Event()
         def OnTick(self):
                 ClockTimer.TickEvent.call(self, self.GetHour(),
                         self.GetMinute(), self.GetSecond())
          def Tick(self):
                 # update internal time-keeping state
                 # ...
                 self.OnTick() 

The Tick method gets called by an internal timer at regular intervals. It updates the internal state and calls the OnTick method to notify observers of the change.

The OnTick method fires the event with whatever parameters seem appropriate. Firing the event indirectly in this way allows subclasses to override the event handling.

Although we have a single Event in this class, the implementation allows for any number of different events to be defined.

Now, we can define a class DigitalClock that displays the time:

 class DigitalClock(Widget):
         def __init__(self, clockTimer):
                 self.__subject = clockTimer
                 clockTimer.TickEvent += self.Update
          def close(self):
                 self.__subject.TickEvent -= self.Update
          def Update(self, subject, hour, min, sec):
                 self.displayedTime = (hour, min, sec)
                 self.Draw()
          def Draw(self):
                 # draw the digital clock 

N.B. We need an explicit close method to be called on this object because there is a circular dependency (ClockTimer contains a reference to the UpdateMethod of the DigitalClock instance, and the DigitalClock instance stores a reference to the clockTimer). This means that a __del__ method would never be called. In cases where this could be a problem, one solution would be to define a WeakMethod class that simulates a bound method but only holds a weak reference to the instance.

The plumbing that allows this to work is as follows:

class Delegate:
     '''Handles a list of methods and functions
     Usage:
         d = Delegate()
         d += function    # Add function to end of delegate list
         d(*args, **kw)   # Call all functions, returns a list of results
         d -= function    # Removes last matching function from list
         d -= object      # Removes all methods of object from list
     '''
     def __init__(self):
         self.__delegates = []
      def __iadd__(self, callback):
         self.__delegates.append(callback)
         return self
      def __isub__(self, callback):
         # If callback is a class instance,
         # remove all callbacks for that instance
         self.__delegates = [ cb
             for cb in self.__delegates
                 if getattr(cb, 'im_self', None) != callback]
          # If callback is callable, remove the last
         # matching callback
         if callable(callback):
             for i in range(len(self.__delegates)-1, -1, -1):
                 if self.__delegates[i] == callback:
                     del self.__delegates[i]
                     return self
         return self
      def __call__(self, *args, **kw):
         return [ callback(*args, **kw)
             for callback in self.__delegates] 

The delegate class maintains a list of callbacks (so we can have several observers for a single subject). The only operations supported on a delegate are to add a function, remove a function or call all of the functions in the delegate. The callback functions are stored in order (so first added is also first called), and removed in last in/first out order.

We could create the Delegate instances in __init__, but there is a potential drawback to this. If we created a class that could fire many events, but events mostly went unused, we should have a lot of delegates created for no reason. The Event class below creates delegates only when they are needed, and the indirect call used in the subject class supports this:

class Event(property):
     '''Class event notifier
     Usage:
         class C:
             TheEvent = Event()
             def OnTheEvent(self):
                 self.TheEvent(self, context)
          instance = C()
         instance.TheEvent += callback
         instance.OnTheEvent()
         instance.TheEvent -= callback
     '''
     def __init__(self):
         self.attrName = attrName = "__Event_" + str(id(self))
         def getEvent(subject):
             if not hasattr(subject, attrName):
                  setattr(subject, attrName, Delegate())
             return getattr(subject, attrName)
         super(Event, self).__init__(getEvent)

      def call(self, subject, *args, **kw):
         if hasattr(subject, self.attrName):
             getattr(subject, self.attrName)(subject, *args, **kw) 

Within the ClockTimer class a reference to instance.TickEvent will create the Delegate. The Delegate could be called using self.TickEvent(args), but this would always create it. By calling it instead using ClockTimer.TickEvent.call(args) we avoid doing this unneccessarily.

4.2   Iterators and Generators

Intent

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

The iterator pattern is one which Python has embraced fully, albeit in a slightly simpler form than the one proposed by the GoF. GoF iterators have methods:

 First()
 Next()
 IsDone()
 CurrentItem() 

Python's iterator interface requires the following methods to be defined:

 __iter__()
      Returns self next()
          Returns the next value or throws StopIteration 

In addition, any object which supports iteration, but is not itself an iterator supports the iterable interface, i.e. it has a method __iter__() which creates a new iterator object of the appropriate type. It may also have additional methods for creating different types of iterator, but this is not required by the language.

The main difference in Python is that Python's iterators cannot be reset. If you want to iterate over a sequence more than once in Python, then you simply have to create multiple iterators.

Here is a simple example using Python's iterators to iterate over a binary tree structure. This involves walking the tree, and because each value is returned in order we must remember which nodes have been processed, and which we have yet to see. We could write the code recursively if we didn't need to keep suspending the iterator to return a result, but handling a stack manually in Python is actually pretty straightforward:

class Node(object):
     class NodeIterator:
         def __init__(self, node):
             self.stack = [node]
          def __iter__(self):
             return self
          def next(self):
             if not self.stack:
                 raise StopIteration
              node = self.stack.pop(-1)
             while isinstance(node, Node):
                 self.stack.append(node.right)
                 node = node.left
             return node
      def __init__(self, left, right):
         self.left = left
         self.right = right
      def __iter__(self):
         return Node.NodeIterator(self)

  import unittest
 class NodeTests(unittest.TestCase):
     def testNode(self):
         tree = Node(
                   Node('a', 'b'),
                   Node(
                       Node('c', 'd'),
                       'e'))
          self.assertEquals(['a', 'b', 'c', 'd', 'e'], list(iter(tree)))

  if __name__=='__main__':
     unittest.main() 

The main problem with this code is that it isn't immediately clear why it works. Why, if I want to return the left side of each branch before the right do I have to deal with the right node first? Why do I never (apparently) return the right hand node of anything?

Iterators often involve thinking backwards in this way. First we maintain our state so we can resume the iterator later on, then we wory about what to return on this iteration.

Also, of course, the unit test obscures the normal use of this code. Where I simply convert the iteration into a flat list to check that all the leaves came back in the correct order, normally we would have some code more like:

for leaf in tree:
         ... do something with the leaf ... 

Generators

Since Python 2.2 there has been special syntax in the language to make it easier to write iterators. Generators turn the process of iterating over an object on its head. The iterator object exists solely to maintain the state of the iteration, this is usually some sort of loop index, but in some cases the data structures can be much more complex. For example the same binary tree structure using a generator becomes:

from __future__ import generators
  class Node(object):
     def __init__(self, left, right):
         self.left = left
         self.right = right
      def __iter__(self):
         if (isinstance(self.left, Node)):
             for n in self.left:
                 yield n
         else:
             yield self.left
          if (isinstance(self.right, Node)):
             for n in self.right:
                 yield n
         else:
             yield self.right

  import unittest
 class NodeTests(unittest.TestCase):
     def testNode(self):
         tree = Node(
                   Node('a', 'b'),
                   Node(
                       Node('c', 'd'),
                       'e'))
          self.assertEquals(['a', 'b', 'c', 'd', 'e'], list(iter(tree)))

  if __name__=='__main__':
     unittest.main() 

The code isn't actually any shorter, but walking the tree has now become rather more obvious. If the left side is another node then we yield each leaf in turn, otherwise we just yield the leaf. Then we repeat on the right side either yielding each leaf in turn or yielding the leaf if that is all we have. Without the generator we were forced to abandon the 'obvious' recursive implementation, but the generator lets us suspend execution as each result is generated.

Other benefits of the generator are that it hides the need for another object type, and (rather suprisingly) it turns out that using a generator is actually much faster than simply calling a Python function repeatedly.

itertools

Iterators and generators may be combined to form pipelines, and the upcoming Python 2.3 includes a new builtin module with a variety of useful iterators. Because these iterators generate each result only as it is returned they provide a way to work with potentially infinite lists:

count([n])
Return consecutive integers starting with n
ifilter(predicate, iterable)
Return all elements x of iterable for which predicate(x) is true.
imap(function, *iterables)
Like map(), but returns an iterator rather than a list.
izip(*iterables)
Like zip(), except it returns an iterator.
repeat(obj)
Returns an iterator that yields obj an unlimited number of times.
times(n, [object])
Returns object a total of n times.

and many more.

It is too early to see how the Python community takes to this new support for iterators. So far there seem to be those (like myself) who see almost every problem as an opportunity for generators, and those who are steering well clear.

4.3   Command Dispatch Pattern

The GoF describe a Command pattern where a request is encapsulated as an object. Back in 1997, Guido van Rossum [GvR] identified a pattern that performs a similar function, but which is unique to dynamic languages such as Python, Perl &c. He gave it the name Command Dispatch.

Sadly, although use of this pattern is common through many Python programs, the name, and perhaps also the identification of this as a pattern, have largely been forgotten.

Suppose you have a class that needs to execute a number of different commands sent from some outside source. e.g. 'get()' and 'put()'. There are various ways to handle this such as:

if command == 'get':
     get()
 elif command == 'put':
     put()
 else:
     error() 

or:

dispatch_table = {
     'get': get,
     'put': put, }
  # Command dispatch:
if dispatch_table.has_key(command):
     func = dispatch_table[command]
     func()
else:
     error() 

but the one used by Python programmers everywhere is:

class Dispatcher:
      def do_get(self): ...
      def do_put(self): ...
      def error(self): ...
      def dispatch(self, command):
         mname = 'do_' + command
         if hasattr(self, mname):
             method = getattr(self, mname)
             method()
         else:
             self.error() 

As Guido put it: I find this approach super elegant and have used it many times.

You can find this pattern used throughout Python's libraries, including BaseHTTPServer, cmd, pydoc, repr, sgmllib, SimpleXMLRPCServer, urllib, distutils and so on.

5   Little patterns in Python

There are many other common idioms in Python which (depending on your viewpoint) are certainly patterns, although they are perhaps too small to count as Design Patterns. However, even if they don't count as fully fledged Design Patterns, the small patterns listed here are representative of how writing software in Python influences the way you think.

DSU

Decorate, Sort, Undecorate. The way in Python to do any but the simplest sorting. Instead of providing a comparison function for your objects, simply replace a list of objects with a list that sorts into the desired order using the builtin functions.

For example, to produce a list of files in the current directory sorted by their 'last modified' time:

 >>> files = glob.glob('*')
 >>> decorated = [ (os.stat(file).st_mtime, file) for file in files ] 
>>> decorated.sort()
>>> files = [ file for (time, file) in decorated ] 
>>> print files ['py.ico', 'pyc.ico', 'pycon.ico', 'default.tag',
      ... (long list of files here)
 ... 'Doc', 'Tools', 'INSTALL.LOG', 'win32', 'win32com', 'Lib'] 
>>>  

List comprehensions

Introduced in Python 2.0, list comprehensions let you build new lists by writing a description instead of a series of commands. This lets you think about what you are writing in a different way, which is one of the important features of design patterns, although the list comprehension on its own is too small to be a major pattern.

Bound methods

Coming to Python from other languages where functions and methods are not first class methods requires a definite mental gearshift. A common Python technique is to pass around bound methods or use them for micro-optimisations. e.g.

result = []
save = result.append
while somecondition:
     save(calculateValue()) 

Lists, tuples, and dictionaries

Everything in Python is an object, but not everything has to be a user-defined object. Thinking in terms of the builtin types is important to Python programmers. Partly this is because the builtin types can run faster or be less memory hungry, but there is another bonus in that code is often easier to understand when it uses more primitive but familiar types rather than customised classes everywhere.

Module as a script

Write every module as a script in Python (and the inverse, write every script as a module). By encapsulating the main code of a script in a block headed by if __name__=='__main__', any classes or functions in the script can be reused in other programs. Likewise adding the same block to a module allows tests use of the module outside the context of the program.

6   Conclusion

Design Patterns are very useful tools. They give you a language for thinking about the design and allow you to recognise familiar problems in new contexts. Recognising a pattern lets you immediately relate that pattern back to previous experiences both good and bad.

Some patterns are almost universal across programming languages but other patterns are specific to the features or even the syntax of a particular language. To become fluent in a programming language means not just understanding the syntax but also adopting a common pattern of thought with the other developers.

Even within a language possible implementations of patterns change as the language evolves. The examples given in this paper use new style classes, weak references, and properties. All features added to Python comparatively recently.

7   References

[GoF] Design Patterns, Elements of Reusable Object-Oriented Software; Erich Gamma, Richard Helm, Ralph Johnson, Jon Vlissides; 1995.
[AM] (12) Five Easy Pieces: Simple Python Non-Patterns; Alex Martelli, AB Strakt. http://www.aleax.it/Python/5ep.html
[VS] Design Patterns in Python; Vespe Savikko, Tampere University of Technology. http://www.python.org/workshops/1997-10/proceedings/savikko.html
[GvR] Command Dispatch Pattern; Guido van Rossum; Python Pattern-SIG mailing list, May 1997
[RJ] Adventures in C#: Some Things We Ought to Do; Ron Jeffries; Jan 2003 http://www.xprogramming.com/xpmag/acsMusings.htm

2008年11月7日星期五

初入职场“七宗罪”之――没事偷着乐

本文摘抄自http://info.china.alibaba.com/news/detail/v5003013-d1003297353.html
送与自己自勉


  "没事偷着乐"是《贫嘴张大民的幸福生活》中,生活在社会底层的主人公历经艰辛之后的一句无奈的感叹。但在有些人心中,它"升华"成了一种生活态度――厌 恶劳动,害怕艰苦,贪图享乐。但事实上,大多数情况下,这种生活态度的表现并非如此明显,它通常以各种很微妙的方式表现出来。

    两个大学生,一条起跑线

    曾经有两个应届大学毕业生D君和Q君,同时被公司招聘进来。两个人的学历相当,能力差别也不明显。原本的计划是要将二人培养成为优秀的编辑,以接替即将离职的老编辑。但是,干起活来两人不同的工作态度就完全表现出来了。

    新 手初上岗,就先让他们对将来的工作有所熟悉。对于大学生来说,修改、校对文章这些工作应该是很简单的,很快两人就做完了。忙完了一期杂志最紧张的排版出版 阶段,接下来的一个星期,办公室的空气显得有几分轻松。不过,老编辑都各有各的栏目,做完了上一期杂志,就有条不紊地开始准备下一期了。这两位新编辑此时 在干什么呢?

    没事偷着乐

    记得小时候,在家没事自顾玩,不帮忙收拾家务。老妈就骂我:"成了癞蛤蟆,不捅不跳!"没想到,大学毕业生中,也还有练就这种蛤蟆神功的高手。

   Q 君无事可干,开始上网看新闻。看新闻看腻味了,又开始和QQ上的好友疯狂聊天。聊得无趣了,就开始在QQ上搜索"谁在线上",专门找闲人聊天。公司有明文 规定,禁止上班时间玩游戏。于是他就苦等到中午下班休息时间跟其他同事玩上一把。下午上班,他也玩累了。于是就趴在桌子上打起了瞌睡。当然,堂堂大学生, 哪能这样天天呼呼大睡?过了几天,他带来一本书,下午无事就坐在办公室看起书来。原以为他在看英语或者计算机专业书,谁知编辑部副主任悄悄告诉我,他"无 意中"看到了那本书的名字。原来是本玄幻小说!

    唉……我几乎都要为他感到有几分悲哀了。让年轻人一连几天按时到公司来无所事事,也真难为他了。

    没事找事做

   D 君在做什么呢?虽然比Q君晚了一点,但是D君也很快完成了分配给他的工作任务。而后,他翻看了一下以前的杂志,跑到一位老编辑的桌边:"刘老师,给点活儿 干吧。"老刘编辑惊讶地看了他一眼,说:"哦,你等会儿吧。"谁知D君等了一会儿,又跑到另外一个老编辑身边:"张老师,给安排点事儿干吧。"

    他厚着脸皮跑到一个个老编辑那里讨活儿干。终于有些老编辑又给他一些简单的稿件,他拿着稿子就像得到了宝贝似的,三步并作两步赶回自己的座位,埋头开干了。做好了,又跑回老编辑那里:"刘老师,您看这样行吗?""张老师,您给指点指点?"

    于是老编辑们多多少少都对他的工作错误加以指点。后来发觉他干得不错,就慢慢把一些复杂的稿子交给他了。D君的业务能力水平由此开始直线攀升。

    而此时,Q君还在聊天、睡觉,看玄幻小说。

    截然不同的表现

    有 一天大家来到公司干了不到半小时,突然停电了!这时干什么好?不少老编辑都毫无准备,一方面着急工作进度,一方面却又无可奈何。于是纷纷打听何时来电,得 知"正在抢修"之后,也只好回到自己的座位翻看一下杂志。有的老编辑聚在一起吹牛,编辑部主任没有干涉――因为大家平时自由沟通交流的机会确实也不多。大 家都没有离开办公室,供电一恢复,就可以立即继续工作。

    过了半小时,来电了。大家赶快回到自己的位置开始工作。这时候,D君和Q 君却不见踪影了。我去找资料的时候,发现D君坐在会议室里面。原来他觉得办公室里面有几个老编辑在聊天,太吵,正好手头有几份打印出来的稿子,就躲到会议 室去改。我告诉他已经来电了,他立即收拾东西回了办公室。等我回到办公室,Q君依然不在。又过去了大约一小时,Q君回来了――他和读者服务部的MM一起上 楼顶放风筝去了!

    两种结局,一个道理

    一个月下来,新一期杂志的几大栏目都有了D君负责编校的文章。而Q君仍然只负责完成了几篇简单文章的编校。所有这些,编辑部的头儿看在眼里记在心里。于是,两个月过去,D君提前转正,独立负责一个小栏目;Q君却没有通过试用期考核,被解聘了。

    公司不是学校。虽然有工作任务的分配,但是没人会像学校的老师那样,从早读到晚自习,全面安排好你的课程表。通常情况下,只有工作任务和质量考核。如果你能 轻松完成分配给你的工作任务,你自认为能力强,价值高,却被埋没在一些简单工作里面,怎么体现出来?我想唯一的办法,就是主动去寻找,去做一些能体现你自 身价值的事情。

    "没事偷着乐"这种生活态度,在社会中有很多信徒。有人没监督就要偷懒,有人没检查就要出错,有人没加薪就坚决不多干一份活儿。他们还有一个共同点,就是羡慕成功人士的名誉、地位和物质生活,却总是忽视他们背后的艰辛。你是不是其中的一员呢?

2008年11月4日星期二

在Solaris 10下用SMF配置Subversion

Solaris 10下配置subversion有如下几个关键点:
  1. 获取subversion
  2. 配置subversion
  3. 设置subversion为系统服务
在获取subversion的时候,直接从subversion的官方网站难以获得二进制版本,最后用的是pkg-get从blastwave.org上获取的。参见www.blastwave.org/howto.html吧,要记得更新pkg库

花了不少时间从blastwave上down下二进制的subversion以及subversion的dependece二进制

subversion中的程序默认下载在/opt/csw/bin下面了

第二步配置subversion还是很简单的,从网络上能找到很多

第三步配置subversion成系统服务,以自动启动的方式运行。这里网络上很多都是用init.d/rc*.d这样的方法来弄,不过呢,这些已经是不建议的方式了。
solaris 10里面建议用SMF来完成管理,确实很方便。
具体的SMF就不讲了,Google下或者去sun的Bigadmin里面能看到很多。

(因为现在是根据回忆来写,有些路径或者文件名可能会打错。。。。)
我这里配置subversion是参考了/var/svc/manifest/network/utmp.xml这个文件,因为我的subversion也是一个network服务,类似utmp需要依靠多用户run-level
所以写了个subversion.xml如下
<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM '/usr/share/lib/xml/dtd/service_bundle.dtd.1'>
<service_bundle type='manifest' name='export'>
  <service name='network/subversion' type='service' version='0'>
    <create_default_instance enabled='true'/>
    <single_instance/>
    <dependent name='svnserve_multi-user' restart_on='none' grouping='optional_all'>
      <service_fmri value='svc:/milestone/multi-user'/>
    </dependent>
    <!-- 以脚本启动-->
    <exec_method name='start' type='method' exec='/lib/svc/method/svc-subversion' timeout_seconds='60'>
      <method_context/>
    </exec_method>
<!-- 以kill方式将服务进程干掉,这是有subversion的管理方式决定的,干掉svnserve进程-->
    <exec_method name='stop' type='method' exec=':kill' timeout_seconds='60'>
      <method_context/>
    </exec_method>
    <stability value='Unstable'/>
    <template>
      <common_name>
        <loctext xml:lang='C'>Subversion monitoring</loctext>
      </common_name>
    </template>
  </service>
</service_bundle>


然后写了个启动的shell脚本: subversion
#! /usr/bin/bash

# Start the subversion server
/opt/csw/bin/svnserve -d -r /export/home/svn/svn/repos/

用svccfg import subversion.xml导入到管理库里面,将subversion这个脚本添加执行权限,并拷贝成/lib/svc/method/svc-subversion

然后svcs |grep subversion看看运行状态,如果是online就OK了

可以通过 svcadm disable subversion
svcadmin enable subversion
svcadmin restart subversion
来管理这个服务

更多的看man svccfg 和 svcadm

通过 svcs -xv subversion可以诊断故障

有问题看看/var/svc/log/network-subversion的日志

2008年10月13日星期一

在Windows环境下编译SendIP的问题总结

以下是SendIP的介绍,我主要是想用这个东西来发伪造的数据包,可惜在俺的D版的Windows XP SP2上还是不通。
SendIP is a tool to send completely arbitrary packets out over the network.
In conjunction with PackPrint (see
http://www.earth.li/projectpurple/progs/packprint.html), this makes an
extremely powerful debugging tool for networks.

SendIP目前支持如下协议:
Here is a list of protocols that SendIP currently understands:
* IPv4 (but see below section 7)
* TCP
* BGP
* ICMP
* UDP
* RIP
* NTP
* IPv6 (except on solaris)
* ICMPv6
* TCP
* UDP
* RIPng
* NTP?

Other protocols will be added in future versions, as and when I have time
to add them.

Of course, it is still possible to send packets using other protocols, but
you have to construct the packet data and headers entirely by hand.


因为这东西只提供了Linux和Solaris下的版本,我猜可能国外的人私人都用不起Windows……
我就在Cygwin下想将其编译看看。
结果遇到如下问题:
  1. 在编译的时候,遇到了gethostbyname2这个函数未定义……
  2. gcc的-fPic等选项不支持
第一个问题么,我知道gethostbyname是在netdb.h这个头文件中声明的,gethostbyname2不清楚。google 关键字cygwin+gethostbyname2发现,gethostbyname2也是在netdb上声明,但是从http://win6.jp/Cygwin/index.html这上面知道,现在最新版本的cygwin并没有支持IPV6,需要从这个网址上下载补丁。
下载后按照里面的README很快的就解决了第一个问题

第二个问题也简单,直接将Makefile里面相关的编译选项去掉就可以了




最后编译好了,就开始运行了……

$ ./sendip -p ipv4 -p tcp -d r99 x.x.x.x
sendto: Interrupted system call

faint!!!!
$ ls
CHANGES contrib gnugetopt1.o ipv6.so sendip.1 tcp.so
LICENSE csum.c help2man ntp.c sendip.c types.h
Makefile csum.o icmp.c ntp.h sendip.exe udp.c
README cygwin1.dll icmp.h ntp.so sendip.o udp.h
TODO dummy.c icmp.so rip.c sendip.spec udp.so
VERSION dummy.h ipv4.c rip.h sendip.spec.in
bgp.c gnugetopt.c ipv4.h rip.so sendip2.exe
bgp.so gnugetopt.h ipv4.so ripng.c sendip_module.h
compact.c gnugetopt.o ipv6.c ripng.h tcp.c
compact.o gnugetopt1.c ipv6.h ripng.so tcp.h


$ fgrep "Interrupted system call" *
Binary file cygwin1.dll matches

看来这个错误是在Cygwin下封装了。

最后想起了,MS在winXP SP2版本后就对发送raw packet进行了限制
C:\Documents and Settings\Administrator>net helpmsg 10004

一个封锁操作被对 WSACancelBlockingCall 的调用中断。
发送伪造的数据包将被WSACancelBlockingCall中断。


解决方法应该是用驱动直接发包。。。。。。


可以参考winpcap + libnet +自己的code来实现吧

郁闷,还以为有现成的工具呢,自己写的话,就是组装包比较麻烦。

可以参考参考tcpReplay-Win32或者JPcap,封装的都还挺好。

2008年10月8日星期三

什么是 Pythonic

的确,什么是 Pythonic 呢?经常看到大家说这个是 Pythonic 而那个又不是,但如何定义,如何区分呢?这篇Blog给出了作者的一个解释。看这里

其中有几句话是这样说的:

To be Pythonic is to use the Python constructs and datastructures with clean, readable idioms. It is Pythonic is to exploit dynamic typing for instance, and it's definitely not Pythonic to introduce static-type style verbosity into the picture where not needed. To be Pythonic is to avoid surprising experienced Python programmers with unfamiliar ways to accomplish a task.\

基 本意思就是说如果想 Pythonic 就应该使用 Python 的构造和数据结构,并且要干净、符合可读性的习惯。例如使用动态类型是 Pythonic 的,而使用静态类型明显不是 Pythonic 的。想 Pythonic 就应该避免为了完成一件工作使用让有经验的 Python 程序员吃惊的不熟悉的方式。

就我个人对 Pythonic 的理解来说,简单、清晰,不要过分强调技巧,尽量使用 Python 已经提供的功能以及符合Python的思维方式。

其中最后还有一句话:

A less powerful framework that is easy to pick up for a Python programmer may be considered more Pythonic than a far more powerful system that takes more of a time investment to learn.

也就是说:一个功能不是很强但容易上手的框架比起功能强大但要花大量时间学习的框架来说更 Pythonic 。因为Python的哲学就是简单,美!

如果想了解 Python 的哲学或 Python 之禅(The Zen of Python),可以执行:

import this

它的内容真需要仔细研究:

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!

-- by Tim Peters

上面的中文翻译已经在 啄木鸟社区有一个翻译了,不过说实在的真没仔细读过,现在读一读真是很有体会,不过我还是在各别用词上进行了修改,让我自已感觉更好吧。

优美胜过丑陋
明确胜过含蓄
简单胜过复杂
复杂胜过难懂
扁平胜过嵌套
稀疏胜过密集
易读亦有价
尽管实用会击败纯洁
特例也不能特殊到打破规则
除非明确地使其沉默
错误永远不应默默地溜掉
面对着不确定,要拒绝猜测的诱惑
应该有一个--宁肯只有一个--明显的实现方法
也许这个方法开始不是很明显,除非你是荷兰人
尽管不做通常好过立刻做
但现在做也要胜过不去做
如果实现很难解释,那它就是一个坏想法
如果实现容易解释,那它可能就是一个好想法
名字空间是一个响亮的出色想法--就让我们多用用它们

-- Tim Peters



Trackback: http://tb.donews.net/TrackBack.aspx?PostId=498175

The Zen of Python

>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!


蠎 禅

美丽好过丑陋;
明显好过隐晦;
简单好过复合;
复合好过复杂;
扁平好过嵌套;
稀疏好过密集;
可读性最重要;
即便实用性比纯度重要,
但是!特殊案例不可特殊到打破规则;
错误从来不会默默消失,
直到明确的让它闭嘴!
面对模糊,拒绝猜测的诱惑;
应该有一个(宁愿只有一个)显而易见的解决方法;
尽管刚开始方法不会是很明显,除非你是(Dutch)
即使永远不做比"立刻"做要"聪明",
但是!现在就做永远比不做要好;
只要实现很难解释,那么它就不是一个好主意;
只要实现很容易解释,那么这就是一个好主意;
名称空间是一个正在召唤的绝妙想法
--大家一起来实践这些规则吧!

-- by Tim Peters

-- ZoomQuiet 整理


优美胜过丑陋
明确胜过含蓄
简单胜过复杂
复杂胜过难懂
扁平胜过嵌套
稀疏胜过密集
易读亦有价
尽管实用会击败纯洁
特例也不能特殊到打破规则
除非明确地使其沉默
错误永远不应默默地溜掉
面对着不确定,要拒绝猜测的诱惑
应该有一个--宁肯只有一个--明显的实现方法
也许这个方法开始不是很明显,除非你是荷兰人
尽管不做通常好过立刻做
但现在做也要胜过不去做
如果实现很难解释,那它就是一个坏想法
如果实现容易解释,那它可能就是一个好想法
名字空间是一个响亮的出色想法--就让我们多用用它们

-- Tim Peters
-- 译:limodou

Python之道

美比丑好
直言不讳比心照不宣好
简单比困难好
困难总还比复杂好

平面的比嵌套的好
错落有致比密密匝匝的好
可读性很重要

虽然实用比纯粹更重要
但特殊情况不能特殊到打破规律
永远别让错误悄悄地溜走
除非是你故意的
碰到模棱两可的地方,绝对不要去作猜测
什么事情都应该有一个,而且最好只有一个显而易见的解决办法
虽然刚开始的时候,这个办法可能不是那么的显而易见,但谁叫你不是荷兰人
有些事情不理不睬可能会比过一会解决要好
但最好是现在就解决

如果一个想法实现起来很困难,那它本身就不是一个好想法
如果一个想法实现起来很容易,那它或许就是一个好想法
名字空间是个了不起的想法,所以我们现在就开始吧

注释::

  1. Zen of Python
    • Zen是禅的意思,是一个在老外那里很时髦的中国词。不过我们只说 XX之道,从来没有 XX之禅的说法
  2. Complex is better than complicated
    • 这里能体现英语的表达力。complex和complicated在中文里都是复杂的意思,但是两者有区别。complex是指内部关系的复杂,而complicated是指牵涉到很多外部的事务。 这里,我也不知道应该怎么翻译,姑且找了一个。希望能有网友帮忙,找一个更好的
  3. Now is better than never.
    • Although never is often better than *right* now.
    • 字面意思不难理解,但翻译过来不成句子。我这里做了补充,但是不知道贴切不贴切。
  4. 其他地方,或许有些朋友会认为有些问题,不过我自认为理解准确无误。
shhgs 回复: python-chinese@lists.python.cn 收件人: python-chinese@lists.python.cn 日期: 2006-1-2 上午2:34 主题: [python-chinese] The Zen of Python, Python之道
  • Now is better than never.

Although never is often better than *right* now.

  • 我觉得是这意思吧:做总比不做好,但如果匆忙上阵的话那还不如不做。