??xml version="1.0" encoding="utf-8" standalone="yes"?> The squares in the middle look suspicious so you think that the answer is encoded within it.
Unfortunately, Python does not have a built-in Image library so
you'll have to search for an external module. I've chosen to use PIL (http://www.pythonware.com/products/pil/), which I had pre-installed.
There seem to be a lot of data here, but it is noticable that the grey squares have R=G=B, and it has a period of 7 pixels.
Applying the hint:
打开一EmailQ查看其原始信息Q您可以通过收取、导邮g用文本编辑器查看Q。你会看到类DL一个效果:
Date: Thu, 25 Dec 2003 06:33:07 +0800
From: "eSX?!" <snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net>
Reply-To: snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net
To: "snaix" <snaix@126.com'>snaix@126.com>
Subject:
X-mailer: Foxmail 5.0 beta2 [cn]
Mime-Version: 1.0
Content-Type: text/plain;
charset="gb2312"
Content-Transfer-Encoding: base64
xOO6w6OsU25haVgNCg0KoaGhodXiysfSu7j2QmFzZTY0tcSy4srU08q8/qOhDQoNCkJlc3QgV2lz
aGVzIQ0KIAkJCQkNCqGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaEgICAgICAgICAgICAgICBl
U1g/IQ0KoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoSAgICAgICAgICAgICAgIHNuYWl4QHll
YWgubmV0DQqhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhICAgICAgICAgMjAwMy0x
Mi0yNQ0K
是否看到?#8220;base64”标记Q是否看C标记下面的一行ؕ码?也许你会恍然大悟Q对Q这是Base64~码?
什么是Base64Q?/strong>
?
照RFC2045的定义,Base64被定义ؓQBase64内容传送编码被设计用来把Q意序列的8位字节描qCؓ一U不易被人直接识别的形式。(The
Base64 Content-Transfer-Encoding is designed to represent arbitrary
sequences of octets in a form that need not be humanly readable.Q?
Z么要使用Base64Q?/strong>
在设计这个编码的时候,我想设计人员最主要考虑?个问题:
1.是否加密Q?
2.加密法复杂E度和效?
3.如何处理传输Q?
加密是肯定的Q但是加密的目的不是让用户发送非常安全的Email。这U加密方式主要就?#8220;防君子不防小?#8221;。即辑ֈ一眼望d全看不出内容卛_?
?
于这个目的加密算法的复杂E度和效率也׃能太大和太低。和上一个理q|MIME协议{用于发送Email的协议解决的是如何收发EmailQ而ƈ?
是如何安全的收发Email。因此算法的复杂E度要小Q效率要高,否则因ؓ发送Email而大量占用资源,路就有点走歪了?
但是Q如果是Z以上两点Q那么我们用最单的恺撒法即可,Z么Base64看v来要比恺撒法复杂呢?q是因ؓ在Email的传送过E中Q由于历史原
因,Email只被允许传送ASCII字符Q即一?位字节的?位。因此,如果您发送了一带有非ASCII字符Q即字节的最高位?Q的Email?
q有“历史问题”的网x可能会出现问题。网兛_能会把最高位|ؓ0Q很明显Q问题就q样产生了!因此Qؓ了能够正常的传送EmailQ这个问题就必须
考虑Q所以,单单靠改变字母的位置的恺撒之cȝҎ也就不行了。关于这一点可以参考RFC2046?
Z以上的一些主要原因生了Base64~码?
法详解
Base64~码要求??位字节(3*8=24Q{化ؓ4?位的字节Q?*6=24Q,之后?位的前面补两?QŞ?位一个字节的形式?
具体转化形式间下图:
字符?#8220;?”
11010101 11000101 00110011
00110101 00011100 00010100 00110011
?
可以q么考虑Q把8位的字节q成一?10101011100010100110011
然后每次序?个出来之后再把这6二进制数前面再添加两?Q就成了一个新的字节。之后再选出6个来Q再d0Q依此类推,直到24个二q制数全部被选完?
让我们来看看实际l果Q?
字符?#8220;?”
11010101 HEX:D5 11000101 HEX:C5 00110011 HEX:33
00110101 00011100 00010100 00110011
字符’5’ 字符’^"’ 字符’^T’ 字符’3’
十进?3 十进?4 十进?0 十进?1
?
q样“? ”q个字符串就被Base64表示?#8221;5^"^T3”了么Q。错Q?
Base64~码方式q不是单U利用{化完的内容进行编码。像’^"’字符是控制字W,q不能通过计算机显C出来,在某些场合就不能使用了。Base64有其自n的编码表Q?
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v (pad) =
14 O 31 f 48 w
15 P 32 g 49 x
16 Q 33 h 50 y
?
q?
也是Base64名称的由来,而Base64~码的结果不是根据算法把~码变ؓ高两位是0而低6Z表数据,而是变ؓ了上表的形式Q如”A”有7位,
?#8221;a”只?位。表中,~码的编号对应的是得出的新字节的十进制倹{因此,从表2可以得到对应的Base64~码Q?
字符?#8220;?”
11010101 HEX:D5 11000101 HEX:C5 00110011 HEX:33
00110101 00011100 00010100 00110011
字符’5’ 字符’^"’ 字符’^T’ 字符’3’
十进?3 十进?4 十进?0 十进?1
字符’1’ 字符’i’ 字符’U’ 字符’z’
?
q样Q字W串“?”l过~码后就成了字符?#8220;1iUz”了?
Base64?个字节{变ؓ4个字节,因此Q编码后的代码量Q以字节为单位,下同Q约比编码前的代码量多了1/3。之所以说?#8220;U?#8221;Q是因ؓ如果代码量正好是3的整数倍,那么自然是多?/3。但如果不是呢?
l心的h可能已经注意CQ在The Base64 Alphabet中的最后一个有一?pad) =字符。这个字W的目的是用来处理q个问题的?
当代码量不是3的整数倍时Q代码量/3的余数自然就?或?。{换的时候,l果不够6位的?来补上相应的位置Q之后再?位的前面补两?。{换完I出的结果就用就?#8220;=”来补位。譬如结果若最后余下的?个字节的“?#8221;Q?
字符?#8220;?#8221;
11010101 HEX:D5 11000101 HEX:C5
00110101 00011100 00010100
十进?3 十进?4 十进?0 pad
字符’1’ 字符’i’ 字符’U’ 字符’=’
?
q样Q最后的2个字节被整理成了“1iU=”?
同理Q若原代码只剩下一个字节,那么会d两个“=”。只有这两种情况Q所以,Base64的编码最多会在编码结有两个“=”
至于Base64的解码,只是一个简单的~码的逆过E,读者可以自己探讨。我在文章的最后给码算法?
法实现
其实在算法详解的时候基本上已经说的很清楚了。用于程序上Q除ȝ束判断,大概可以分ؓ如下几步几步Q?
d数据3字节用AND取前6位,攑օ新的变量中右移两位Q高两位?AND取第一个字节的?位和W二个字节的?位移位放入新变量中右移两位Q清0……依此cL?
解码的类C语言实现的算法:
BYTE LMoveBit(int base, int MoveNum)
{
BYTE result=base;
if(MoveNum==0)return 1;
if(MoveNum==1)return MoveNum;
result=base<<(MoveNum-1);
return result;
}
char base64_alphabet[]=
{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/','='};
BYTE Base64Decode(char *base64code, DWORD base64length)
{
char buf[4];
int i,j;
int k;
int l=0;
BYTE temp1[4],temp2;
BYTE *Buffer=new BYTE[base64length*3/4];
DWORD base64a=(base64length/4)-1;
DWORD base64b=0;
for(;base64b<base64a+1;base64b++)
{
for(i=0;i<4;i++)
{
buf[i]=*(base64code+(base64b*4)+i);
for(j=0;j<65;j++)
{
if(buf[i]==base64_alphabet[j])
{
temp1[i]=j;
break;
}
}
}
i--;
for(k=1;k<4;k++)
{
if(temp1[i-(k-1)]==64){m_padnum++; continue;}
temp1[i-(k-1)]=temp1[i-(k-1)]/LMoveBit(2,(k-1)*2);
temp2=temp1[i-k];
temp2=temp2&(LMoveBit(2,k*2)-1);
temp2*=LMoveBit(2,8-(2*k));//move 4
temp1[i-(k-1)]=temp1[i-(k-1)]+temp2;
Buffer[base64b*3+(3-k)]=temp1[i-(k-1)];
}
}
return Buffer;
}
Ҏq段法Q文章最开始给出的Email内容Q可以解码ؓQ?
你好QSnaiX
q是一个Base64的测试邮Ӟ
Best Wishes!
eSX?!
snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net'>snaix@yeah.net
2003-12-25
如文章有问题恌指出q与我联p:snaix@126.com'>snaix@126.com
主要参考资料:
RFC2045
RFC2046
《奇妙的Base64~码》,|聪
以及一些来自互联网上的其他资料
]]>
>>> import Image, urllib, StringIO
>>> img = urllib.urlopen('http://www.pythonchallenge.com/pc/def/oxygen.png').read()
>>> i = Image.open(StringIO.StringIO(img)) # Image.open requires a file-like object
>>> i.size
(629, 95)
>>> [i.getpixel((x,45)) for x in range(629)]
[(115, 115, 115, 255), (115, 115, 115, 255), (115, 115, 115, 255), ...
# Extract every 7th pixel from row 45.
>>> row = [i.getpixel((x, 45)) for x in range(0, i.size[0], 7)]
# Take the R value from all with equal R, G, and B values.
>>> ords = [r for r, g, b, a in row if r == g == b]
# And convert to characters.
>>> print "".join(map(chr, ords))
smart guy, you made it. the next level is [105, 110, 116, 101, 103, 114, 105, 116, 121]
>>> "".join(map(chr,[105, 110, 116, 101, 103, 114, 105, 116, 121]))
'integrity'
-------------------------------------------------------------------------------------------------------------------------------
Level 8: http://www.pythonchallenge.com/pc/def/integrity.html
]]>
I believe the technical difference is that a function is not in a class, whereas a method is.
You'll see method and member function used interchangeably which is
fine (a function that is a member of a class, get it? Correct term when
discussing C++). Function and method shouldn't be used interchangeably,
but often will be.
I'd suggest you don't sweat it, they both represent blocks of code that do something and might return a value.
]]>
上——http://www.linuxdby.com/html/linux/program/20070412/1753.html
下——http://www.linuxdby.com/html/linux/program/20070412/1754.html)
什么是持久性?
持久性的基本思想很简单。假定有一?Python E序Q它可能是一个管理日常待办事的E序Q您希望在多ơ执行这个程序之间可以保存应用程序对象(待办事项Q。换句话_您希望把对象存储在磁盘上Q便? 以后索。这是持久性。要辑ֈq个目的Q有几种ҎQ每一U方法都有其优缺炏V?
例如Q可以把对象数据存储在某U格式的文本文g中,譬如 CSV 文g。或者可以用关系数据库,譬如 Gadfly、MySQL、PostgreSQL 或?DB2。这些文件格式和数据库都非常优秀Q对于所有这些存储机ӞPython 都有健壮的接口?
q些存储机制都有一个共同点Q存储的数据是独立于对这些数据进行操作的对象和程序? q样做的好处是,数据可以作ؓ׃n的资源,供其它应用程序用。缺ҎQ用q种方式Q可以允许其它程序访问对象的数据Q这q背了面向对象的装性原? ?卛_象的数据只能通过q个对象自n的公共(publicQ接口来讉K?
另外Q对于某些应用程序,关系数据库方法可能不是很理想。尤其是Q关pL据库不理 解对象。相反,关系数据库会使用自己的类型系l和关系数据模型Q表Q,每张表包含一l元l(行)Q每行包含具有固定数目的静态类型字D(列)。如果应 用程序的对象模型不能够方便地转换到关pL型,那么在把对象映射到元l以及把元组映射回对象方面,会碰C定难度。这U困隑ָ被称为阻性不匚w Qimpedence-mismatchQ问题?
对象持久?/strong>
如果希望透明地存?Python 对象Q而不丢失其n份和cd{信息,则需要某UŞ式的对象序列化:它是一个把L复杂的对象{成对象的文本或二q制表示的过E。同P必须能够把对象经q? 序列化后的Ş式恢复到原有的对象。在 Python 中,q种序列化过E称?pickleQ可以把对象 pickle 成字W串、磁盘上的文件或者Q何类g文g的对象,也可以把q些字符丌Ӏ文件或McM于文件的对象 unpickle 成原来的对象。我们把在本文后面详l讨?pickle?
假定您喜Ƣ把M事物都保存成对象Q而且希望避免把对象{换成某种Z非对象存? 的开销Q那?pickle 文g可以提供q些好处Q但有时可能需要比q种单的 pickle 文g更健壮以及更h可~性的事物。例如,只用 pickle 不能解决命名和查?pickle 文gq样的问题,另外Q它也不能支持ƈ发地讉K持久性对象。如果需要这些方面的功能Q则要求助类g ZODBQ针?Python ?Z 对象数据库)q类数据库。ZODB 是一个健壮的、多用户的和面向对象的数据库pȝQ它能够存储和管理Q意复杂的 Python 对象Qƈ支持事务操作和ƈ发控制。(请参阅参考资料,以下?ZODB。)令h_感兴的是,甚至 ZODB 也依?Python 的本机序列化能力Q而且要有效地使用 ZODBQ必d分了?pickle?
另一Uo人感兴趣的解x久性问题的Ҏ?PrevaylerQ它最初是? Java 实现的(有关 Prevaylor 斚w?developerWorks 文章Q请参阅参考资料)。最q,一?Python E序员把 Prevayler ULC Python 上,另v名ؓ PyPerSystQ由 SourceForge 托管Q有兌 PyPerSyst 目的链接,请参阅参考资料)。Prevayler/PyPerSyst 概念也是建立?Java ?Python 语言的本机序列化能力之上。PyPerSyst 把整个对象系l保存在内存中,q过不时地把pȝ快照 pickle 到磁盘以及维护一个命令日志(通过此日志可以重新应用最新的快照Q来提供N恢复。所以,管使用 PyPerSyst 的应用程序受到可用内存的限制Q但好处是本机对象系l可以完全装入到内存中,因而速度极快Q而且实现h要比?ZODB q样的数据库单,ZODB 允许对象的数目比同时在能内存中所保持的对象要多?
既然我们已经要讨Z存储持久对象的各U方法,那么现在该详l探? pickle q程了。虽然我们主要感兴趣的是探烦以各U方式来保存 Python 对象Q而不必把其{换成某种其它格式Q但我们仍然q有一些需要关注的地方Q譬如:怎么h效地 pickle ?unpickle 单对象以及复杂对象,包括定制cȝ实例Q怎么L护对象的引用Q包括@环引用和递归引用Q以及怎么样处理类定义发生的变化,从而用以前经q? pickle 的实例时不会发生问题。我们把在随后关?Python ?pickle 能力探讨中涉及所有这些问题?br />一些经q?pickle ?Python
pickle 模块及其同类模块 cPickle ?Python 提供? pickle 支持。后者是?C ~码的,它具有更好的性能Q对于大多数应用E序Q推荐用该模块。我们把l箋讨论 pickleQ但本文的示例实际是利用?cPickle。由于其中大多数CZ要用 Python shell 来显C,所以先展示一下怎么样导? cPickleQƈ可以作ؓ pickle 来引用它Q?
|
现在已经导入了该模块Q接下来让我们看一?pickle 接口。pickle 模块提供了以下函数对Qdumps(object) q回一个字W串Q它包含一?pickle 格式的对象;loads(string) q回包含? pickle 字符串中的对象;dump(object, file) 把对象写到文Ӟq个文g可以是实际的物理文gQ但也可以是McM于文件的对象Q这个对象具?write() ҎQ可以接受单个的字符串参敎ͼload(file) q回包含?pickle 文g中的对象?
~省情况下,dumps() ?dump() 使用可打印的 ASCII 表示来创?pickle。两者都有一?final 参数Q可选)Q如果ؓ TrueQ则该参数指定用更快以及更小的二q制表示来创? pickle。loads() ?load() 函数自动?pickle 是二q制格式q是文本格式?
清单 1 昄了一个交互式会话Q这里用了刚才所描述?dumps() ?loads() 函数Q?
|
注:该文?pickle 格式很简单,q里׃解释了。事实上Q在 pickle 模块中记录了所有用的U定。我们还应该指出Q在我们的示例中使用的都是简单对象,因此使用二进?pickle 格式不会在节省空间上昄出太大的效率。然而,在实际用复杂对象的pȝ中,您会看到Q用二q制格式可以在大和速度斚w带来显著的改q?
接下来,我们看一些示例,q些CZ用到?dump() ? load()Q它们用文件和cM文g的对象。这些函数的操作非常cM于我们刚才所看到?dumps() ? loads()Q区别在于它们还有另一U能??dump() 函数能一个接着一个地把几个对象{储到同一个文件。随后调?load() 来以同样的顺序检索这些对象。清?2 昄了这U能力的实际应用Q?
|
Pickle 的威?/strong>
到目前ؓ止,我们讲述了关?pickle 斚w的基本知识。在q一节,把讨Z些高U问题,当您开?pickle 复杂对象Ӟ会遇到这些问题,其中包括定制cȝ实例。幸q的是,Python 可以很容易地处理q种情Ş?
可移植?/strong>
从空间和旉上说QPickle 是可UL的。换句话_pickle 文g格式独立于机器的体系l构Q这意味着Q例如,可以?Linux 下创Z?pickleQ然后把它发送到?Windows ?Mac OS 下运行的 Python E序。ƈ且,当升U到更新版本?Python Ӟ不必担心可能要废弃已有的 pickle。Python 开发h员已l保?pickle 格式把可以向后兼?Python 各个版本。事实上Q在 pickle 模块中提供了有关目前以及所支持的格式方面的详细信息Q?
|
多个引用Q同一对象
?Python 中,变量是对象的引用。同Ӟ也可以用多个变量引用同一个对象。经证明QPython 在用l过 pickle 的对象维护这U行为方面丝毫没有困难,如清?4 所C:
|
循环引用和递归引用
可以把刚才演C的对象引用支持扩展到循环引用Q两个对象各自包含对Ҏ的引用)和递归引用Q一个对象包含对其自w的引用Q。下面两个清单着重显CU能力。我们先看一下递归引用Q?
|
现在Q看一个@环引用的CZQ?
|
注意Q如果分?pickle 每个对象Q而不是在一个元l中一?pickle 所有对象,会得到略微不同(但很重要Q的l果Q如清单 7 所C:
|
相等Q但q不L相同
正如在上一个示例所暗示的,只有在这些对象引用内存中同一个对象时Q它们才是相同的。在 pickle 情Ş中,每个对象被恢复到一个与原来对象相等的对象,但不是同一个对象。换句话_每个 pickle 都是原来对象的一个副本:
|
同时Q我们看?Python 能够l护对象之间的引用,q些对象是作Z个单元进? pickle 的。然而,我们q看到分别调?dump() 会 Python 无法l护对在该单元外部进?pickle 的对象的引用。相反,Python 复制了被引用对象Qƈ把副本和?pickle 的对象存储在一赗对?pickle 和恢复单个对象层ơ结构的应用E序Q这是没有问题的。但要意识到q有其它情Ş?
值得指出的是Q有一个选项实允许分别 pickle 对象Qƈl护怺之间的引用,只要q些对象都是 pickle 到同一文g卛_。pickle ?cPickle 模块提供了一? PicklerQ与此相对应?UnpicklerQ,它能够跟t已l被 pickle 的对象。通过使用q个 PicklerQ把会通过引用而不是通过值来 pickle ׃n和@环引用:
|
不可 pickle 的对?/strong>
一些对象类型是不可 pickle 的。例如,Python 不能 pickle 文g对象Q或者Q何带有对文g对象引用的对象)Q因?Python ?unpickle 时不能保证它可以重徏该文件的状态(另一个示例比较难懂,在这cL章中不值得提出来)。试?pickle 文g对象会导致以下错误:
|
cd?/strong>
?pickle 单对象类型相比,pickle cd例要多加留意。这主要׃ Python ?pickle 实例数据Q通常?_dict_ 属性)和类的名Uͼ而不?pickle cȝ代码。当 Python unpickle cȝ实例Ӟ它会试图使用?pickle 该实例时的确切的cdU和模块名称Q包括Q何包的\径前~Q导入包含该cd义的模块。另外要注意Q类定义必须出现在模块的最层Q这意味着它们不能是嵌? 的类Q在其它cL函数中定义的c)?
?unpickle cȝ实例Ӟ通常不会再调用它们的 _init_() Ҏ。相反,Python 创徏一个通用cd例,q应用已q行q?pickle 的实例属性,同时讄该实例的 _class_ 属性,使其指向原来的类?
?Python 2.2 中引入的新型c进?unpickle 的机制与原来的略有不同。虽然处理的l果实际上与Ҏ型类处理的结果相同,?Python 使用 copy_reg 模块?_reconstructor() 函数来恢复新型类的实例?
如果希望Ҏ型或旧型cȝ实例修改~省?pickle 行ؓQ则可以定义Ҏ的类的方?_getstate_() ?_setstate_()Q在保存和恢复类实例的状态信息期_Python 会调用这些方法。在以下几节中,我们会看C些示例利用了q些Ҏ的方法?
现在Q我们看一个简单的cd例。首先,创徏一?persist.py ?Python 模块Q它包含以下新型cȝ定义Q?
|
现在可以 pickle Foo 实例Qƈ看一下它的表C:
|
可以看到q个cȝ名称 Foo 和全限定的模块名U? Orbtech.examples.persist 都存储在 pickle 中。如果把q个实例 pickle 成一个文ӞE后? unpickle 它或在另一台机器上 unpickleQ则 Python 会试囑֯?Orbtech.examples.persist 模块Q如果不能导入,则会抛出异常。如果重命名该类和该模块或者把该模块移到另一个目录,则也会发生类似的错误?
q里有一?Python 发出错误消息的示例,当我们重命名 Foo c,然后试图装入先前q行q?pickle ?Foo 实例时会发生该错误:
|
在重命名 persist.py 模块之后Q也会发生类似的错误Q?
|
Ҏ的状态方?/strong>
前面提到对一些对象类型(譬如Q文件对象)不能q行 pickle。处理这U不? pickle 的对象的实例属性时可以使用Ҏ的方法(_getstate_() ?_setstate_()Q来修改cd例的状态。这里有一? Foo cȝCZQ我们已l对它进行了修改以处理文件对象属性:
|
pickle Foo 的实例时QPython 把只 pickle 当它调用该实例的 _getstate_() Ҏ时返回给它的倹{类似的Q在 unpickle ӞPython 把提供经q?unpickle 的g为参C递给实例?_setstate_() Ҏ。在 _setstate_() Ҏ内,可以Ҏl过 pickle 的名U和位置信息来重建文件对象,q把该文件对象分配给q个实例?logfile 属性?
模式改进
随着旉的推U,您会发现自己必须要更改类的定义。如果已l对某个cd例进行了 pickleQ而现在又需要更改这个类Q则您可能要索和更新那些实例Q以便它们能在新的类定义下l正常工作。而我们已l看到在对类或模块进行某些更? Ӟ会出C些错误。幸q的是,pickle ?unpickle q程提供了一?hookQ我们可以用它们来支持这U模式改q的需要?
在这一节,我们把探讨一些方法来预测常见问题以及怎么栯册些问题。由于不? pickle cd例代码,因此可以d、更改和除去ҎQ而不会媄响现有的l过 pickle 的实例。出于同L原因Q可以不必担心类的属性。您必须保包含cd义的代码模块?unpickle 环境中可用。同时还必须些可能导? unpickle 问题的更改做好规划,q些更改包括Q更改类名、添加或除去实例的属性以及改变类定义模块的名U或位置?cd的更?/strong>
要更改类名,而不破坏先前l过 pickle 的实例,请遵循以下步骤。首先,保原来的类的定义没有被更改Q以便在 unpickle 现有实例时可以找到它。不要更改原来的名称Q而是在与原来cd义所在的同一个模块中Q创cd义的一个副本,同时l它一个新的类名。然后用实际的新类 名来替代 NewClassNameQ把以下Ҏd到原来类的定义中Q?
|
?unpickle 现有实例ӞPython 把查扑֎来类的定义,q调用实例的 _setstate_() ҎQ同时把l新的类定义重新分配该实例的 _class_ 属性。一旦确定所有现有的实例都已l? unpickle、更新和重新 pickle 后,可以从源代码模块中除L的类定义?
属性的d和删?/strong>
q些Ҏ的状态方?_getstate_() ?_setstate_() 再一ơ我们能控制每个实例的状态,q我们有机会处理实例属性中的更攏V让我们看一个简单的cȝ定义Q我们把向其d和除M些属性。这是是最初的定义Q?
|
假定已经创徏q?pickle ?Person 的实例,现在我们军_真的只想存储一个名U属性,而不是分别存储姓和名。这里有一U方式可以更改类的定义,它把先前l过 pickle 的实例迁Ud新的定义Q?
|
在这个示例,我们d了一个新的属?fullnameQƈ除去了两个现有的属? firstname ?lastname。当对先前进行过 pickle 的实例执?unpickle Ӟ其先前进行过 pickle 的状态会作ؓ字典传递给 _setstate_()Q它把包?firstname ?lastname 属性的倹{接下来Q把q两个值组合v来,q把它们分配l新属?fullname。在q个q程中,我们删除了状态字怸旧的属性。更新和重新 pickle 先前q行q?pickle 的所有实例之后,现在可以从类定义中除?_setstate_() Ҏ?
模块的修?/strong>
在概念上Q模块的名称或位|的改变cM于类名称的改变,但处理方式却完全不同。那? 因ؓ模块的信息存储在 pickle 中,而不是通过标准?pickle 接口可以修改的属性。事实上Q改变模块信息的唯一办法是对实际? pickle 文g本n执行查找和替换操作。至于怎么L切地dQ这取决于具体的操作pȝ和可使用的工兗很昄Q在q种情况下,您会惛_份您的文Ӟ以免发生错误? 但这U改动应该非常简单,q且对二q制 pickle 格式q行更改与对文本 pickle 格式q行更改应该一h效?
l束?/strong>
对象持久性依赖于底层~程语言的对象序列化能力。对?Python 对象x味着 pickle。Python ?pickle ?Python 对象有效的持久性管理提供了健壮的和可靠的基。在下面的参考资料中Q您把会扑ֈ有关建立?Python pickle 能力之上的系l的信息?
q篇文改编?/span>Guido最初的?/span>Python风格指南》一文,q从?/span>Barry's style guide》中d了部分内宏V在有冲H的地方Q?/span>Guide的风D则应该是W合?/span>PEP的意?/span>(译注Q指当有冲突Ӟ应以Guido风格为准)。这?/span>PEP仍然未完成(实际上,它可能永q都不会完成)?/span>
在这风格指g的一致性是重要的。在一个项目内的一致性更重要。在一个模块或函数内的一致性最重要。但最重要的是Q知道何时会不一致——有时只是没有实施风格指对{当出现疑惑Ӟq用你的最佛_断,看看别的例子Q然后决定怎样看v来更好。ƈ且要不M问!
打破一条既定规则的两个好理由:
(1) 当应用这个规则是导致代码可L下降,即便Ҏ人来_他已l习惯于按这条规则来阅读代码了?/span>
(2) Z和周围的代码保持一致而打破规?/span>(也许是历史原?/span>)Q虽然这也是个清除其它q好机?/span>(真正?/span>XP风格)?/span>
代码的布局
~进
使用Emacs?/span>Python-mode的默认|4个空g个羃q层ơ。对于确实古老的代码Q你不希望生乱,可以l箋使用8I格的制表符(8-space tabs)?/span>Emacs Python-mode自动发现文g中主要的~进层次Q依此设定羃q参数?/span>
制表W还是空?/span>
永远不要L制表W和I格。最行?/span>Python~进方式是仅使用I格Q其ơ是仅用制表符Q合着制表W和I格~进的代码将被{换成仅用空根{?/span>(?/span>Emacs中,选中整个~冲区,?/span>ESC-x去除制表W?/span>)调用Python命o行解释器时?/span>-t选项Q可对代码中不合法得混合制表W和I格发出警告Q?/span>-tt时警告将变成错误。这些选项是被高度推荐的?/span>
对于新的目Q强烈推荐仅使用I格而不是制表符。许多编辑器拥有使之易于实现的功?/span>(?/span>Emacs中,认indent-tabs-mode?/span>nil)?/span>
行的最大长?/span>
周围仍然有许多设备被限制在每?/span>80字符Q而且Q窗口限制在80个字W。ɞ多个窗口ƈ排放|成为可能。在q些讑֤上用默认的折叠方式看v来有点丑陋。因此,请将所有行限制在最?/span>79字符(Emacs准确得将行限制ؓ?/span>80字符)Q对序排放的大块文?/span>(文字符串或注释)Q推荐将长度限制?/span>72字符?/span>
折叠长行的首选方法是使用Pyhon支持的圆括号Q方括号和花括号内的行gl。如果需要,你可以在表达式周围增加一寚w外的圆括P但是有时使用反斜杠看h更好Q确认恰当得~进了gl的行?/span>
Emacs?/span>Python-mode正确得完成了q些。一些例子:
#!Python
class Rectangle(Blob)Q?/span>
def __init__(selfQ?/span>widthQ?/span>heightQ?/span>color='black'Q?/span>emphasis=NoneQ?/span>highlight=0)Q?/span>
if width == 0 and height == 0 and \
color == 'red' and emphasis == 'strong' or \
highlight > 100Q?/span>
raise ValueErrorQ?/span> "sorryQ?/span> you lose"
if width == 0 and height == 0 and (color == 'red' or
emphasis is None)Q?/span>
raise ValueErrorQ?/span>"I don't think so"
Blob.__init__(selfQ?/span>widthQ?/span>heightQ?/span>colorQ?/span>emphasisQ?/span>highlight)
I
用两行空行分割顶层函数和cȝ定义Q类内方法的定义用单个空行分Ԍ额外的空行可被用?/span>(保守?/span>)分割相关函数l成的群Q在一l相关的单句中间可以省略I?/span>(例如Q一l哑元素)?/span>
当空行用于分割方法的定义Ӟ?#8216;class’行和W一个方法定义之间也要有一个空行。在函数中用空行时Q请谨慎的用于表CZ个逻辑D落?/span>Python接受contol-L(?/span>^L)换页W作为空|Emacs(和一些打印工?/span>)Q视q个字符为页面分割符Q因此在你的文g中,可以用他们来为相关片D分c?/span>
~码
Python核心发布中的代码必须始终使用ASCII?/span>Latin-1~码(又名 ISO-8859-1)Q?/span>ASCII的文件不必有~码cookieQ?/span>Latin-1仅当注释或文档字W串涉及作者名字需?/span>Latin-1时才被用:
另外使用\x转义字符是在字符串中包含?/span>ASCII(non-ASCII)数据的首选方法?/span>
作ؓPEP 263实现代码的测试套件的部分文g是个例外?/span>
导入
通常应该在单独的行中导入(Imports)Q例如:
NoQ?/span>import sysQ?/span> os
YesQ?/span>import sys
import os
但是q样也是可以的:
from types import StringTypeQ?/span> ListType
Imports 通常被放|在文g的顶部,仅在模块注释和文字W串之后Q在模块的全局变量和常量之前?/span>Imports应该有顺序地成组安放Q?/span>
1、标准库的导?/span>(Imports )
2、相关的d(major package)的导?/span>(卻I所有的email包在随后导入)
3、特定应用的导入(imports)
你应该在每组导入之间攄一个空行,对于内部包的导入是不推荐使用相对导入的,Ҏ有导入都要用包的绝对\径?/span>
从一个包含类的模块中导入cLQ通常可以写成q样Q?/span>
from MyClass import MyClass
from foo.bar.YourClass import YourClass
如果q样写导致了本地名字冲突Q那么就q样?/span>
import MyClass
import foo.bar.YourClass
即?/span>"MyClass.MyClass"?/span>"foo.bar.YourClass.YourClass"
表达式和语句中的I格
Guido不喜Ƣ在以下地方出现I格Q?/span>
紧挨着圆括PҎ号和花括LQ如Q?/span>"spam( ham[ 1 ]Q?/span>{ eggsQ?/span>2 } )"。要始终它写成"spam(ham[1]Q?/span>{eggsQ?/span> 2})"?/span>
紧脓在逗号Q分h冒号前的Q如Q?/span>
"if x == 4Q?/span>print xQ?/span>yQ?/span>xQ?/span>y = yQ?/span>x"。要始终它写成
"if x == 4Q?/span>print xQ?/span>yQ?/span>xQ?/span>y = yQ?/span>x"?/span>
紧脓着函数调用的参数列表前开式括?/span>(open parenthesis )的,?/span>"spam (1)"。要始终它写成"spam(1)"?/span>
紧脓在烦引或切片Q开始的开式括号前的,如:
"dict ['key'] = list [index]"。要始终它写成"dict['key'] = list[index]"?/span>
在赋?/span>(或其?/span>)q算W周围的用于和其它ƈ排的一个以上的I格Q如Q?/span>
#!Python
x= 1
y= 2
long_variable = 3
要始l将它写?/span>
#!Python
x = 1
y = 2
long_variable = 3
(不要对以上Q意一条和他争论—?/span>Guido Lq样的风Dq?/span>20q了?/span>)
其它
始终在这些二元运符两边攄一个空|赋?/span>(=)Q?/span> 比较(==Q?/span><Q?/span>>Q?/span>!=Q?/span><>Q?/span><=Q?/span> >=Q?/span>inQ?/span>not inQ?/span>isQ?/span>is not)Q布运?/span> (andQ?/span>orQ?/span>not)?/span>
按你的看法在术q算W周围插入空根{?/span> 始终保持二元q算W两边空格的一致?/span>
一些例子:
#!Python
i = i+1
submitted = submitted + 1
x = x*2 - 1
hypot2 = x*x + y*y
c = (a+b) * (a-b)
c = (a + b) * (a - b)
不要在用于指定关键字参数或默认参数值的'='号周围用空|例如Q?/span>
#!Python
def complex(realQ?/span> imag=0?/span>0)Q?/span>
return magic(r=realQ?/span> i=imag)
不要多条语句写在同一行上Q?/span>
NoQ?/span> if foo == 'blah'Q?/span>do_blah_thing()
YesQ?/span>if foo == 'blah'Q?/span>
do_blah_thing()
NoQ?/span>do_one()Q?/span>do_two()Q?/span>do_three()
YesQ?/span> do_one()
do_two()
do_three()
注释
同代码不一致的注释比没注释更差。当代码修改Ӟ始终优先更新注释!注释应该是完整的句子Q如果注释是一个短语或句子Q首字母应该大写Q除非他是一个以写字母开头的标识W?/span>(永远不要修改标识W的大小?/span>)?/span>
如果注释很短Q最好省略末句号。注释块通常׃个或多个由完整句子构成的D落l成Q每个句子应该以句号l尾。你应该在句末,句号后用两个空|以便?/span>Emacs的断行和填充工作协调一致?/span>
用英语书写时Q断词和I格是可用的。非p国家?/span>PythonE序员:Lp书写你的注释Q除非你120%的确信这些代码不会被不懂你的语言的h阅读?/span>
注释?/span>
注释块通常应用于跟随着一?/span>(或者全?/span>)代码q和q些代码有着相同的羃q层ơ。注释块中每行以‘#’和一个空格开?/span>(除非他是注释内的~进文本)。注释块内的D落以仅含单?#8216;#’的行分割。注释块上下Ҏ好有一I包围(或上方两行下方一行,对一个新函数定义D늚注释)?/span>
行内注释
一个行内注释是和语句在同一行的注释Q行内注释应该}慎适用Q行内注释应该至用两个I格和语句分开Q它们应该以'#'和单个空格开始?/span>
x = x+1 # Increment x
如果语意是很明了的,那么行内注释是不必要的,事实上是应该被移除的。不要这样写Q?/span>
x = x+1 # Increment x
x = x+1 # Compensate for border
但是有时Q这h有益的:
x = x+1 # Compensate for border
文档字符?/span>
应该一直遵守编写好的文档字W串的约?/span>PEP 257 [3]。ؓ所有公共模块,函数Q类和方法编写文字W串。文字W串寚w公开的方法不是必要的Q但你应该有一个描q这个方法做什么的注释。这个注释应该在"def"q行后?/span>
PEP 257 描述了好的文档字W串的约定。一定注意,多行文档字符串结"""应该单独成行Q例如:
"""Return a foobang
Optional plotz says to frobnicate the bizbaz first?/span>
"""
对单行的文字符Ԍl尾?/span>"""在同一行也可以?/span>
版本注记
如果你要?/span>RCS?/span>CVS的杂?/span>(crud)包含在你的源文g中,按如下做?/span>
#!Python
__version__ = "$RevisionQ?/span> 1?/span>4 $"
# $SourceQ?/span> EQ?/span>/cvsroot/Python_doc/pep8?/span>txtQ?/span>v $
q个行应该包含在模块的文字W串之后Q所有代码之前,上下用一个空行分剌Ӏ?/span>
命名U定
Python库的命名U定有点混ؕQ所以我们将永远不能使之变得完全一_不过q是有公认的命名规范的。新的模块和?/span>(包括W三方的框架)必须W合q些标准Q但对已有的库存在不同风格的Q保持内部的一致性是首选的?/span>
描述Q命名风?/span>
有许多不同的命名风格。以下的有助于L认正在用的命名风格Q独立于它们的作用?/span> 以下的命名风格是众所周知的:
b (单个写字母)
B (单个大写字母)
LowercaseQ小写)
lower_case_with_underscoresQ有下划U的写Q?/span>
UPPERCASEQ大写)
UPPER_CASE_WITH_UNDERSCORESQ有下划U的大写Q?/span>
CapitalizedWords (?/span> CapWordsQ?/span>CamelCaseq样命名是因为可从字母的大小写分出单词。这有时也被当作StudlyCaps?/span>
mixedCase (?/span>CapitalizedWords的不同在于首字母写!)
Capitalized_Words_With_UnderscoresQ有下划U的首字母大写) (丑陋!)
q有用短的特别前~相关的名字聚合在一L风格。这?/span>Python中不常用Q但是出于完整性要提一下,例如Q?/span>os.stat()函数q回一个元l,他的元素传统上说名如st_modeQ?/span> st_sizeQ?/span>st_mtime{等?/span>
X11库的所有公开函数?/span>X开头?/span>(?/span>Python中,q个风格通常认ؓ是不必要的,因ؓ属性和Ҏ名以对象作前~Q而函数名以模块名作前~?/span>)
另外Q以下用下划U作前导或结Ҏ形式是被公认?/span>(q些通常可以和Q何习惯组?/span>)Q?/span>
_single_leading_underscore(单个下划U作前导)Q弱?#8220;内部使用(internal use)”标志?/span> (例如Q?#8220;from M import *”不会导入以下划线开头的对象)?/span>
single_trailing_underscore_(单个下划U结?/span>)Q?/span> 用于避免?/span>Python关键词的冲突Q例如:“Tkinter.Toplevel(masterQ?/span>class_='ClassName')”?/span>
_double_leading_underscore(双下划线)Q从Python 1.4起ؓcȝ有名?/span>
_double_leading_and_trailing_underscore_Q?#8220;magic”对象或属性,存在于用h制的(user-controlled)名字I间Q例如:_init_Q?/span> _import_ ?/span>_file_。有时它们被用户定义用于触发某个法行ؓ(例如Q运符重蝲)Q有时被构造器插入Q以便自׃用或Z调试。因此,在未来的版本中,构造器(松散得定义ؓPython解释器和标准?/span>)可能打算建立自己的魔法属性列表,用户代码通常应该限制这U约定作为己用。欲成ؓ构造器的一部分的用户代码可以在下滑U中l合使用短前~Q例如:
_bobo_magic_attr__?/span>
说明Q命名约?/span>
应避免的名字。永q不要用字符‘l’(写字母el(是读音Q下?/span>))Q?#8216;O’(大写字母oh)Q或‘I’(大写字母eye)作ؓ单字W的变量名。在某些字体中这些字W不能与数字1?/span>0分L。试着在?#8216;l’时用‘L’代替?/span>
模块?/span>
模块应该是不含下划线的,短的Q小写的名字。因为模块名被映到文g名,有些文gpȝ大小写不敏感q且截短长名字,模块名被选ؓ相当短是重要的,q在Unix上不是问题,但当代码传到Mac?/span>Windows上就可能是个问题了?/span>
当用C?/span>C++~写的扩展模块有一个伴?/span>Python模块提供高层(例如q一步的面向对象)接口ӞC/C++模块有下划线前导(如:_socket)?/span>Python包应该是不含下划U的Q简短的Q全写的名字?/span>
cd
几乎不出意料Q类名?/span>CapWordsU定。内部用的cd加一个前g划线?/span>
异常?/span>
如果模块Ҏ有情况定义了单个异常Q它通常被叫?#8220;error”?#8220;Error”。似乎内?/span>(扩展)的模块?#8220;error”(例如Q?/span>os.error)Q?/span>Python模块通常?#8220;Error” (例如Q?/span>xdrlib.Error)。趋势似乎是們使用CapWords异常名?/span>
全局变量?/span>
(让我们祈些变量仅在一个模块的内部有意?/span>)
q些U定和在函数中的一栗模块是被设计ؓ通过“from M import *”来用的Q必ȝ一个下划线作全局变量(及内部函数和c?/span>)的前~防止其被导出(exporting)?/span>
函数?/span>
函数名应该ؓ写Q可能用下划UK格单词以增加可读性?/span>mixedCase仅被允许用于q种风格已经占优势的上下?/span>(如:threading.py)Q以便保持向后兼宏V?/span>
Ҏ名和实例变量
q段大体上和函数相同Q通常使用写单词Q必要时用下划线分隔增加可读性。仅Z打算作ؓcȝ公共界面的内部方法和实例使用一个前g划线Q?/span>Python不强制要求这P它取决于E序员是否遵守这个约定?/span>
使用两个前导下划U以表示cȝ有的名字Q?/span>Python这些名字和cdq接在一P
如果c?/span>Foo有一个属性名?/span>_aQ它不能?/span>Foo._a讉K?/span>(固执的用戯是可以通过Foo._Foo__a得到讉K权?/span>)
通常双前g划线仅被用于避免含子cȝcM的属性名的名字冲H?/span>
l承的设?/span>
始终要确定一个类中的Ҏ和实例变量是否要被公开。通常Q永q不要将数据变量公开Q除非你实现的本质上只是记录Qh们几乎L更喜Ƣ代之给Z个函C为类的界?/span>(Python 2.2 的一些开发者在q点上做得非常漂?/span>)?/span>
同样Q确定你的属性是否应为私有的。私有和非私有的区别在于模板永q不会对原有的类(导出c?/span>)有效Q而后者可以。你应该在大脑中ql承设计好了你的c,U有属性必L两个前导下划U,无后|下划线Q非公有属性必L一个前g划线Q无后置下划U,公共属性没有前导和后置下划U,除非它们与保留字冲突Q在此情况下Q单个后|下划线比前|或混ؕ的拼写要好,例如Q?/span>class_优于klass?/span>
最后一Ҏ些争议:如果相比class_你更喜欢klassQ那么这只是一致性问题?/span>
设计
单个元素(singletons)的比较,?/span>None 应该永远用:‘is’?#8216;is not’来做。当你本意是“if x is not None”Ӟ对写?#8220;if x”要小心。例如当你测试一个默认ؓNone的变量或参数是否被设|ؓ其它值时Q这个g许在布尔上下?/span>(Boolean context)中是falseQ?/span>
Zcȝ异常L好过Z字符串的异常。模块和包应该定义它们自q域内特定的基异常c,基类应该是内建的Exceptioncȝ子类。还始终包含一个类的文档字W串。例如:
#!Python
class MessageError(Exception)Q?/span>
"""Base class for errors in the email package?/span>"""
使用字符串方?/span>(methods)代替字符串模块,除非必须向后兼容Python 2.0以前的版本。字W串ҎL非常快,而且?/span>unicode字符串共用同LAPI(应用E序接口)在检查前~或后~旉免对字符串进行切片。用startswith()?/span>endswith()代替Q因为它们是明确的ƈ且错误更。例如:
NoQ?/span> if foo[Q?/span>3] == 'bar'Q?/span>
YesQ?/span> if foo?/span>startswith('bar')Q?/span>
例外是如果你的代码必d作在Python 1.5.2 (但是我们希望它不会发生!)Q对象类型的比较应该始终?/span>isinstance()代替直接比较cdQ例如:
NoQ?/span> if type(obj) is type(1)Q?/span>
YesQ?/span> if isinstance(objQ?/span> int)Q?/span>
查一个对象是否是字符串时Q紧记它也可能是unicode字符Ԍ?/span>Python 2.3Q?/span>str?/span>unicode有公q基类Q?/span>basestringQ所以你可以q样做:
if isinstance(objQ?/span> basestring)Q?/span>
?/span>Python 2.2cd模块为此定义?/span>StringTypescdQ例如:
#!Python
from types import StringTypes
if isinstance(objQ?/span> StringTypes)Q?/span>
?/span>Python 2.0?/span>2.1Q你应该q样做:
#!Python
from types import StringTypeQ?/span> UnicodeType
if isinstance(objQ?/span> StringType) or \
isinstance(objQ?/span> UnicodeType) Q?/span>
对序列,(字符Ԍ列表Q元l?/span>)Q用空列表?/span>falseq个事实Q因?#8220;if not seq”?#8220;if seq”?#8220;if len(seq)”?#8220;if not len(seq)”好。书写字W串文字时不要依赖于有意义的后置I格。这U后|空格在视觉上是不可辨别的,q且有些~辑?/span>(特别是近来,reindent.py)会将它们修整掉。不要用==来比较布型的g定?/span>True?/span>False(布尔型是Pythn 2.3中新增的)
NoQ?/span> if greeting == TrueQ?/span>
YesQ?/span> if greetingQ?/span>
NoQ?/span> if greeting == TrueQ?/span>
YesQ?/span> if greetingQ?/span>
http://net.pku.edu.cn/%7Eyhf/tao_regexps_zh.html
pythonq种~程语言我很早就听说它了Q早?998q_我在玩Linux的时候,接触过它,但是我对python的印象仅仅停留在它是一U流行的面向对象的脚本语a的认识上?/p>
zopeQ基于python的app serverQ早?000q我已l对它如雯耳了Q但是我对zope的印象仅仅停留在它是一U类似Apache HTTPD ServerQAOL Server之类的web server上?/p>
今年ozzzzzz多次向我提到python和zopeQ听得我x都v了老茧了,dlee又徏议我开设python版面Q虽然我没有{应Q但是架不住朋友们的左劝叛_Q终I对pythonq门语言有了好奇心?/p>
几天前,当我漫不l心的浏览了python和zope的网站之后,我突然有了一U“众里寻它千癑ֺQ那人却在灯火阑珊处”的感觉Q悔不P错过了那么多ơ相逢的Z?/p>
对于软g开发,我和ozzzzzz有一个共识,是脚本解释q型语a在开发效率上q远过~译强类型语aQ从软g开发角度来_脚本语言具备天然的开发效率上的优势,q是pa的内在属性决定的?/p>
例如我们可以比较一下Web~程使用PHP和Servlet/JSPQ比较一下Windows桌面应用使用VB和VC/DelphiQ比较一下Unix环境下面Shell和C/JavaQ比较一下数据库环境下面的PL/SQL和JDBC/SQLJ?/p>
我虽然用Java开发Y件已l有5q的历史了,但是能不用Java的时候,我一定不会用Java的。如果搭Z个小型的|站Q我一定选择PHP而不是JavaQ如果针Ҏ据库的小型编E,我一定用PL/SQL而不是JavaQ如果是桌面应用Q我一定选择VB而不是JavaQ如果是Unix环境我宁愉K择shellQperl甚至PHPQ而不是Java?/p>
做ؓ一U严谨的Q编译式的,面向对象语言QJavaLl我一U须正襟危坐Q须一板一眼的按照OOAD的原则编E,才敢在键盘上敲下字符的感觉。即使编写一个最规模的E序Q我也不能够接受把所有的code塞到main里面的做法。Javag以不怒自威的威严使我不敢随意~码Q不敢玷污Java的严谨。于是我即写一个很单的JDBCE序Q也要一板一眼的try catch finallyQ一层层的处理ConnectionQPreparedStatement和ResultSet?/p>
诚然Q如果开发规模比较大的项目,或者开发自有的软g产品Q必d该按照严谨的方式Q此时Java也是最适合的语a。但是我不想zȝ那么累,很多Z不想zȝ那么累,于是大家都怀念v来脚本语a的好来。对于小规模的应用,使用脚本语言快速简单完成的事情Q当你用Java的时候,你陷入了q多的层层代码包围中厅R于是groovy出现了,bean shell出现了。大家终于明白,~译语言不是软g开发的全部Q脚本语a才是最适合E序员的语言?/p>
我喜Ƣ脚本语aQ喜Ƣ的没边QJava是我的职业,但是我从来都没有在内心深处喜Ƣ过它的语法Q我更加讨厌C++变本加厉的复杂。我钟爱的语a包括学接触的BASIC和LogoQ毕业以后才掌握的Unix Shell和PHPQPerlQPL/SQL。几乎我接触q的每种脚本语言Q我都有厚的兴和感情Q除了VBA是一个例外?/p>
看看Java里面镉K的对象,Ҏ和属性命名,看看Java~程冗长的调用语句和愚蠢的对象赋值和l常长达几十行的getter/setterQ我会时不时从心底泛h心的感觉Q虽然我l常也是q种恶心感觉的制造者。但是恶心归恶心Q我知道Java有它不可取代的作用,PHP有它无法弥补的缺陗大部分脚本语言Q包括perlQPHPQPL/SQLQVBA都不是真正意义上的面向对象编E语aQ即使包括了部分面向对象语言的特性,q注定了脚本语言不能够承担大型项目的开发,甚至也不能够充当良好的可复用的组件存在?/p>
所以我很遗憾,我欣赏PHP脚本语言的开发效率,我也ƣ赏Java的面向对象的能力Q我ƣ赏PHP的低部v成本高可靠运行,我也ƣ赏Java App Server带来的开发复杂运的强大能力Q但是鱼与熊掌不可得兹{?/p>
直到我看Cpython和zopeQ我l于扑ֈ了梦寐以求的东西Q兼有脚本语a开发的高效率,兼有低部|成本的易用性,同时又有完备的面向对象的强大支撑能力Q同时又具备完善的强大的app server支持。最令我生气的还是ploneQ这个运行在zope之上的YӞ你可以称之ؓportalQ或者称之ؓcmsQ或者其他的什么名词,但是我知道它几乎可以实现M|站惌实现的功能。默认安装下Q这个东西很像confluenceQ一个Java的商业的cmsQ但是比confluence功能强大的太多,可定制性,可开发性又强的太多了。plone在默认安装情况下你就可以把它当做cms来用Q比较类?**nukecY?PHPNuke, PostNuke, JBossNuke,...)Q通过插g的扩展,你可以让plone里面集成了forumQblogQwiki的功能,再加上plone本来支持的WebDAVQ功能强大的Z文档的权限控Ӟ多用户多l的理Q你可以在很短的旉内实C个全功能的门L站。可W的是,我从dCq一直在考虑把JavaEye成ؓ一个集成forumQblogQwikiQcms功能的网站,甚至雄心壮志的想要做一个这么的软g产品来,但是现在我发现plone已经漂亮的实Cq一切,最令我沮的是Qozzzzzz在听q我的Y件品计划之后提Z个用关键词来l织|站内容的设惻Il果我发现plone已经q样做了Q我能说的只有惭愧!
我只能感叹自己没有在一q之前就发现ploneQ否则的话现在的JavaEye完整的使用plone来架设。更令我惭愧的是Q当我刚刚意识到zope/plone的h值的时候,上v已经有h成立了专业的zope/plone解决Ҏ的Y件厂商,q且拿下了好几个大型的客P(http://www.zopechina.com)。有时候我们真的不能把眼睛盲目的盯着大厂商强行推q的标准了,应该好好的审视自q正需要的是什么,q且围绕它构q核心竞争力,否则我们只有永远做IT行业食物链最底层的命q?/p>
ozzzzzz曄Ҏ_zope是B/S应用中的VBQ快速原型开发中型企业应用的最x器,我现在真切的理解了他的话。我觉得我们实不能够眼睛光盯着Java/C#不放Q也应该了解一下zope/ploneQ它应该成ؓ中小型企业应用,特别是基于文档管理的企业应用的最重要的解x案?/p>
zope/plone虽然很好Q但是我知道它不会如Java/J2EEQC#/dotnet那样在国内成ZU主的软g开发解x案。原因就在于国内的Y件开发行业长期处于国际分工业链的底层,~Z创新意识和开拓的_Q而往往满于跟随跨国公司的标准Q啃啃h家剩下的肉骨头。位于食物链层的厂商,例如MSQIBMQSunQBEAQCAQOracle{等Q争夺的是标准。他们是规则的制订者,制订好了规则Q放大家q场Q他们负责收费,钱收的差不多了的时候,他们又重新竞争,制订C轮的规则Ql坐地收贏V很多时候,市场的真实需求ƈ没有被真实的体现Q真实的需求被厂商掩盖了。他们创造了一个市场需求,有了市场需求,有pQ赚的差不多了,摧毁这个市场,然后创造下一个市场需求。因此本质上来说QIT行业是几个寡头在博弈,不管谁赢谁输Q我们都是输Ӟ我们只是人家的筹码。大家可以回一下这些年软g技术发展的历程Q寡头厂商制造了EJB市场赚大发了Q寡头厂商了刉了ERP市场赚大发了Q寡头厂商l在刉着SOAQ等着l箋攉。我们不能够被满天飞的技术迷惑了Q我们不能被人卖了还替h家数钱?/p>
所以多多关注一下我们真正需要的技术吧?/p>