python 学习
2014-09-10 23:40 cmLighters 阅读(164) 评论(0) 收藏 举报python语言数据类型: 整、浮、字符串('' "abc" '''...''')、布尔(True False,与或非对应and or not)、空值None。
注意:None不是0,而是特殊的值。 0不是False,1也不是True。
变量和常量: 整数的运算总是精确地,10/3=3。变量的赋值需要区分。 复杂元素如列表,
1 >>> a=['abc', 'cde'] 2 >>> b = a 3 >>> b 4 ['abc', 'cde'] 5 >>> a.remove('abc') 6 >>> a 7 ['cde'] 8 >>> b 9 ['cde']
简单元素如字符串:
1 >>> a='abc' 2 >>> b = a 3 >>> a = 'xyz' 4 >>> b 5 'abc'
字符串可见廖雪峰python教程中变量部分,而较复杂类型变量为了节省开销,b和a同时只想同一内存区,复制复杂类型变量可以使用切片。
pass语句单独成行,用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。实际上该语句什么也不做。
名称空间与作用域:
名称空间是名字与对象间的映射关系,作用域是变量在用户代码的哪些物理位置上可以访问这些名字。
python可以在任何需要放置数据的地方获得一个名字空间:
def foo(): pass foo.x = 1 foo.__doc__ = 'Oops, forgot to add doc str ablove!'
模块的导入和加载:导入模块时,若在函数中导入,它的作用域是局部的。若模块第一次被导入,它将被加载并执行。一个模块只被加载一次且只在第一次导入时发生。
使用from module import var可以把模块的属性导入当前名字空间,即不需要使用module.var而是直接使用var就可以了。所以应严格使用from module import *语句。
判断python中某对象是否可迭代:
>>> from collections import Iterable >>> isinstance('abc', Iterable) # str是否可迭代 True >>> isinstance([1,2,3], Iterable) # list是否可迭代 True >>> isinstance(123, Iterable) # 整数是否可迭代 False
如何判断一个函数是否是一个特殊的 generator 函数?使用 isgeneratorfunction 判断
>>> from inspect import isgeneratorfunction >>> isgeneratorfunction(fab) True
生成器详解:http://blog.csdn.net/xiaobei4929/article/details/10394409
类中变量类别和下划线'_'的含义:
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。
有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量
python函数
参数是按优先级排序的,普通参数 - 默认参数 - 可变参数 - 关键字参数,这么设计的目的是任何函数都可以通过func(*args, **kw)调用,无论它的参数怎么定义
python中super函数:
super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type) -> unbound super object
super(type, type2) -> bound super object; requires issubclass(type2, type)
Typical use to call a cooperative superclass method:
class C(B):
def meth(self, arg):
super(C, self).meth(arg)
可以看出函数返回的是父类对象,最后三行表示多用于调用父类中meth函数
闭包函数:
def lazy_sum(*args): def sum(): ax = 0 for n in args: ax = ax + n return ax return sum
我们在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。
【python类和对象】
类的主要特性有封装、继承、多态。多态有继承产生,多继承用到Mixin。
Mixin的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个Mixin的功能,而不是设计多层次的复杂的继承关系。
metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。连接起来就是:先定义metaclass,就可以创建类,最后创建实例。所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。
class ModelMetaclass(type): def __new__(cls, name, bases, attrs): if name=='Model': #如果是Model,则只下面return语句,否则说明是其他Model的子类,这时候使用Model中定义时使用的元类ModelMetaclass。 return type.__new__(cls, name, bases, attrs) #cla: Model, name: 'Model', bases: dict, attrs: Model's attrs mappings = dict() for k, v in attrs.iteritems(): if isinstance(v, Field): print('Found mapping: %s==>%s' % (k, v)) mappings[k] = v for k in mappings.iterkeys(): attrs.pop(k) attrs['__table__'] = name # 假设表名和类名一致 attrs['__mappings__'] = mappings # 保存属性和列的映射关系 return type.__new__(cls, name, bases, attrs)
实例属性优先级比类属性高
异常
异常的Traceback打印结果是
如果不捕获错误,自然可以让Python解释器来打印出错误堆栈,但程序也被结束了。既然我们能捕获错误,就可以把错误堆栈打印出来,然后分析错误原因,同时,让程序继续执行下去。
logging的使用
raise ValueError, e: logging.exception(e) #终端中第一行打印出该异常
import logging logging.basicConfig(level=logging.INFO) logging.info('n = %d' % n)
这就是logging的好处,它允许你指定记录信息的级别,有debug,info,warning,error等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。同理,指定level=WARNING后,debug和info就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。logging的另一个好处是通过简单的配置,一条语句可以同时输出到不同的地方,比如console和文件。
hashlib的使用——摘要算法,用于存储密码摘要,建议使用 用户名+密码+Salt 来生成摘要存储到数据库中。
import hashlib md5 = hashlib.md5() md5.update('how to use md5 in python hashlib?') print md5.hexdigest()
md5还可换成sha1或者其他sha224, sha256等
unittest的使用——单元测试
import unittest class IntegerArithmeticTestCase(unittest.TestCase): #继承TestCase def testAdd(self): ## test method names begin 'test*' self.assertEqual((1 + 2), 3) self.assertEqual(0 + 1, 1) def testMultiply(self): self.assertEqual((0 * 10), 0) self.assertEqual((5 * 8), 40) if __name__ == '__main__': unittest.main() #用该语句进行测试,或者在shell下使用‘python -m unittest ModelNameOfTestfile’
time的使用——计算程序端运行时间time(),让程序沉睡多少秒sleep().
文件IO
字符编码
要读取非ASCII编码的文本文件,就必须以二进制模式打开,再解码。比如GBK编码的文件:
>>> f = open('/Users/michael/gbk.txt', 'rb') >>> u = f.read().decode('gbk') >>> u u'\u6d4b\u8bd5' >>> print u 测试
如果每次都这么手动转换编码嫌麻烦(写程序怕麻烦是好事,不怕麻烦就会写出又长又难懂又没法维护的代码),Python还提供了一个codecs模块帮我们在读文件时自动转换编码,直接读出unicode:
import codecs with codecs.open('/Users/michael/gbk.txt', 'r', 'gbk') as f: f.read() # u'\u6d4b\u8bd5'
你可以反复调用write()来写入文件,但是务必要调用f.close()来关闭文件。当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。所以,还是用with语句来得保险:
with open('/Users/michael/test.txt', 'w') as f: f.write('Hello, world!')
操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中。基本上操作目录的放在os.path中。文件的重命名os.rename, 删除os.remove,拷贝用shutil模块提供了copyfile()的函数
【序列化】
我们把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
ython提供两个模块来实现序列化:cPickle和pickle。这两个模块功能是一样的,区别在于cPickle是C语言写的,速度快,pickle是纯Python写的,速度慢,跟cStringIO和StringIO一个道理。用的时候,先尝试导入cPickle,如果失败,再导入pickle:
try: import cPickle as pickle except ImportError: import pickle
pickle的dump方法将对象dump到file-like Object中,dumps将对象dump为字符串。load方法从file-like Object中读取对象,loads将dumps的对象反序列化出来
>>> d = dict(name='Bob', age=20, score=88) >>> pickle.dumps(d) "(dp0\nS'age'\np1\nI20\nsS'score'\np2\nI88\nsS'name'\np3\nS'Bob'\np4\ns." >>> f = open('dump.txt', 'wb') >>> pickle.dump(d, f) >>> f.close() >>> f = open('dump.txt', 'rb') >>> d = pickle.load(f) >>> f.close() >>> d {'age': 20, 'score': 88, 'name': 'Bob'}
JSON
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。同pickle,json也有dump,dumps, load, loads。
json的高级用法:
import json
class Student(object):
def __init__(self, name, age, score):
self.name = name
self.age = age
self.score = score
def student2dict(std):
return {
'name': std.name,
'age': std.age,
'score': std.score
}
s = Student('Bob', 20, 88)
print(json.dumps(s, default=student2dict))
def dict2student(d):
return Student(d['name'], d['age'], d['score'])
json_str = '{"age": 20, "score": 88, "name": "Bob"}'
print(json.loads(json_str, object_hook=dict2student)) #<__main__.Student object at 0x10cd3c190>
0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getppid()就可以拿到父进程的ID。import os print 'Process (%s) start...' % os.getpid() pid = os.fork() if pid==0: print 'I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()) else: print 'I (%s) just created a child process (%s).' % (os.getpid(), pid) 结果: Process (876) start... I (876) just created a child process (877). I am child process (877) and my parent is 876.
但是windows下没有fork()系统调用,由于Python是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块。multiprocessing模块提供了一个Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束:
from multiprocessing import Process import os # 子进程要执行的代码 def run_proc(name): print 'Run child process %s (%s)...' % (name, os.getpid()) if __name__=='__main__': print 'Parent process %s.' % os.getpid() p = Process(target=run_proc, args=('test',)) print 'Process will start.' p.start() #子进程开始执行 p.join() #等待子进程执行结束 print 'Process end.'
#执行结果如下:
Parent process 928.
Process will start.
Run child process test (929)...
Process end.
Pool
如果要启动大量的子进程,可以用进程池的方式批量创建子进程:
from multiprocessing import Pool import os, time, random def long_time_task(name): print 'Run task %s (%s)...' % (name, os.getpid()) start = time.time() time.sleep(random.random() * 3) end = time.time() print 'Task %s runs %0.2f seconds.' % (name, (end - start)) if __name__=='__main__': print 'Parent process %s.' % os.getpid() p = Pool() for i in range(5): p.apply_async(long_time_task, args=(i,)) print 'Waiting for all subprocesses done...' p.close() p.join() print 'All subprocesses done.'
#执行结果如下:
Parent process 669.
Waiting for all subprocesses done...
Run task 0 (671)...
Run task 1 (672)...
Run task 2 (673)...
Run task 3 (674)...
Task 2 runs 0.14 seconds.
Run task 4 (673)...
Task 1 runs 0.27 seconds.
Task 3 runs 0.86 seconds.
Task 0 runs 1.41 seconds.
Task 4 runs 1.91 seconds.
All subprocesses done.
对Pool对象调用join()方法会等待所有子进程执行完毕,调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。请注意输出的结果,task 0,1,2,3是立刻执行的,而task 4要等待前面某个task完成后才执行,这是因为Pool的默认大小在我的电脑上是4,因此,最多同时执行4个进程。这是Pool有意设计的限制,并不是操作系统的限制。如果改成:
p = Pool(5)
就可以同时跑5个进程。
由于Pool的默认大小是CPU的核数,如果你不幸拥有8核CPU,你要提交至少9个子进程才能看到上面的等待效果。
进程间通信
Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。
from multiprocessing import Process, Queue import os, time, random # 写数据进程执行的代码: def write(q): for value in ['A', 'B', 'C']: print 'Put %s to queue...' % value q.put(value) time.sleep(random.random()) # 读数据进程执行的代码: def read(q): while True: value = q.get(True) print 'Get %s from queue.' % value if __name__=='__main__': # 父进程创建Queue,并传给各个子进程: q = Queue() pw = Process(target=write, args=(q,)) pr = Process(target=read, args=(q,)) # 启动子进程pw,写入: pw.start() # 启动子进程pr,读取: pr.start() # 等待pw结束: pw.join() # pr进程里是死循环,无法等待其结束,只能强行终止: pr.terminate()
python内建collections模块
namedtuple创建自己命名的tuple类,如p = namedtuple('Point', ['x', 'y'])
deque双链表插入和删除比list快很多,因为list是线性存储的。
defaultdict(factory_func)创建一个如果key不存在就调用factory_func函数的dict。其他与普通dict相同。
OrderedDict是有序字典。现有dict不是有序的
Counter计数器
base64:
Base64适用于小段内容的编码,比如数字证书签名、Cookie的内容等。常用于在URL、Cookie、网页中传输少量二进制数据
【python高级编程】
#python网络编程#
读取网页:httplib、urllib、 urllib2、urllib3 http://www.verydemo.com/demo_c122_i18730.html、 requests http://docs.python-requests.org/en/latest/
http://www.douban.com/group/topic/40995866/。 解析网页: BeautifulSoup
urllib与urllib2区别:http://stackoverflow.com/questions/2018026/should-i-use-urllib-or-urllib2-or-requests http://www.cnblogs.com/yuxc/archive/2011/08/01/2124073.html
【python中的性能优化】
使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。deque(double endian queue)是为了高效实现插入和删除操作的双向列表,适合用于队列和栈。
【python中的一些语法相关难点】
一、浅拷贝和深拷贝
?????
二、函数默认参数的改变(不能使用可变对象)
>>>def add_end(L=[]): L.append('END') return L >>> add_end() ['END', 'END'] >>> add_end() ['END', 'END', 'END']
很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了'END'后的list。
原因解释如下:
Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。
所以,定义默认参数要牢记一点:默认参数必须指向不变对象!
类中 有实例方法(普通方法)、类方法(@classmethod)、静态方法(@staticmethod)区别:
http://www.zhihu.com/question/20021164
Python 代码调试技巧
浙公网安备 33010602011771号