Python 的代码风格由 PEP 8 描述。这个文档描述了 Python 编程风格的方方面面。在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格。这样就易于阅读,易于在程序员之间交流。
1 变量
常量 : 大写加下划线
USER_CONSTANT
对于不会发生改变的全局变量,使用大写加下划线。
私有变量 : 小写和一个前导下划线
_private_value
Python 中不存在私有变量一说,若是遇到需要保护的变量,使用小写和一个前导下划线。但这只是程序员之间的一个约定,用于警告说明这是一个私有变量,外部类不要去访问它。但实际上,外部类还是可以访问到这个变量。
内置变量 : 小写,两个前导下划线和两个后置下划线
__class__
两个前导下划线会导致变量在解释期间被更名。这是为了避免内置变量和其他变量产生冲突。用户定义的变量要严格避免这种风格。以免导致混乱。
2 函数和方法
总体而言应该使用,小写和下划线。但有些比较老的库使用的是混合大小写,即首单词小写,之后每个单词第一个字母大写,其余小写。但现在,小写和下划线已成为规范。
私有方法 : 小写和一个前导下划线
def _secrete(self):
print "don't test me."
这里和私有变量一样,并不是真正的私有访问权限。同时也应该注意一般函数不要使用两个前导下划线(当遇到两个前导下划线时,Python 的名称改编特性将发挥作用)。特殊函数后面会提及。
特殊方法 : 小写和两个前导下划线,两个后置下划线
def __add__(self, other):
return int.__add__(other)
这种风格只应用于特殊函数,比如操作符重载等。
函数参数 : 小写和下划线,缺省值等号两边无空格
def connect(self, user=None):
self._user = user
3 类
类总是使用驼峰格式命名,即所有单词首字母大写其余字母小写。类名应该简明,精确,并足以从中理解类所完成的工作。常见的一个方法是使用表示其类型或者特性的后缀,例如:
SQLEngine
MimeTypes
对于基类而言,可以使用一个 Base 或者 Abstract 前缀
BaseCookie
AbstractGroup
class UserProfile(object):
def __init__(self, profile):
return self._profile = profile
def profile(self):
return self._profile
4 模块和包
除特殊模块 __init__ 之外,模块名称都使用不带下划线的小写字母。
若是它们实现一个协议,那么通常使用lib为后缀,例如:
import smtplib
import os
import sys
5 关于参数
5.1 不要用断言来实现静态类型检测
断言可以用于检查参数,但不应仅仅是进行静态类型检测。 Python 是动态类型语言,静态类型检测违背了其设计思想。断言应该用于避免函数不被毫无意义的调用。
5.2 不要滥用 *args 和 **kwargs
*args 和 **kwargs 参数可能会破坏函数的健壮性。它们使签名变得模糊,而且代码常常开始在不应该的地方构建小的参数解析器。
6 其他
6.1 使用 has 或 is 前缀命名布尔元素
is_connect = True
has_member = False
6.2 用复数形式命名序列
members = ['user_1', 'user_2']
6.3 用显式名称命名字典
person_address = {'user_1':'10 road WD', 'user_2' : '20 street huafu'}
6.4 避免通用名称
诸如 list, dict, sequence 或者 element 这样的名称应该避免。
6.5 避免现有名称
诸如 os, sys 这种系统已经存在的名称应该避免。
7 一些数字
一行列数 : PEP 8 规定为 79 列,这有些苛刻了。根据自己的情况,比如不要超过满屏时编辑器的显示列数。这样就可以在不动水平游标的情况下,方便的查看代码。
一个函数 : 不要超过 30 行代码, 即可显示在一个屏幕类,可以不使用垂直游标即可看到整个函数。
一个类 : 不要超过 200 行代码,不要有超过 10 个方法。
一个模块 不要超过 500 行。
8 验证脚本
可以安装一个 pep8 脚本用于验证你的代码风格是否符合 PEP8。
>>easy_install pep8
>>pep8 -r --ignoire E501 Test.py
这个命令行的意思是,重复打出错误,并且忽略 501 错误(代码超过 79 行)。
posted @
2011-02-02 00:45 lincode 阅读(9315) |
评论 (0) |
编辑 收藏
Emacs 不仅仅是一个文本编辑器,它还可用于文件管理。使用 Emacs 作为文件管理工具的话,也解决了跨平台问题,这样在不同平台下,你都可以使用一套工具来管理文件。
1 基本命令
Ctrl + x d : 打开文件管理视图,在文件管理视图中支持的操作如下表:
键值 |
效果 |
Enter |
打开文件 |
a |
打开文件并关闭文件管理视图 |
o |
打开文件,但是在一个新建视图中打开 |
q |
关闭文件管理视图 |
C(大写) |
复制文件 |
R(大写) |
重命名文件 |
D(大写) |
删除文件 |
2 基于文件集合的命令
这主要是使一条命令作用于几个文件。方法是标记你要操作的文件。
基本命令为 m
键值 |
效果 |
m |
标记文件 |
u |
去掉标记 |
U |
标记所有文件 |
t |
反向所以文件 |
% m |
基于正则表达式,标记文件 |
3 其他相关命令
在文件管理视图中还可以做到:
键值 |
效果 |
g |
刷新文件夹 |
^ |
返回上级目录 |
+ |
创建一个文件夹 |
Z |
压缩或解压文件 |
posted @
2011-02-01 18:14 lincode 阅读(1058) |
评论 (0) |
编辑 收藏
我使用的是 goddady 的 VPS。家里使用 mac 。所以直接在 terminal 中使用 ssh 连接服务器即可。
> ssh 189.129.1.12 -l username
敲入密码,进入服务器。
> su
敲入密码,进入根用户。
> cd /etc/ngnix/
进入 ngnix 配置文件目录,进入 conf.d 目录
> vim ghs.conf
建立一个 配置文件
一个范例:
upstream ghs {
ip_hash;
server ghs.google.com;
server 72.14.203.121;
server 72.14.207.121;
server 74.125.43.121;
server 74.125.47.121;
server 74.125.53.121;
server 74.125.77.121;
server 74.125.93.121;
server 74.125.95.121;
server 74.125.113.121;
server 216.239.32.21;
server 216.239.34.21;
server 216.239.36.21;
server 216.239.38.21;
}
server {
listen 80;
server_name ghs.myhosts.com www.test.com;
access_log /data/logs/ghs_proxyaccess.log;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_pass http://ghs;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_redirect false;
}
}
>/etc/init.d/ngnix start
启动 nginx
在本机的浏览器中敲入反向代理 server 的 ip,能看到 ngnix 的蓝色的界面,这验证了 ngnix 启动正常
> ping ghs.myhosts.com
应该指向反向代理 server 的 ip
首先将你的域名例如,www.tests.com 绑定到 google app engine 的你的目标 application 上
然后,在你的域名服务提供商那里,添加一个 www.tests.com 指向 ghs.myhosts.com 的 CNAME 即可。
posted @
2010-12-15 07:12 lincode 阅读(496) |
评论 (0) |
编辑 收藏
transient:
java有个特点就是序列化,简单地来说就是可以将这个类存储在物理空间(当然还是以文件的形式存在),那么当你从本地还原这个文件时,你可以将它转换为它本身。这可以极大地方便网络上的一些操作,但同时,因为涉及到安全问题,所以并不希望把类里面所有的东西都能存储(因为那样,别人可以通过序列化知道类里面的内容),那么我们就可以用上transient这个关键字,它的意思是临时的,即不会随类一起序列化到本地,所以当还原后,这个关键字定义的变量也就不再存在。
volatile:
Volatile 修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
Java 语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。
这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。
而volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
使用建议:在两个或者更多的线程访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,不必使用。
由于使用volatile屏蔽掉了VM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。
posted @
2010-06-14 23:03 lincode 阅读(215) |
评论 (0) |
编辑 收藏
一 基本概念
单例模式是一种为类 提供唯一实例的设计模式。单例模式的目的是为了控制对象的创建,它可以限制创建的数目为一,但在情况改变的时候,也允许灵活地创建更多的对象。因为只有一个实例,所以也只有一套实例的类变量的拷贝,这很像 static 变量。
在 JAVA 中,单例模式不应该被当作一种实现全局变量的方法。更多的,如同工厂模式,单例模式允许你通过 确认某些先决条件是否满足 或者 以 lazily 方式按需创建的方式 来封装和控制创建过程。
二 编程实现
1 饥饿模式 Eager Singleton
public class MySingleton {
private static MySingleton fInstance = new MySingleton();
private MySingleton(){
// Construct object
}
public static MySingleton getInstance(){
reutnr fInstance;
}
}
2 懒汉模式 Lazy Singleton
public class MySingleton {
private static MySingleton fInstance;
private MySingleton(){
// construct object
}
public static synchronized MySingleton getInstance(){
if (fInstance == null){
fInstance = new MySingleton();
}
return fInstance;
}
}
由于只有一个私有构造器,所以单例类是无法被集成的。基于这一点,单例模式并不是一个面向对象模式,仅仅是一个基于对象的模式。
3 饥饿模式基本没有问题,懒汉模式则容易出现一些错误的编程方法
1)
// error, no synchronization on method
public static MySingleton getInstance() {
if (fInstance==null) {
fInstance = new MySingleton();
}
return fInstance;
}
2)
// Also an error, synchronization does not prevent
// two calls of constructor.
public static MySingleton getInstance() {
if (fInstance==null) {
synchronized (MySingleton.class) {
fInstance = new MySingleton();
}
}
return fInstance;
}
3) Double-checked locking 不要使用
public static MySingleton getInstance(){
if (fInstance == null ){
synchronized (MySingleton.class) {
if(fInstance == null){
fInstance = new MySingleton();
}
}
}
}
为了避免每次调用 getInstance方法是抓取同步锁的消耗,有人发明了 Double-checked locking 。但不要使用,因为这样的代码将无法在编译器优化和多处理器共享内存的情况下工作。若想详细了解,附录中有对此做详细描述的链接。
三 总结
1 单例模式不应被滥用,比如不能为了得到一个全局变量而创建单例,单例是用于控制对象的创建过程的。只有真正的目的是控制对象创建的过程或数量时,才能考虑使用单例。在大部分情况下,单例模式是有代替方案的。比如经典的数据库连接类被以单例实现,其实可以以对象池模式实现。
2 使用单例模式,尽量使用饥饿模式 ,只有你能预测这个类一定会被创建,那么就可以使用饥饿模式。如果,一定需要推迟对象的创建时间。那么不要使用 Double-checked locking 之类的方法的来提高效率,这将得不偿失。
[1] DoubleCheckedLocking
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
posted @
2010-04-30 21:04 lincode 阅读(206) |
评论 (0) |
编辑 收藏
一 基本概念
这篇文章比较清楚地讲述了字符集和编码的基本概念
http://www.regexlab.com/zh/encoding.htm
摘抄:
各个国家和地区所制定的不同 ANSI 编码标准中,都只规定了各自语言所需的“字符”。比如:汉字标准(GB2312)中没有规定韩国语字符怎样存储。这些 ANSI 编码标准所规定的内容包含两层含义:
- 使用哪些字符。也就是说哪些汉字,字母和符号会被收入标准中。所包含“字符”的集合就叫做“字符集”。
- 规定每个“字符”分别用一个字节还是多个字节存储,用哪些字节来存储,这个规定就叫做“编码”。
各个国家和地区在制定编码标准的时候,“字符的集合”和“编码”一般都是同时制定的。因此,平常我们所说的“字符集”,比如:GB2312, GBK, JIS 等,除了有“字符的集合”这层含义外,同时也包含了“编码”的含义。
“UNICODE 字符集”包含了各种语言中使用到的所有“字符”。用来给 UNICODE 字符集编码的标准有很多种,比如:UTF-8, UTF-7, UTF-16, UnicodeLittle, UnicodeBig 等。
二 eclipse 中对于编码方式的设置
1 源文件的编码设置
preference -> general -> Content Types
右边选择文件类型,右下更新 缺省编码方式
2 控制台的编码设置
Run -> Run configuration( 或 Debug configuration)
右边选项卡中 common, 一般为最后一项
在 console encoding 的 other 中选取需要的 编码方式
三 java 中的 编码转换
byte[] bytes = oldStr.getBytes(); //默认编码方式下的字节数组
String newStr = new String( bytes, "UTF-8" ); //转换成 UTF-8 编码下的字符串
posted @
2010-04-29 23:31 lincode 阅读(251) |
评论 (0) |
编辑 收藏
Java 中函数参数传递和函数返回值都是以值方式传递的。当然,对于对象,我们也可以说是引用的方式传递,其实传递也是值,只不过是引用值。引用是一个对象的别名,对于引用的修改就是对于对象本身的修改。
为了便于理解还是可以说成是两种类型,原始类型以值方式传递,对象以引用方式传递。
向函数里传递参数,已经有很多java教程讲解了。这里主要记录一个 函数返回值的问题。在返回一个对象时,是返回值本身的应用,还是拷贝这个值,再传拷贝的引用呢。这是需要考虑清楚的。
这个问题,是我在 不同手机上调试 J2ME 程序时遇到的。
具体如下,这是一个关于时间的工具类。我发觉
Calendar 的 getTime() 在有的机器下 如 Nokia,返回的
Calendar 当前时间的一个拷贝的引用,而 SAMSUNG 则直接返回
Calendar 的当前时间的引用。这导致,我在想得到一个时间所在那一的起始时间和结束时间时,总是得到相同的值,即后一次调用的值。按照,比较正常的理解,这里应该返回拷贝的引用比较正确,就是说 SAMSUNG 的 JVM 实现有些问题。面对这种情况,我只能先用 Date 类 返回 一个 long 值,再用 long 值构造一个新日期,即日历当前日期的拷贝,返回这个拷贝。
修改函数中的最后一行为
return new Date(fCalendar.getTime().getTime());
private static Date fCalendar = Calendar.getInstance();
/**
* Get the beginning of a day
* @param date <description>
* @return <description>
*/
public static Date getBeginOfDay( final Date pDate ) {
fCalendar.setTime( pDate );
try{
fCalendar.set( Calendar.HOUR_OF_DAY, 0 );
fCalendar.set( Calendar.MINUTE, 0 );
fCalendar.set( Calendar.SECOND, 0 );
}catch(ArrayIndexOutOfBoundsException ex){
ex.printStackTrace();
}
return fCalendar.getTime();
}
/**
* Get the end of a day
* @param date <description>
* @return <description>
*/
public static Date getEndOfDay( final Date pDate ){
fCalendar.setTime( pDate );
try{
fCalendar.set( Calendar.HOUR_OF_DAY, 23 );
fCalendar.set( Calendar.MINUTE, 59 );
fCalendar.set( Calendar.SECOND, 59 );
}catch(ArrayIndexOutOfBoundsException ex){
ex.printStackTrace();
}
return fCalendar.getTime();
}
posted @
2010-02-24 21:36 lincode 阅读(2290) |
评论 (0) |
编辑 收藏
摘要: 原则很简单: 不要使用 字符串链接操作符来合并多个字符串,除非性能无关紧要。相反,应该使用StringBuffer的append方法,或者采用其它的方案,比如使用字符数组,或者每次只处理一个字符串,而不是将它们组合起来。
阅读全文
posted @
2010-02-10 18:46 lincode 阅读(404) |
评论 (0) |
编辑 收藏
J2me 中使用 Log, 可以使用搜索引擎搜索下载 log4j2me.
使用方法和 j2se 中有一些区别,下面是在 log4j2me 包中的一个例子
package log4j2me.test;
import org.apache.log4j.*;
import org.apache.log4j.helpers.LogLog;
/**
Very simple log4j usage example.
@author Ceki Gülcü, Witmate
*/
// Modifiers: Witmate [Nov,2004: Modified for log4j2me]
public class Hello {
static Category log = Category.getInstance(Hello.class);
static Category log1 = Category.getInstance("Hello");
public static void main(String argv[]) {
Category root = Category.getRoot();
root.setPriority( Priority.DEBUG );
Layout layout = new PatternLayout("%p [%t] %c - %m%n");
try {
root.addAppender(new FileAppender(layout, System.out));
} catch(Exception e) {
LogLog.warn("Could not open file appender.");
}
log.debug("Hello world.");
log.info("What a beatiful day.");
log1.debug("Hello world.");
log1.info("What a beatiful day.");
}
}
posted @
2010-01-28 01:13 lincode 阅读(362) |
评论 (0) |
编辑 收藏
摘要: Django 的 template 有继承功能。这两天遇到一个问题,
仅仅包含 {% extends "base.html" %} 一条语句的子 html 文件在浏览器中和 base.html 的渲染结果不一样。
搞了两天才找出问题的原因。是子文件选择了 UTF-8 格式。
所有的文件应该都选择 UTF-8 without BOM 格式。这样就得到一致的结果了。
阅读全文
posted @
2009-12-31 06:37 lincode 阅读(221) |
评论 (0) |
编辑 收藏