python - 常用模块栗子
内容摘自Python参考手册(第4版) 及 自己测试后得出。仅作为一个简单记录,方便使用查询之用。
另 dir(func)及func.__doc__可以查看对象属性及说明文档。
序列包括字符串、列表、元组。
a = [5,6,3,2]
b = [1,3]
1、连接 s+r
c = a + b # [5,6,3,2,1,3]
2、解包 V1,V2..,Vn = s
v1,v2,v3,v4 = a #v1 = 5,v2 = 6 ,v3 = 3 ,v4 =2
3、索引 s[i],切片 s[i:j],s[i:j:stride]
v = a[0] # 5 c = a[0:2] # [5,6] d = a[0:2:2] # [5] e = a[3:2:-1] # [2] stride负数则反过来取子序列
4、从属关系 x in s , x not in s
3 in a # True 0 in a # False
5、迭代 for x in s:
for x in a: print x # 5 6 3 2
6、其他
print all(a) # True 全部为True返回True print any(a) # True 任意为True返回True print len(a) # 4 长度 print min(a) # 2 最小值 print max(a) # 6 最大值 print sum(a) # 16 和
7、复制
a = [ 1,2 ,[3,4]] b = list(a) # 浅复制 地址拷贝,值类型拷贝 b[0] = 6 # a = [1,2,[3,4]] b = [6,2,[3,4]] b[2][0] = 5 # a = [1,2,[5,4]] b = [6,2,[5,4]] # 深拷贝 import copy b = copy.deepcoy(a) b[2][0] =5 # a = [1,2,[3,4]] b = [6,2,[5,4]]
一、取模运算符(s%d) 生成格式化字符串,s是一个格式字符串,d是对象元组或映射对象(字典)。
在 字符串内 %后修饰符意思:
1)位于括号内的键名,映射对应字典内的对象。
2) ' - ' 字符 表示左对齐,默认右对齐。 ' + ' 表示包含数字符号(正负号) 。 ' 0 ' 表示一个零填充。
3) 一个指定最小自动宽度的数字。(%10d ) 长度为10
4) 一个小数点,按精度分割字段宽度。
5) 一个数字,指定打印字符串的最大字符个数 ,浮点数中小数点之后的位数,或者整数最小位数。
6) 星号(*),用于在任意宽度字段中替换数字。
栗子:
a = 42 b = 3.1415926 c = "hello world" d ={'x':13,'y':b,'z':c} e = 123456789012345678901234567890 r ="a is 10:%d 16:%x 8:%o" % (a,a,a) #a is 10:42 16:2a 8:52 r ="%10d %f %E" % (a,b,b) # 42 3.141593 3.141593E+00 r ="%(x)-10d %(y)0.3g" % d #13 3.14 #g,G表示指数小于-4使用%e或%E,否则使用%f stock ={ 'name': 'GooG', 'shares':100, 'price': 490.10 } r = "%(shares)d of %(name)s at %(price)0.2f" % stock #100 of GooG at 490.10 shares =111 name ="currect_name" r = "%(shares)d of %(name)s" %vars() # 111 of currect_name #vars() 取当前变量名表示的值
二、用字符串的 s.format(*args,*kwargs) 方法。
1) {n} 占位符,n为数字,将被format()方法的位置参数n代替。
2) {name} 占位符,将被format()方法关键字参数name所代替。
栗子:
r = "{0} {1} {2} {age}".format('GOOG',100,490.10,age =47) # GOOG 100 490.1 47 r = "Use {{ and }} to output single curly braces".format() # Use { and } to output single curly braces r = "{0[name]:8} {0[shares]:8d} {0[price]:0.3f}".format(stock) # GooG 100 490.100
装饰器是一个函数,主要用途是包装另一个函数或类。
栗子:
1) 函数装饰器
enable_tracing = True def trace(func): if enable_tracing: def callf(*args,**kwargs): print("Calling %s: %s, %s\n" % (func.__name__,args,kwargs)) r = func(*args,**kwargs) print("%s returned %s\n" % (func.__name__,r)) return r return callf else: return func @trace def square(x): return x*x print square(5) #>>>>>>>>>>>>> Calling square: (5,), {} square returned 25 25
上述trace就是装饰器,添加@trace相当于执行square = trace(square)。而为了保持被装饰函数的属性不被改变,装饰器需要做如下处理:
def trace(func): if enable_tracing: def callf(*args,**kwargs): print("Calling %s: %s, %s\n" % (func.__name__,args,kwargs)) r = func(*args,**kwargs) print("%s returned %s\n" % (func.__name__,r)) return r callf.__doc__ = func.__doc__ callf.__name__ = func.__name__ callf.__dict__.update(func.__dict__) return callf else: return func
2) 类装饰器:
def register(cls): def cls__init(self): print 'register init!' cls.__init__ =cls__init return cls @register class Foo(object): def __init__(self): print "Foo init!" Foo() #register init!
类定义了一组属性,这些属性与一组叫做实例的对象相关且由其共享。类通常是由函数(方法)、变量(类变量)和计算出的属性(特性)组成的集合。
1) 继承
# 父类 class classA(object): var = 0 def __init__(self): self.classname = classA.__name__ def show(self): print self.var,self.classname # 子类 class classB(classA): def __init__(self): classA.__init__(self) self.classname = classB.__name__ f = classB() f.show() # 0 classB
实例方法默认第一个参数都是self,函数定义也要有self作为第一个参数。
2) 静态方法
相当于用类名作为命名空间的方式的普通函数。
class Foo(object): @staticmethod def add(x,y): return x+y x = Foo.add(233,332) # x = 565
3) 类方法
将类作为第一个参数的函数。
class Foo(object): @classmethod def show_classname(cls): return cls.__name__ f = Foo() print f.show_classname() # 'Foo' print Foo.show_classname() # 'Foo'
4) 特性 (property)
实例或者类的属性方法,可以直接通过访问属性得到函数值。
import math class Circle(object): __radius = 1.0 @property def area(self): return math.pi*self.__radius**2 @property def perimeter(self): return 2*math.pi*self.__radius @property def radius(self): return self.__radius @radius.setter def radius(self,var): self.__radius = var @radius.deleter def radius(self): self.__radius = 1.0 f = Circle() f.radius =4.0 print f.area # 50.2654824574 print f.perimeter # 25.1327412287 del f.radius print f.area # 3.14159265359 print f.perimeter # 6.28318530718
属性.setter和.deleter分别表示对属性设置和删除
除了上述方法外,也可以用类的默认属性函数 __getattr__,__setattr__,__delattr。如下所示,还实现了只读的功能。
class Circle(object): radius = 1.0 def __getattr__(self,name): if name == 'area': return math.pi*self.radius**2 elif name == 'perimeter': return 2*math.pi*self.radius else: return object.__getattr__(self,name) def __setattr__(self,name,value): if name in ['area','perimeter'] : raise TypeError("%s readonly" % name) object.__setattr__(self,name,value)
5) 元类 __metaclass__
用来创建和管理类的对象。
class DocMeta(type): def __init__(self,name,bases,dict): for key,value in dict.items(): print key,value # 以"__"开始的 默认函数不检查 if key.startswith("__"):continue # 仅检测可以调用 "__call__" 的函数 if not hasattr(value,"__call__"):continue # 判断函数是否有说明文档 if not getattr(value,"__doc__"): raise TypeError("%s must have a docstring" % key) type.__init__(self,name,bases,dict) class Circle(object): __metaclass__ = DocMeta
6) 弱引用 weakref
可以用来检测对象是否被正常释放。简单栗子如下:
import weakref class LeakObserver(object): table_observers = [] @classmethod def add(cls,obj): "添加需要监听释放的对象" cls.table_observers.append(weakref.ref(obj)) @classmethod def findLeak(cls): "查找未被正常释放对象" cls.table_observers = [ref for ref in cls.table_observers if ref()] print cls.table_observers a = Circle() LeakObserver.add(a) #del a LeakObserver.findLeak()
通过在函数内使用yield语句的方式,称为协程。先执行next()或for循环才会时函数执行到yield语句。如果yield在左侧则循环生成列表返回,如果在右侧则挂起等待send()消息传入yield处。
1) yield在左侧
import os import fnmatch def find_files(topdir,pattern): for path,dirname,filelist in os.walk(topdir): for name in filelist: if fnmatch.fnmatch(name,pattern): yield os.path.join(path,name) import gzip,bz2 def opener(filenames): for name in filenames: if name.endswith(".gz"): f = gzip.open(name) elif name.endswith(".bz2"): f = bz2.BZ2File(name) else: f = open(name,"r") yield f def cat(filelist): for f in filelist: for line in f: yield line def grep(pattern,lines): for line in lines: if pattern in line: yield line debuglogs = 'debug.log' files = opener(debuglogs) lines = cat(files) pylines = grep("python",lines) for line in pylines: sys.stdout.write(line)
在该栗子中,整个程序由最后的for语句驱动,中间不会产生临时列表等,占用内存极少。
2)yield在右侧
def receiver(): print("ready to receiver") while True: n = (yield) print("Got %s" % n) r = receiver()
r.next() r.send("hello")
执行next()后,函数执行到yield处。
通过 import logging 来使用 logging模块记录日志。
1) 基本配置
通过 basicConfig设置默认的日志配置。如下:
import logging logging.basicConfig( filename ="app.log", format = "%(levelname)-10s %(asctime)s %(message)s", level = logging.INFO )
然后通过正常的logging记录如下:
log = logging.getLogger('app') log.info("hello world")
这样可以在 app.log文件中看到按format格式输出的记录了。
2) 筛选日志
通过addFilter,setLevel可以对单独的logging对象进行输出控制。如下:
format = logging.Formatter("%(levelname)-10s %(asctime)s %(message)s") log = logging.getLogger('app.test') log.addHandler(logging.FileHandler('app.test.log')) # 添加输出到文件 stdout_hand = logging.StreamHandler(sys.stdout) # 输出到控制台显示 stdout_hand.setFormatter(format) # 设置输出格式 log.addHandler(stdout_hand) # 添加输出Handler log.setLevel(logging.ERROR) # 设置消息级别 log.info("info message!") log.log(logging.ERROR,"error message!")
这样控制台和app.test.log文件都会按格式输出错误消息!"ERROR 2016-03-28 10:29:28,651 error message!"
而因为基础设置上的设置,app.log上会输出info和error的日志信息。
3) 其他
log.propagate = False #禁止输出到父级log对象 'app.test' -> ‘app’
log.close() #关闭当前输出log对象
optparse模块处理sys.argv中提供的UNIX风格命令行选项高级支持。栗子如下:
import optparse p = optparse.OptionParser() #简单项,不带参数 p.add_option("-t",action = "store_true",dest = "tracing") #接受字符串参数 p.add_option("-o","--outfile",action = "store", type = "string",dest= "outfile") #接收整数 p.add_option("-d","--debuglevel",action = "store", type = "int",dest= "debug") #带选项参数 p.add_option("--speed",action = "store" , type ="choice",dest="speed",choices=["slow","fast","ludicrous"]) #多个参数 p.add_option("--coord",action = "store", type="int", dest="coord",nargs =2) #一组控制常用目的地的选项 p.add_option("--novice",action="store_const",const="novice",dest="mode") p.add_option("--guru",action="store_const",const="guru",dest="mode") #设置默认值 p.set_defaults(tracing=False,debug=0,speed="fast",coor=(0,0),mode="novice") opt,args = p.parse_args() print opt,args
可以通过输入test.py(文件名) -h参看说明。
以下仅摘自参考手册并没有进行过系统测试。
1、理解程序
a、 理解算法
b、使用内置类型
2、不要添加层
import timeit print timeit.timeit("s= {'name':'GOOG','shares':100,'price':490.10}") #0.139700907932 print timeit.timeit("s = dict(name='GOOG',shares=100,price = 490.10)") #0.341468762487
3、了解如何基于字典构建类和实例
如果值构建简单数据结构存储数据,字典比类可能更好。
4、使用__slots__
不实用字典(__dict__)存储实例数据,内存少,访问效率高。__slots__ =['name','shares','price']
5、避免使用(.)运算符
6、使用异常处理不常见的情况
正常情况下不会抛出异常的代码设置try代码块比if语句速度更快。
7、避免对常见情况使用异常
#方法1 try: value = items[key] except KeyError: value = None #方法2 if key in items: value = items[key] else: value = None
大部分是查找得到值的情况下,方法2运算是方法1的17倍。而且in运算符比方法调用(items.get(key))更快。
8、鼓励使用函数编程和迭代
9、使用装饰器和元类