用心纪录,用心发现。

发布新日志

  • Python中字典(dict)和列表(list)的排序方法实例

    2014-09-03 17:53:49

    一、对列表(list)进行排序

    推荐的排序方式是使用内建的sort()方法,速度最快而且属于稳定排序

    复制代码代码如下:

    >>> a = [1,9,3,7,2,0,5]
    >>> a.sort()
    >>> print a
    [0, 1, 2, 3, 5, 7, 9]
    >>> a.sort(reverse=True)
    >>> print a
    [9, 7, 5, 3, 2, 1, 0]
    >>> b = ['e','a','be','ad','dab','dbc']
    >>> b.sort()
    >>> print b
    ['a', 'ad', 'be', 'dab', 'dbc', 'e']

    对列表的排序是遵循DSU(decorate-sort-undecorate)模式的,序列是安装条目的顺序进行比较的,对刚刚例子中的字符串来说,就是按照从左到右的顺序,逐个字符进行比较,一旦得出结果就停止比较。

    二、对字典(dict)进行排序

    其实字典(dict)是一个无序序列,谈不上排序,我们只能按照字典的键/值进行排序,然后让对应值/键也处于同样的顺序
    任何对字典的排序问题,都要最终归结为对字典(dict)的键(key)或者值(value)组成的列表(list)的排序

    1、按字典(dict)的键进行排序[1]

    复制代码代码如下:

    def sortedDictValues(adict,reverse=False):
     keys = adict.keys()
     keys.sort(reverse=reverse)
     return [adict[key] for key in keys]

    如果需要同时返回键和值的话,之用将最后的return语句改为:
    复制代码代码如下:
    return [(key,adict[key]]) for key in keys]

    还有一种书写简单的方法,就是使用内置的sorted()方法进行排序:
    复制代码代码如下:

    >>> d = {'c':1,'e':'5','b':7}
    >>> sorted(d.items())
    [('b', 7), ('c', 1), ('e', '5')]

    不过性能会有些许的下降,如果很苛求性能,还是使用原生对list.sort()方法比较好

    2、按字典(dict)的值进行排序[2]

    复制代码代码如下:

    def sorted_dict(container, keys, reverse):
     """返回 keys 的列表,根据container中对应的值排序"""
     aux = [ (container[k], k) for k in keys]
     aux.sort()
     if reverse: aux.reverse()
     return [k for v, k in aux]

    同样可以用sorted()方法实现同样的功能:
    复制代码代码如下:
    sorted(d.items(), key=lambda d:d[1], reverse=True)

    三、结语

    通过以上代码的分析,大致总结处以下几条原则:
    * 对字典的排序,最终都要归结为对字典的键或者值组成的列表的排序
    * 对列表的排序,优先使用内置的list.sort()方法

  • Python的lambda匿名函数

    2014-08-28 15:55:05

    lambda函数也叫匿名函数,即,函数没有具体的名称。先来看一个最简单例子:

    def f(x):
    return x**2
    print f(4)

    Python中使用lambda的话,写成这样

    g = lambda x : x**2
    print g(4)

     

    lambda表达式在很多编程语言都有对应的实现。比如C#:

    var g = x => x**2
    Console.WriteLine(g(4))

    那么,lambda表达式有什么用处呢?很多人提出了质疑,lambda和普通的函数相比,就是省去了函数名称而已,同时这样的匿名函数,又不能共享在别的地方调用。其实说的没错,lambda在Python这种动态的语言中确实没有起到什么惊天动地的作用,因为有很多别的方法能够代替lambda。同时,使用lambda的写法有时显得并没有那么pythonic。甚至有人提出之后的Python版本要取消lambda。

     

    回过头来想想,Python中的lambda真的没有用武之地吗?其实不是的,至少我能想到的点,主要有:

    1. 使用Python写一些执行脚本时,使用lambda可以省去定义函数的过程,让代码更加精简。

    2. 对于一些抽象的,不会别的地方再复用的函数,有时候给函数起个名字也是个难题,使用lambda不需要考虑命名的问题。

    3. 使用lambda在某些时候让代码更容易理解。

    lambda基础

    lambda语句中,冒号前是参数,可以有多个,用逗号隔开,冒号右边的返回值。lambda语句构建的其实是一个函数对象,见证一下:

    g = lambda x : x**2
    print g
    <function <lambda> at 0x00AFAAF0>

    C#3.0开始,也有了lambda表达式,省去了使用delegate的麻烦写法。C#中的lambda表达式关键字是=>,看下面的一个例子:

    var array = new int[] {2, 3, 5, 7, 9};
    var result = array.Where(n => n > 3); // [5, 6, 9]

     

    C#使用了扩展方法,才使得数组对象拥有了像Where,Sum之类方便的方法。Python中,也有几个定义好的全局函数方便使用的,他们就是filter, map, reduce。

    >>> foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
    >>>
    >>> print filter(lambda x: x % 3 == 0, foo)
    [18, 9, 24, 12, 27]
    >>>
    >>> print map(lambda x: x * 2 + 10, foo)
    [14, 46, 28, 54, 44, 58, 26, 34, 64]
    >>>
    >>> print reduce(lambda x, y: x + y, foo)
    139

     

     

    非lambda不可?

    上面例子中的map的作用,和C#的Where扩展方法一样,非常简单方便。但是,Python是否非要使用lambda才能做到这样的简洁程度呢?在对象遍历处理方面,其实Python的for..in..if语法已经很强大,并且在易读上胜过了lambda。比如上面map的例子,可以写成:

    print [x * 2 + 10 for x in foo]

    非常的简洁,易懂。filter的例子可以写成:

    print [x for x in foo if x % 3 == 0]

    同样也是比lambda的方式更容易理解。

    所以,什么时候使用lambda,什么时候不用,需要具体情况具体分析,只要表达的意图清晰就好。一般情况下,如果for..in..if能做的,我都不会选择lambda。

    lambda broken?

    在数学教学中,经常会使用到lambda,比如有一位老兄就遇到这样一个问题。他想创建一个函数数组fs=[f0,...,f9] where fi(n)=i+n. 于是乎,就定义了这么一个lambda函数:

    fs = [(lambda n: i + n) for i in range(10)]

    但是,奇怪的是,

    >>> fs[3](4)
    13
    >>> fs[4](4)
    13
    >>> fs[5](4)
    13

    结果并没有达到这位老兄的预期,预期的结果应该是:

    >>> fs[3](4)
    7
    >>> fs[4](4)
    8
    >>> fs[5](4)
    9

    问题其实出在变量i上。上面的代码换个简单的不使用lambda的缩减版本:

    i = 1
    def fs(n):
    return n + i
    print fs(1) # 2
    i = 2
    print fs(1) # 3

    可见,上面没有达到预期的原因是lambda中的i使用的是匿名函数外的全局变量。修改一下:

    fs = [(lambda n, i=i : i + n) for i in range(10)]
    >>> fs[3](4)
    7
    >>> fs[4](4)
    8
    >>> fs[5](4)
    9

  • python with关键字用法

    2014-08-28 15:34:54

    with从Python 2.5就有,需要from __future__ import with_statement。
    python 2.6开始,成为默认关键字。
    在What's new in python2.6/3.0中,明确提到:
    The 'withstatement is a control-flow structure whose basic structure is:
    with expression [as variable]: with-block
    也就是说with是一个控制流语句,跟if/for/while/try之类的是一类的,with可以用来简化try finally代码,看起来可以比try finally更清晰。
    这里新引入了一个"上下文管理协议"context management protocol,实现方法是为一个类定义__enter__和__exit__两个函数。
    with expresion as variable的执行过程是,首先执行__enter__函数,它的返回值会赋给as后面的variable,想让它返回什么就返回什么,只要你知道怎么处理就可以了,如果不写as variable,返回值会被忽略。
    然后,开始执行with-block中的语句,不论成功失败(比如发生异常、错误,设置sys.exit()),在with-block执行完成后,会执行__exit__函数。
    这样的过程其实等价于:
    try:
    执行 __enter__的内容
    执行 with_block.
    finally:
    执行 __exit__内容
    只不过,现在把一部分代码封装成了__enter__函数,清理代码封装成__exit__函数。
    我们可以自己实现一个例子:
    import sys
    class test:
    def __enter__(self):
           print("enter")
           return 1
    def __exit__(self,*args):
           print("exit")
           return True
    with test() as t:
    print("t is not the result of test(), it is __enter__ returned")
    print("t is 1, yes, it is {0}".format(t))
    raise NameError("Hi there")
    sys.exit()
    print("Never here")
    注意:
    1,t不是test()的值,test()返回的是"context manager object",是给with用的。t获得的是__enter__函数的返回值,这是with拿到test()的对象执行之后的结果。t的值是1.
    2,__exit__函数的返回值用来指示with-block部分发生的异常是否要re-raise,如果返回False,则会re-raise with-block的异常,如果返回True,则就像什么都没发生。
    符合这种特征的实现就是符合“上下文管理协议”了,就可以跟with联合使用了。
    as关键字的另一个用法是except XXX as e,而不是以前的except XXX,e的方式了。
    此外,还可以使用contextlib模块中的contextmanager,方法是:
    @contextmanager
    ...
    yield something
    ...
    的方式,具体需要看看文档和手册了。
    yield的用法还是很神奇的,一句两句搞不清楚,如果您已经弄懂,看看文档就明白了,如果不懂yield,根据自己的需要去弄懂或者干脆不理他也可以,反正用到的时候,您一定回去搞懂的:-
    其实with很像一个wrapper或者盒子,把with-block部分的代码包装起来,加一个头,加一个尾,头是__enter__,尾是__exit__,无论如何,头尾都是始终要执行的。


    有一篇详细的介绍在:http://effbot.org/zone/python-with-statement.htm

     

    我简单翻译一下其中的要点:

    如果有一个类包含  __enter__ 方法和 __exit__ 方法,像这样:
    class  controlled_execution:
           def__enter__(self):
                  set things up
                  return thing
            def__exit__(self, type, value, traceback):
                  tear things down
    那么它就可以和with一起使用,像这样:

    with controlled_execution() as thing:
    some code
        当with语句被执行的时候,python对表达式进行求值,对求值的结果(叫做“内容守护者”)调用__enter__方法,并把__enter__
    方法的返回值赋给as后面的变量。然后python会执行接下来的代码段,并且无论这段代码干了什么,都会执行“内容守护者”的__exit__
    方法。

           作为额外的红利,__exit__方法还能够在有exception的时候看到exception,并且压制它或者对它做出必要的反应。要压制exception,只需要返回一个true。比如,下面的__exit__方法吞掉了任何的TypeError,但是让所有其他的exceptions通过:

    def__exit__(self, type, value, traceback):
    return isinstance(value, TypeError)

    在Python2.5中,file object拥有__enter__和__exit__方法,前者仅仅是返回object自己,而后者则关闭这个文件:
    >>> f = open("x.txt")
    >>> f
    <open file 'x.txt', mode 'r' at 0x00AE82F0>
    >>> f.__enter__()
    <open file 'x.txt', mode 'r' at 0x00AE82F0>
    >>> f.read(1)
    'X'
    >>> f.__exit__(None, None, None)
    >>> f.read(1)
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    ValueError: I/O operation on closed file
    这样要打开一个文件,处理它的内容,并且保证关闭它,你就可以简简单单地这样做:
    with open("x.txt") as f:
    data = f.read()
    do something with data

    我的补充:
    数据库的连接好像也可以和with一起使用,我在一本书上看到以下内容:
    conn = sqlite.connect("somedb")
    with conn:
        conn.execute("insert into sometable values (?,?)",("foo","bar"))
    在这个例子中,commit()是在所有with数据块中的语句执行完毕并且没有错误之后自动执行的,如果出现任何的异常,将执行rollback()
    操作,再次提示异常
  • Python基础学习篇——Global全局变量的使用

    2014-08-28 15:24:38

    为了测试Python中全局变量的使用,我们试图撰写以下几个例子进行说明:
    #第一例子,是用来验证一个最基础的全局变量与局部变量的区别,内容如下:
    #-*- coding: cp936 -*-
    global a 
    def a():
     a=2
     a+=1
     print a
     #注意这里没有使用return a 
    def do():
     a()
     #并把a方法的value(a)进行运算
     a+=1
    #我们写一个main函数来调用这个do的过程
    if __name__ = "__main__":
     do()
     print a
    #我们在Python(idle)中,运行程序F5
    #程序出现调试错误:local variable 'a' referenced before assignment
    #由此,我们可以看出局部变量在方法中是不能传递的,为了能够使用几个方法返回的
    #值,并在do()这个函数中进行运算,我们引入了全局变量global a,现在我们对以上
    #的程序做出进行以下调整
    #================================ RESTART ================================
    global a 
    def a():
    #这里我们引用设置的全局变量a,写在函数中
     global a
     a = 2
     a += 1
     #预期的a = 3
     print a
    def do():
    #这里由于我们需要对定义的全局变量进行重新计算,我们这次引用a
    global a
     a()
     a+=1
    if __name__ = "__main__":
     do()
    #如果我们需要在最后的main函数中,输出由do()函数最终计算的变量a,则我们必须在这里在此引用这个变量a
     global a 
     #预期的值4
     print a 
    #现在我们再次运行程序这时,我们看到的数值结果与预期结果一致,为3,4
    #================================ RESTART ================================
    #总结:全局变量的使用是为了使我们在一个类或一个函数中使用由函数返回的变量,
    #并进行复杂的计算过程而使用。而对于一个函数的局部变量,则只在一个函数内部是
    #可使用的,而如果需要跨越不同的函数或者类则需要在基础函数中返回一个该值,在
    #下一个函数中运行其方法才能获取该值进行计算,如果程序不复杂在一个类中可以解决
    #全局变量会为我们节省不少的时间,以及内存空间。
  • python中'\'的用法

    2014-08-06 15:35:15

    1.换行(与Bash效果相同)

    ' this is the frist sentence.\

    this is the second sentence.'

    其输出结果为 this is the frist sentence.this is the second sentence.

    又print/

        (s)

    等同于print(s)

     

    2.用于输出 ' \ " 等特殊符号

    'What\'s your name?'  =="what's your name?"

    \\ == 输出"\"

     

    3.用于特殊字母前表示不同的意义

    如 \n  代表换行

    print("this is the frist line \n this is the second line")

    结果

    this is the frist line

    this is the second line

  • Python:list and dictionary

    2014-08-06 14:43:36


    创建列表
    sample_list = ['a',1,('a','b')]

    Python 列表操作
    sample_list = ['a','b',0,1,3]

    得到列表中的某一个值
    value_start = sample_list[0]
    end_value = sample_list[-1]

    删除列表的第一个值
    del sample_list[0]

    在列表中插入一个值
    sample_list[0:0] = ['sample value']

    得到列表的长度
    list_length = len(sample_list)

    列表遍历
    for element in sample_list:
    print(element)

    Python 列表高级操作/技巧

    产生一个数值递增列表
    num_inc_list = range(30)
    #will return a list [0,1,2,...,29]

    用某个固定值初始化列表
    initial_value = 0
    list_length = 5
    sample_list = [ initial_value for i in range(10)]
    sample_list = [initial_value]*list_length
    # sample_list ==[0,0,0,0,0]


    附:python内置类型
    1、list:列表(即动态数组,C++标准库的vector,但可含不同类型的元素于一个list中)
    a = ["I","you","he","she"] #元素可为任何类型。

    下标:按下标读写,就当作数组处理
    以0开始,有负下标的使用
    0第一个元素,-1最后一个元素,
    -len第一个元 素,len-1最后一个元素
    取list的元素数量 
    len(list) #list的长度。实际该方法是调用了此对象的__len__(self)方法。

    创建连续的list
    L = range(1,5) #即 L=[1,2,3,4],不含最后一个元素
    L = range(1, 10, 2) #即 L=[1, 3, 5, 7, 9]

    list的方法
    L.append(var) #追加元素
    L.insert(index,var)
    L.pop(var) #返回最后一个元素,并从list中删除之
    L.remove(var) #删除第一次出现的该元素
    L.count(var) #该元素在列表中出现的个数
    L.index(var) #该元素的位置,无则抛异常 
    L.extend(list) #追加list,即合并list到L上
    L.sort() #排序
    L.reverse() #倒序
    list操作符:,+,*,关键字del
    a[1:] #片段操作符,用于子list的提取
    [1,2]+[3,4] #为[1,2,3,4]。同extend()
    [2]*4 #为[2,2,2,2]
    del L[1] #删除指定下标的元素
    del L[1:3] #删除指定下标范围的元素
    list的复制
    L1 = L #L1为L的别名,用C来说就是指针地址相同,对L1操作即对L操作。函数参数就是这样传递的
    L1 = L[:] #L1为L的克隆,即另一个拷贝。

    list comprehension
    [ <expr1> for k in L if <expr2> ]

    2、dictionary: 字典(即C++标准库的map)
    dict = {'ob1':'computer', 'ob2':'mouse', 'ob3':'printer'}
    每一个元素是pair,包含key、value两部分。key是Integer或string类型,value是任意类型。
    键是唯一的,字典只认最后一个赋的键值。

    dictionary的方法
    D.get(key, 0) #同dict[key],多了个没有则返回缺省值,0。[]没有则抛异常
    D.has_key(key) #有该键返回TRUE,否则FALSE
    D.keys() #返回字典键的列表
    D.values()
    D.items()

    D.update(dict2) #增加合并字典
    D.popitem() #得到一个pair,并从字典中删除它。已空则抛异常
    D.clear() #清空字典,同del dict
    D.copy() #拷贝字典
    D.cmp(dict1,dict2) #比较字典,(优先级为元素个数、键大小、键值大小)
    #第一个大返回1,小返回-1,一样返回0

    dictionary的复制
    dict1 = dict #别名
    dict2=dict.copy() #克隆,即另一个拷贝。

    3、tuple:元组(即常量数组)
    tuple = ('a', 'b', 'c', 'd', 'e')
    可以用list的[],:操作符提取元素。就是不能直接修改元素。

    4、string: 字符串(即不能修改的字符list)
    str = "Hello My friend"
    字符串是一个整 体。如果你想直接修改字符串的某一部分,是不可能的。但我们能够读出字符串的某一部分。
    子字符串的提取
    str[:6]
    字符串包含 判断操作符:in,not in
    "He" in str
    "she" not in str

    string模块,还提供了很多方法,如
    S.find(substring, [start [,end]]) #可指范围查找子串,返回索引值,否则返回-1
    S.rfind(substring,[start [,end]]) #反向查找
    S.index(substring,[start [,end]]) #同find,只是找不到产生ValueError异常
    S.rindex(substring,[start [,end]])#同上反向查找
    S.count(substring,[start [,end]]) #返回找到子串的个数

    S.lowercase()
    S.capitalize() #首字母大写
    S.lower() #转小写
    S.upper() #转大写
    S.swapcase() #大小写互换

    S.split(str, ' ') #将string转list,以空格切分
    S.join(list, ' ') #将list转string,以空格连接

    处理字符串的内置函数
    len(str) #串长度
    cmp("my friend", str) #字符串比较。第一个大,返回1
    max('abcxyz') #寻找字符串中最大的字符
    min('abcxyz') #寻找字符串中最小的字符

    string的转换

    oat(str) #变成浮点数,float("1e-1") 结果为0.1
    int(str) #变成整型, int("12") 结果为12
    int(str,base) #变成base进制整型数,int("11",2) 结果为2
    long(str) #变成长整型,
    long(str,base) #变成base进制长整型,

    字符串的格式化(注意其转义字符,大多如C语言的,略)
    str_format % (参数列表) #参数列表是以tuple的形式定义的,即不可运行中改变
    >>>print ""%s's height is %dcm" % ("My brother", 180)
    #结果显示为 My brother's height is 180cm

    。。。。。。。。。。。。。。。。。。

    list 和 tuple 的相互转化

    tuple(ls) 
    list(ls)

  • Python: file open

    2014-08-04 14:50:56

    from sys import argv
    script, filename = argv
    file = open(filename,'r+')

    open/文件操作
    f=open('/tmp/hello','w')

    #open(路径+文件名,读写模式)

    #读写模式:r只读,r+读写,w新建(会覆盖原有文件),a追加,b二进制文件.常用模式

    如:'rb','wb','r+b'等等

    读写模式的类型有:

    rU 或 Ua 以读方式打开, 同时提供通用换行符支持 (PEP 278)
    w     以写方式打开,
    a     以追加模式打开 (从 EOF 开始, 必要时创建新文件)
    r+     以读写模式打开
    w+     以读写模式打开 (参见 w )
    a+     以读写模式打开 (参见 a )
    rb     以二进制读模式打开
    wb     以二进制写模式打开 (参见 w )
    ab     以二进制追加模式打开 (参见 a )
    rb+    以二进制读写模式打开 (参见 r+ )
    wb+    以二进制读写模式打开 (参见 w+ )
    ab+    以二进制读写模式打开 (参见 a+ )


    注意:

    1、使用'W',文件若存在,首先要清空,然后(重新)创建,

    2、使用'a'模式 ,把所有要写入文件的数据都追加到文件的末尾,即使你使用了seek()指向文件的其他地方,如果文件不存在,将自动被创建。



    f.read([size]) size未指定则返回整个文件,如果文件大小>2倍内存则有问题.f.read()读到文件尾时返回""(空字串)

    file.readline() 返回一行

    file.readline([size]) 返回包含size行的列表,size 未指定则返回全部行

    for line in f: print line #通过迭代器访问

    f.write("hello\n") #如果要写入字符串以外的数据,先将他转换为字符串.

    f.tell() 返回一个整数,表示当前文件指针的位置(就是到文件头的比特数).

    f.seek(偏移量,[起始位置])

    用来移动文件指针

    偏移量:单位:比特,可正可负

    起始位置:0-文件头,默认值;1-当前位置;2-文件尾

    f.close() 关闭文件

    Code:


    #!/usr/bin/env python
    # Filename: using_file.py

    poem='''\Programming is funWhen the work is doneif you wanna make your work also fun: use Python!'''
    f=file('poem.txt','w') # open for 'w'riting
    f.write(poem) # write text to file
    f.close() # close the file
    f=file('poem.txt')

    # if no mode is specified, 'r'ead mode is assumed by default
    while True: 
    line=f.readline() 
    if len(line)==0: # Zero length indicates EOF 
    break 
    print line, 
    # Notice comma to avoid automatic newline added by Python
    f.close() 
    # close the file
  • Python: file.seek

    2014-08-04 14:24:45

    file.seek(0)是重新定位在文件的第0位及开始位置
    好处是不用再打开文件,既可以定位到0的位置或者别的位置,可以对文件进行操作
    如果有一个文件test.txt
    hello
    test!

    file = open("test.txt","rw")
    file.seek(300)
    for i in file:
    print i #不会有值返回,因为是第300个空格

    file.seek(0)
    for i in file
    	print i #有值返回,从0开始
    file.seek(300)
    file.write("test22!")
    for i in file
    	print i
Open Toolbar