代码改变世界

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同时只想同一内存区,复制复杂类型变量可以使用切片。

 

python 运算符 和 优先级

 

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的好处,它允许你指定记录信息的级别,有debuginfowarningerror等几个级别,当我们指定level=INFO时,logging.debug就不起作用了。同理,指定level=WARNING后,debuginfo就不起作用了。这样一来,你可以放心地输出不同级别的信息,也不用删除,最后统一控制输出哪个级别的信息。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提供两个模块来实现序列化:cPicklepickle。这两个模块功能是一样的,区别在于cPickle是C语言写的,速度快,pickle是纯Python写的,速度慢,跟cStringIOStringIO一个道理。用的时候,先尝试导入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>

 

【进程和线程】
多进程:
  linux/Unix 下有fork(),所以可以用os.fork()。子进程永远返回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 0123是立刻执行的,而task 4要等待前面某个task完成后才执行,这是因为Pool的默认大小在我的电脑上是4,因此,最多同时执行4个进程。这是Pool有意设计的限制,并不是操作系统的限制。如果改成:

p = Pool(5)

就可以同时跑5个进程。

由于Pool的默认大小是CPU的核数,如果你不幸拥有8核CPU,你要提交至少9个子进程才能看到上面的等待效果。

 

进程间通信

Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了QueuePipes等多种方式来交换数据。

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 代码调试技巧