却是无题

想说什么,终究是不知如何开口,便随便流水账吧。

这转眼的,加班又加了好久了。说累也就那样吧,说不累也可,总之它就这么消耗着你的时间,消磨着。倒是如今的我心态变了,木有那么120%的干劲了,就那么不咸不淡的完成着,一边自己捣鼓些什么。嗯,在做一个小小的聊天程序,也没啥特别的用意,倒是对socket啊,thread啊,尤其是OptionParser啥的理解更深了,蛮好玩的。最近也在打算整理下,自己做的qml相关的控件效果啥的,算是保留下来,省的以后要用类似的,没啥可抄袭的。

然后,大约小半月前,终于如愿的入手了mac pro了,嗯,真的超有编程的感觉,简直是满满。自从拿回家后,天天孜孜不倦的在git上提交各种各样的,嘿嘿,超级上瘾了。好吧,自从1年前上班开始用linux后,没对比不知道,我挑剔多了,哎,如果不是微软系列的,win真的不适合编程啊,cmd啥的难用死了。不过由于,手头还有一台win,再加上上班用的ubuntu,我能说,我现在各种快捷键已经记晕了。

晚上刚刚把武娘娘传奇看完,嗯,好失望啊,真心说不好看,原以为能看到宫斗,结果只看到一次次武娘娘泪流满面。倒是其中的服饰什么的越发的华贵起来,我能吐槽说武娘娘的装扮、尤其是头饰越来越有日风么。没有宫斗就算了,我一直在等待武娘娘称帝,好吧,一直到最后一集,终于、终于称帝了。嗯,那一瞬间倒是甚是霸气。然后,约莫是15分钟后,瞬间过了15年,武娘娘退位了,再然后剧终了,这……何堪。

突然想起来很久以前喜欢的一首诗,算是摘抄在这儿吧。

生活 娜夜

我珍爱过你
像小时候珍爱一颗黑糖球
舔一口马上用糖纸包上
再舔一口
舔的越来越慢
包的越来越快
现在只剩下我和糖纸了
我必须忍住:忧伤

翻了翻以前的日志,有些那时候不甚明了的事儿,也算是终究身在其中,于是便懂了。该走的终究会走,本来想先一步抽身而去,目送的人总归是难过的,哎,加油罢……


额,js深复制

好吧,最近做页面的时候被js深深的坑到了。

当我轻松的用var a = b的时候,由于b是一个对象,并且在这之后我对b进行了修改,然后自然而然的悲剧了,a也一起改变了。虽然,我很快的想到了这是由于我用了浅复制造成了。于是,我开始百度深复制的方法。
b是一个array所以我自然而然的用了var a = b.slice(0)。然后我满怀信心的run了我的程序,然后又一次悲剧了QAQ

我意识到,由于我b中的每个元素,仍有可能是一个对象,造成其实它里面每个对象元素还是浅复制。(๑•́ ₃ •̀)

嗯,so,我不得不用递归来复制元素了,然后我懒得写了,就抄袭了一个[代码抄袭自],js你赢了(= =)

function deepCopy(srcObject) {
    var newObject
    if (srcObject instanceof Array) {
        newObject = []
        for (var i = 0; i < srcObject.length; i++) {
            newObject[i] = deepCopy(srcObject[i])
        }
        return newObject
    }else if (srcObject instanceof Object) {
        newObject = {}
        for (var j in srcObject) {
            newObject[j] = deepCopy(srcObject[j])
        }
        return newObject
    }else {
        return srcObject
    }
}

这是一个对比的例子~(我是在qml中用的js)

function test() {
    var a = ['1',{"aaa":"qqq"},'3']
    var b = deepCopy(a)
    var c = a.slice(0)
    a[1]["12"]="444"
    console.log(JSON.stringify(a[1]))
    console.log(JSON.stringify(b[1]))
    console.log(JSON.stringify(c[1]))
}

输出

qml: {"12":"444","aaa":"qqq"}
qml: {"aaa":"qqq"}
qml: {"12":"444","aaa":"qqq"}

谁懂呢。

从上周开始的几天,我开始疯狂的找工作,试图想逃离现在疯狂加班、无法忍受的代码风格里。好似在那一刻,所有的不满都激怨爆发。我面试了几家,也收到了offer,但是在落定之后却又陷入纠结。原因无他,我真心想去的没给我面试机会,但是给我offer的所做的活却不甚感兴趣。

于是,我拒绝了。与其为了换工作而换工作,不如留在我还相对感兴趣的这里。

闺蜜痛斥了我,我问她,在公司与兴趣之间你选择哪个,她毫不犹豫的说公司,好吧,你看这就是我们之间的区别。

不说这个了,最近在找班学画画,嗯,不过看到的大多是青少年那种美术考试那种班,有没有比较好的素描水彩成人兴趣班呢。脑中总能浮现很多画面,尤其是在听音乐的时候,真想将他们画下来呢。

哦,我把评论系统换disqus了,开审核麻烦,不开老有人发广告,烦得紧,换个第三方吧,这种烦心事还是交给别人烦去吧~♪(^∀^●)ノシ 就酱,干活去了.


01.17.2015 换回原生评论:原因是评论不好订阅=。= 之前在disqus上的评论等我下班回来后搬运上来。


qml实现QQ列表界面侧划效果

今天,出于需求,需要在列表中用qt实现一个类似qml实现QQ列表界面侧划效果。经过我不懈打酱油+听音乐+发呆+刷新闻后终于得以实现,记录下~

对于这个神奇的控件,就称为DragBar,我所定义它的行为为:

DragBar

  1. 它有[打开]和[关闭]两种状态。
  2. 在[关闭]状态时,点击或者是拖动其划过超过某一个阀值距离后,进入[打开]状态。
  3. 在[打开]状态时,点击或者是拖动任意距离,都会进入[关闭]状态。
  4. 在[打开]状态时,会出现两个按钮,一个为[修改]一个为[删除]。
  5. 当用DragBar组成列表后,同一时间只有一个DragBar为[打开]状态。

因为是有拖动组件然后出现按钮这样的行为,所以我在实现时,利用MouseArea的drag属性,将两层组件覆盖在一起,于是如果你拖动上层组件,就自然而然会出现下层组件的外形。

drag provides a convenient way to make an item draggable.

  • drag.target specifies the id of the item to drag.
  • drag.active specifies if the target item is currently being dragged.
  • drag.axis specifies whether dragging can be done horizontally (Drag.XAxis), vertically (Drag.YAxis), or both (Drag.XAndYAxis)
  • drag.minimum and drag.maximum limit how far the target can be dragged along the corresponding axes.

这是Qt文档中对于drag属性的描述,所以可以很轻松的做如下设计。

DragBar结构

由于在对DragBar的定义上,又要响应点击又要响应拖拽,所以我把事件放在了MouseArea的released事件上,并通过判断触发该事件时的x坐标来区分这几种行为。

[关闭状态]

  • x<=阀值
    上层关闭
  • x>阀值
    上层打开
  • 如果是点击,即press和release时x坐标未改变
    上层打开

[打开状态]

  • 点击关闭

在定义第5条中'当用DragBar组成列表后,同一时间只有一个DragBar为[打开]状态',所以我将DragBar的打开关闭状态与activefocus属性关联,当activefocus为false时,即当焦点不在该控件上时,DragBar关闭。

好像差不多就这样,具体代码如下:

//DragBar.qml
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Controls.Private 1.0

Control {
    id:root

    implicitWidth: parent.width
    implicitHeight: 80

    style: Qt.createComponent("DragBarStyle.qml", root)

    property real boundary: 40 //滑动开关的边界值
    property alias isOpen: dragRec.isOpen //是否打开标志 true打开 false关闭

    onActiveFocusChanged: {
        if (!activeFocus) {
            isOpen = false
        }
    }

    Loader {
        id:backboard
        property Component __bkButtons //背景图标
        height: parent.height
        anchors.right: parent.right
        sourceComponent: __style && __style.buttons ? __style.buttons : __bkButtons
    }

    Loader {
        id: dragRec
        property Component __upPanel //上层面板
        property bool isOpen: false //是否打开标志 true打开 false关闭
        height: parent.height
        width: parent.width
        Drag.active: dragArea.drag.active
        sourceComponent: __style && __style.upper ? __style.upper : __upPanel

        onIsOpenChanged: {
            if (isOpen) {
                dropOpen.start()
            }else {
                dropClose.start()
            }
        }

        PropertyAnimation on x {
            id:dropOpen
            running:false
            to:dragArea.drag.minimumX
            easing.type: Easing.InOutQuad
        }

        PropertyAnimation on x {
            id:dropClose
            running:false
            to:dragArea.drag.maximumX
            easing.type: Easing.InOutQuad
        }

        MouseArea {
            id: dragArea
            anchors.fill: parent
            drag.target: parent
            drag.axis: Drag.XAxis
            drag.maximumX: 0
            drag.minimumX: -backboard.width
            property real oldx

            onPressed: {
                oldx = mouse.x
            }

            onReleased: {
                root.forceActiveFocus()
                console.log("dragRec.x:"+dragRec.x)
                if (!dragRec.isOpen) {
                    if (dragRec.x !== 0 && dragRec.x>-root.boundary) {
                        dropClose.start()
                    }else if (dragRec.x !== 0 || oldx===mouse.x){
                        dragRec.isOpen = true
                    }
                }else {
                    dragRec.isOpen = false
                }
            }
        }
    }

    function modifyfun(){
        console.log("修改操作")
    }

    function deletefun() {
        console.log("删除操作")
    }
}

这是对应的style样式的qml:

//DragBarStyle.qml
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Controls.Private 1.0

Style {
    id:style

    //背景上的按钮们
    property Component buttons: Row {
        height: parent.height

        Rectangle {
            height: parent.height
            width: 80
            color: "#f9cdac"

            Text{
                anchors.centerIn: parent
                text:"修改"
                color: "#ffffff"
            }

            MouseArea {
                anchors.fill: parent
                onClicked: {
                    control.modifyfun()
                }
            }
        }

        Rectangle {
            id:aaaa
            height: parent.height
            width: 80
            color: "#fc9d9a"

            Text{
                anchors.centerIn: parent
                text:"删除"
                color: "#ffffff"
            }

            MouseArea {
                anchors.fill: parent
                onClicked: {
                    control.deletefun()
                }
            }
        }
    }

    //上层面板样式
    property Component upper: Rectangle {
        anchors.fill: parent
        color: "#ffffff"
        Text {
            anchors.centerIn: parent
            text:"点一下或者拖拽就会打开"
            color: "#666666"
        }
    }

    //布局面板 可以设置底板背景颜色 不过一般看不见吧
    property Component panel: Item {
        anchors.fill: parent
    }
}

运行效果图:

~ 这个是全关闭的状态
关闭状态

~ 打开上面的DragBar
打开1

~ 打开下面的DragBar,上面的自动关闭
打开2


python题目收集

  • Python是如何进行内存管理的?

    小块空间内存池和大对象缓冲池

    参考:python内存管理

  • 什么是lambda函数?它有什么好处?

    Python支持一种有趣的语法,它允许你快速定义单行的最小函数。这些叫做 lambda 的函数是从Lisp中借用来的,可以被用在任何需要函数的地方。

     >>> def f(x):
     ...     return x*2
     ...     
     >>> f(3)
     6
    
     >>> g = lambda x: x*2
     >>> g(3)
     6
    
     >>> (lambda x: x*2)(3)
     6
    

    这是一个通常的函数声明,尽管以前你可能没有看到过定义在交互式窗口中的函数。这个 ... 说明它是一个多行的交互语句。只要在第一行的后面敲入回车,Python IDE会让你接着输入命令。

    这是一个 lambda 函数,它完成同上面普通函数相同的事情。注意这里的简短的语法;没有小括号, return 是默认的,并且函数没有名字,只有将它赋值给变量的变量名。

    你甚至可以不将 lambda 函数赋值给一个变量而使用它。这不是举世无双的东西,它只是展示了 lambda 函数只是一个内联函数。

    总之, lambda 函数是一个可以接收任意多个参数(包括可选参数)并且返回单个表达式值的函数。 lambda 函数不能包含命令,它们所包含的表达式不能超过一个。不要试图向 lambda 函数中塞入太多的东西;如果你需要更复杂的东西,应该定义一个普通函数,然后想让它多长就多长。

    参考:lambda

  • 如何反序的迭代一个序列?how do I iterate over a sequence in reverse order

    如果是一个list, 最快的解决方案是:

     list.reverse()
     try:
         for x in list:
             “do something with x”
     finally:
         list.reverse()
    

    如果不是list, 最通用但是稍慢的解决方案是:

     for x in sequence[::-1]:
         <do something with x>
    

    参考:反序遍历

  • Python是如何进行类型转换的?

     函数                      描述
     int(x [,base ])         将x转换为一个整数
     long(x [,base ])        将x转换为一个长整数
     float(x )               将x转换到一个浮点数
     complex(real [,imag ])  创建一个复数
     str(x )                 将对象 x 转换为字符串
     repr(x )                将对象 x 转换为表达式字符串
     eval(str )              用来计算在字符串中的有效Python表达式,并返回一个对象
     tuple(s )               将序列 s 转换为一个元组
     list(s )                将序列 s 转换为一个列表
     chr(x )                 将一个整数转换为一个字符
     unichr(x )              将一个整数转换为Unicode字符
     ord(x )                 将一个字符转换为它的整数值
     hex(x )                 将一个整数转换为一个十六进制字符串
     oct(x )                 将一个整数转换为一个八进制字符串
    

    参考:python类型转换

  • Python里面如何实现tuple和list的转换?

    函数tuple(seq)可以把所有可迭代的(iterable)序列转换成一个tuple, 元素不变,排序也不变。
    例如,tuple([1,2,3])返回(1,2,3), tuple(‘abc’)返回(‘a’.'b’,'c’).如果参数已经是一个tuple的话,函数不做任何拷贝而直接返回原来的对象,所以在不确定对象是不是tuple的时候来调用tuple()函数也不是很耗费的。

    函数list(seq)可以把所有的序列和可迭代的对象转换成一个list,元素不变,排序也不变。
    例如 list([1,2,3])返回(1,2,3), list(‘abc’)返回['a', 'b', 'c']。如果参数是一个list, 她会像set[:]一样做一个拷贝。

    参考:元组列表转换

  • 请写出一段Python代码实现删除一个list里面的重复元素

     aa = ["1","2","3","1"]
     list(set(aa))
    

    参考:列表去重

  • list与tuple的区别 ?dictionary与set的区别?

    思路:首先弄懂什么是list类型,什么是tuple类型,什么是dict类型和set类型

    对于list与tupel的区别,在《Python核心编程2》中讲解的很清楚,可以总体概括为,可变与不可变、他们本质相同,但是就因为可变性就延伸了很多不同点。如list类型可以进行相应更改和方法操作,但tupel就没有这个功能。

    对于dict和set,一个是Python唯一的映射类型,一个是Python集合。python中集合对象(set)是一组无序排列的可哈希的值,包含两种类型:可变集合(set)和不可变集合(frozenset),所以set不是可哈希的,frozenset是可哈希的,能当作字典的键。

    参考:python字典和集合

  • 如何理解python for else?

     for i in range(0,10):
         if i > 10:
             break;
     else:
         print "hello world";
    

    即在for 循环中,如果没有从任何一个break中退出,则会执行和for对应的else,只要从break中退出了,则else部分不执行。
    while-else/for-else语句:
    在其他语言中,除了条件语句,是不会见到else分支的,但在Python中,while和for循环中,也是可以使用else语句的。它们的工作顺序为:在循环中使用时,else语句只在循环完成后执行,也就是说,break语句也会跳过else代码块,只要循环是正常结束,而不是通过break,else语句就会执行。

    参考Python中的else语句整理

  • 介绍下你所熟悉或知道的Python库

    思路,考察对应聘者对Python了解的程度,如:

    Tkinter———— Python默认的图形界面接口。

    Python Imaging Library(PIL)————python提供强大的图形处理的能力,并提供广泛的图形文件格式支持,

    PyGame———— 用于多媒体开发和游戏软件开发的模块。

    PyQt ———— 用于python的Qt开发库。

    PyMedia ———— 用于多媒体操作的python模块。

    参考:常用的Python库

  • Python如何实现单例模式?其他23种设计模式python如何实现?

    Python有两种方式可以实现单例模式,下面两个例子使用了不同的方式实现单例模式:

    1.  class Singleton(type):
           def __init__(cls, name, bases, dict):
               super(Singleton, cls).__init__(name, bases, dict)
               cls.instance = None
      
           def __call__(cls, *args, **kw):
               if cls.instance is None:
               cls.instance = super(Singleton, cls).__call__(*args, **kw)
               return cls.instance
      
       class MyClass(object):
           __metaclass__ = Singleton
      
       print MyClass()
       print MyClass()
      
    2. 使用decorator来实现单例模式

       def singleton(cls):
           instances = {}
      
       def getinstance():
           if cls not in instances:
               instances[cls] = cls()
               return instances[cls]
           return getinstance
      
       @singleton
       class MyClass:
       …
      
  • Python里面如何拷贝一个对象?

    标准库中的copy模块提供了两个方法来实现拷贝.一个方法是copy,它返回和参数包含内容一样的对象.

     import copy
     new_list = copy.copy(existing_list)
    

    有些时候,你希望对象中的属性也被复制,可以使用deepcopy方法:

     import copy
     new_list_of_dicts = copy.deepcopy(existing_list_of_dicts)
    

    当你对一个对象赋值的时候(做为参数传递,或者做为返回值),Python和Java一样,总是传递原始对象的引用,而不是一个副本.其它一些语言当赋值的时候总是传递副本.Python从不猜测用户的需求 ,如果你想要一个副本,你必须显式的要求.
    Python的行为很简单,迅速,而且一致.然而,如果你需要一个对象拷贝而并没有显式的写出来,会出现问题的,比如:

     >>> a = [1, 2, 3]
     >>> b = a
     >>> b.append(5)
     >>> print a, b 
     [1, 2, 3, 5] [1, 2, 3, 5]
    

    在这里,变量a和b都指向同一个对象(一个列表),所以,一旦你修改了二者之一,另外一个也会受到影响.无论怎样,都会修改原来的对象。

    参考:浅复制深复制

  • 介绍一下except的用法和作用?

    Python的异常处理能力是很强大的,可向用户准确反馈出错信息。在Python中,异常也是对象,可对它进行操作。所有异常都是基类Exception的成员。所有异常都从基类Exception继承,而且都在exceptions模块中定义。Python自动将所有异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可使用异常。一旦引发而且没有捕捉SystemExit异常,程序执行就会终止。如果交互式会话遇到一个未被捕捉的SystemExit异常,会话就会终止。

    方式一:try语句:

    1使用try和except语句来捕获异常

     try:
        block
     except [exception,[data…]]:
        block
    
     try:
         block
     except [exception,[data...]]:
         block
     else:
         block
    

    该种异常处理语法的规则是:

    • 执行try下的语句,如果引发异常,则执行过程会跳到第一个except语句。

    • 如果第一个except中定义的异常与引发的异常匹配,则执行该except中的语句。

    • 如果引发的异常不匹配第一个except,则会搜索第二个except,允许编写的except数量没有限制。

    • 如果所有的except都不匹配,则异常会传递到下一个调用本代码的最高层try代码中。

    • 如果没有发生异常,则执行else块代码。

    参考:python异常

  • Python中pass语句的作用是什么?

    pass语句什么也不做,一般作为占位符或者创建占位程序,pass语句不会执行任何操作, 比如:

     while False:
         pass
    

    pass通常用来创建一个最简单的类:

     class MyEmptyClass:
         pass
    

    pass在软件设计阶段也经常用来作为TODO,提醒实现相应的实现,比如:

     def initlog(*args):
         pass #please implement this
    

    参考:python pass作用

  • 介绍一下Python下range()函数的用法?

    如果需要迭代一个数字序列的话,可以使用range()函数,range()函数可以生成等差级数。

    如例:

     for i in range(5)
         print(i)
    

    这段代码将输出0, 1, 2, 3, 4五个数字

    range(10)会产生10个值, 也可以让range()从另外一个数字开始,或者定义一个不同的增量,甚至是负数增量

    range(5, 10)从5到9的五个数字range(0, 10, 3) 增量为三, 包括0,3,6,9四个数字range(-10, -100, -30) 增量为-30, 包括-10, -40, -70可以一起使用range()和len()来迭代一个索引序列例如:

     a = ['Nina', 'Jim', 'Rainman', 'Hello']
     for i in range(len(a)): 
         print(i, a[i])
    

    参考:python range

  • 如何用Python来进行查询和替换一个文本字符串?

    可以使用sub()方法来进行查询和替换,sub方法的格式为:sub(replacement, string[, count=0])

    replacement是被替换成的文本

    string是需要被替换的文本

    count是一个可选参数,指最大被替换的数量

    例子:

     import re
     p = re.compile(‘(blue|white|red)’)
     print(p.sub(‘colour’,'blue socks and red shoes’))
     print(p.sub(‘colour’,'blue socks and red shoes’, count=1))
    

    输出:

     colour socks and colour shoes
     colour socks and red shoes
    

    subn()方法执行的效果跟sub()一样,不过它会返回一个二维数组,包括替换后的新的字符串和总共替换的数量

    例如:

     import re
     p = re.compile(‘(blue|white|red)’)
     print(p.subn(‘colour’,'blue socks and red shoes’))
     print(p.subn(‘colour’,'blue socks and red shoes’, count=1))
    

    输出

     (‘colour socks and colour shoes’, 2)
     (‘colour socks and red shoes’, 1)
    
  • Python里面search()和match()的区别?

    match()函数只检测RE是不是在string的开始位置匹配, search()会扫描整个string查找匹配, 也就是说match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回none

    例如:
    print(re.match(‘super’, ‘superstition’).span())会返回(0, 5)
    而print(re.match(‘super’, ‘insuperable’))则返回None
    search()会扫描整个字符串并返回第一个成功的匹配

    例如:
    print(re.search(‘super’, ‘superstition’).span())返回(0, 5)
    print(re.search(‘super’, ‘insuperable’).span())返回(2, 7)

  • 用Python匹配HTML tag的时候,<.*><.*?>有什么区别?

    当重复匹配一个正则表达式时候, 例如<.*>, 当程序执行匹配的时候,会返回最大的匹配值

    例如:

     import re
     s = ‘<html><head><title>Title</title>’
     print(re.match(‘<.*>’, s).group())
    

    会返回一个匹配<html><head><title>Title</title>而不是<html>

    而:

     import re
     s = ‘<html><head><title>Title</title>’
     print(re.match(‘<.*?>’, s).group())
    

    则会返回<html>

    <.*>这种匹配称作贪心匹配
    <.*?>称作非贪心匹配

  • Python里面如何生成随机数?

    random.random()用于生成一个指定范围内的随机符点数,两个参数其中一个是上限,一个是下限。如果a > b,则生成随机数

     n: a <= n <= b。如果 a <b, 则 b <= n <= a。
    
     print random.uniform(10, 20)  
     print random.uniform(20, 10)  
     #---- 
     #18.7356606526  
     #12.5798298022  
    

    random.randint()用于生成一个指定范围内的整数。其中参数a是下限,参数b是上限,

     print random.randint(12, 20) #生成的随机数n: 12 <= n <= 20 
     print random.randint(20, 20) #结果永远是20 
     #print random.randint(20, 10) #该语句是错误的。 
    

    下限必须小于上限。

    random.randrange()从指定范围内,生成按指定基数递增的集合。

    随机整数:

     >>> import random
     >>> random.randint(0,99)
     21
    

    随机选取0到100间的偶数:

     >>> import random
     >>> random.randrange(0, 101, 2)
     42
    

    随机浮点数:

     >>> import random
     >>> random.random() 
     0.85415370477785668
     >>> random.uniform(1, 10)
     5.4221167969800881
    

    随机字符:

     >>> import random
     >>> random.choice('abcdefg&#%^*f')
     'd'
    

    多个字符中选取特定数量的字符:

     >>> import random
     random.sample('abcdefghij',3) 
     ['a', 'd', 'b']
    

    多个字符中选取特定数量的字符组成新字符串:

     >>> import random
     >>> import string
     >>> string.join(random.sample(['a','b','c','d','e','f','g','h','i','j'], 3)).replace(" ","")
     'fih'
    

    随机选取字符串:

     >>> import random
     >>> random.choice ( ['apple', 'pear', 'peach', 'orange', 'lemon'] )
     'lemon'
    

    洗牌:

     >>> import random
     >>> items = [1, 2, 3, 4, 5, 6]
     >>> random.shuffle(items)
     >>> items
     [3, 2, 5, 6, 4, 1]
    
  • 如何用Python来发送邮件?

    可以使用smtplib标准库。

    以下代码可以在支持SMTP监听器的服务器上执行。

     import sys, smtplib
    
     fromaddr = raw_input("From: ")
     toaddrs = raw_input("To: ").split(",")
     print "Enter message, end with ^D:"
     msg = ""
     while 1:
         line = sys.stdin.readline()
         if not line:
             break
     msg = msg + line
    
     # 发送邮件部分
     server = smtplib.SMTP(‘localhost’)
     server.sendmail(fromaddr, toaddrs, msg)
     server.quit()
    
  • 有两个序列a,b,大小都为n,序列元素的值任意整形数,无序;
    要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小。

    1. 将两序列合并为一个序列,并排序,为序列Source
    2. 拿出最大元素Big,次大的元素Small
    3. 在余下的序列S[:-2]进行平分,得到序列max,min
    4. 将Small加到max序列,将Big加大min序列,重新计算新序列和,和大的为max,小的为min。
  • Python如何定义一个函数?

    函数的定义形式如下:

     def (arg1, arg2,… argN): 
    

    函数的名字也必须以字母开头,可以包括下划线“ ”,但不能把Python的关键字定义成函数的名字。函数内的语句数量是任意的,每个语句至少有一个空格的缩进,以表示此语句属于这个函数的。缩进结束的地方,函数自然结束。
    下面定义了一个两个数相加的函数:

     >>> def add(p1, p2): 
         print p1, “+”, p2, “=”, p1+p2 
     >>> add(1, 2) 
     1 + 2 = 3 
    

    函数的目的是把一些复杂的操作隐藏,来简化程序的结构,使其容易阅读。函数在调用前,必须先定义。也可以在一个函数内部定义函数,内部函数只有在外部函数调用时才能够被执行。程序调用函数时,转到函数内部执行函数内部的语句,函数执行完毕后,返回到它离开程序的地方,执行程序的下一条语句。

  • 有没有一个工具可以帮助查找python的bug和进行静态的代码分析?

    有,PyChecker是一个python代码的静态分析工具,它可以帮助查找python代码的bug, 会对代码的复杂度和格式提出警告

    Pylint是另外一个工具可以进行coding standard检查。

  • 如何在一个function里面设置一个全局的变量?

    解决方法是在function的开始插入一个global声明:

     def f():
         global x
    
  • 听过 the zen of python 吗?尽可能地默写它,中英文皆可,大意也可。如果没有听过,谈谈你对 pythonic 的看法,或者你认为什么样的 python 代码才是好代码。

    在python中import this就会展示出The Zen of Python如下:

    The Zen of Python, by Tim Peters

    Beautiful is better than ugly.
    Explicit is better than implicit.
    Simple is better than complex.
    Complex is better than complicated.
    Flat is better than nested.
    Sparse is better than dense.
    Readability counts.
    Special cases aren't special enough to break the rules.
    Although practicality beats purity.
    Errors should never pass silently.
    Unless explicitly silenced.
    In the face of ambiguity, refuse the temptation to guess.
    There should be one-- and preferably only one --obvious way to do it.
    Although that way may not be obvious at first unless you're Dutch.
    Now is better than never.
    Although never is often better than right now.
    If the implementation is hard to explain, it's a bad idea.
    If the implementation is easy to explain, it may be a good idea.
    Namespaces are one honking great idea -- let's do more of those!

    这被称为python之禅,以下是翻译

    Python之禅

    优美胜于丑陋(Python 以编写优美的代码为目标)
    明了胜于晦涩(优美的代码应当是明了的,命名规范,风格相似)
    简洁胜于复杂(优美的代码应当是简洁的,不要有复杂的内部实现)
    复杂胜于凌乱(如果复杂不可避免,那代码间也不能有难懂的关系,要保持接口简洁)
    扁平胜于嵌套(优美的代码应当是扁平的,不能有太多的嵌套)
    间隔胜于紧凑(优美的代码有适当的间隔,不要奢望一行代码解决问题)
    可读性很重要(优美的代码是可读的)
    即便假借特例的实用性之名,也不可违背这些规则(这些规则至高无上)
    不要包容所有错误,除非你确定需要这样做(精准地捕获异常,不写 except:pass 风格的代码)
    当存在多种可能,不要尝试去猜测
    而是尽量找一种,最好是唯一一种明显的解决方案(如果不确定,就用穷举法)
    虽然这并不容易,因为你不是 Python 之父(这里的 Dutch 是指 Guido )
    做也许好过不做,但不假思索就动手还不如不做(动手之前要细思量)
    如果你无法向人描述你的方案,那肯定不是一个好方案;反之亦然(方案测评标准)
    命名空间是一种绝妙的理念,我们应当多加利用(倡导与号召)

    参考:pythonic

  • 现在有一个 dict 对象 adict,里面包含了一百万个元素,查找其中的某个元素的平均需要多少次比较?一千万个元素呢?

    python dict和set都是使用hash表来实现(类似c++11标准库中unordered_map),查找元素的时间复杂度是O(1)

     a = range(1000)
     s = set(a)
     d = dict((i,1) for i in a)
     %timeit -n 10000 100 in d
     %timeit -n 10000 100 in s
     10000 loops, best of 3: 43.5 ns per loop
     10000 loops, best of 3: 49.6 ns per loop
    

    dict的效率略高(占用的空间也多一些)。

  • 现在有一个 list 对象 alist,里面的所有元素都是字符串,编写一个函数对它实现一个大小写无关的排序。

     a = ['a', 'A', 'b', 'C', 'd']
     b = [i.lower() for i in a]
     b.sort()
    
  • python 里关于“堆”这种数据结构的模块是哪个?“堆”有什么优点和缺点?举一个游戏开发中可能会用到堆的问题(不限是于 python 的堆,可以是其它语言的相关实现)。

    heapq模块使用一个用堆实现的优先级队列。堆是一种简单的有序列表,并且置入了堆的相关规则。

    堆是一种树形的数据结构,树上的子节点与父节点之间存在顺序关系。二叉堆(binary heap)能够用一个经过组织的列表或数组结构来标识,在这种结构中,元素N的子节点的序号为2N+1和2N+2(下标始于0)。简单来说,这个模块中的所有函数都假设序列是有序的,所以序列中的第一个元素(seq[

     import heapq
    
     heap = []
    
     for value in [20, 10, 30, 50, 40]:
         heapq.heappush(heap, value)
    
     while heap:
         print heapq.heappop(heap)
    

    heapq模块有两个函数nlargest()和nsmallest(),顾名思义,让我们来看看它们的用法。

     import heapq
    
     nums = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2]
     print(heapq.nlargest(3, nums)) # Prints [42, 37, 23]
     print(heapq.nsmallest(3, nums)) # Prints [-4, 1, 2]
    

    两个函数也能够通过一个键参数使用更为复杂的数据结构,例如:

     import heapq
    
     portfolio = [
     {'name': 'IBM', 'shares': 100, 'price': 91.1},
     {'name': 'AAPL', 'shares': 50, 'price': 543.22},
     {'name': 'FB', 'shares': 200, 'price': 21.09},
     {'name': 'HPQ', 'shares': 35, 'price': 31.75},
     {'name': 'YHOO', 'shares': 45, 'price': 16.35},
     {'name': 'ACME', 'shares': 75, 'price': 115.65}
     ]
     cheap = heapq.nsmallest(3, portfolio, key=lambda s: s['price'])
     expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
    
     print cheap
    
     # [{'price': 16.35, 'name': 'YHOO', 'shares': 45},
     # {'price': 21.09, 'name': 'FB', 'shares': 200}, {'price': 31.75, 'name': 'HPQ', 'shares': 35}]
    
     print expensive
    
     # [{'price': 543.22, 'name': 'AAPL', 'shares': 50}, {'price': 115.65, 'name': 'ACME', 
     # 'shares': 75}, {'price': 91.1, 'name': 'IBM', 'shares': 100}]
    

    来看看如何实现一个根据给定优先级进行排序,并且每次pop操作都返回优先级最高的元素的队列例子。

     import heapq
    
     class Item:
         def __init__(self, name):
             self.name = name
    
         def __repr__(self):
             return 'Item({!r})'.format(self.name)
    
     class PriorityQueue:
         def __init__(self):
             self._queue = []
             self._index = 0
    
         def push(self, item, priority):
             heapq.heappush(self._queue, (-priority, self._index, item))
             self._index += 1
    
         def pop(self):
             return heapq.heappop(self._queue)[-1]
    
     q = PriorityQueue()
     q.push(Item('foo'), 1)
     q.push(Item('bar'), 5)
     q.push(Item('spam'), 4)
     q.push(Item('grok'), 1)
    
     print q.pop() # Item('bar')
     print q.pop() # Item('spam')
     print q.pop() # Item('foo')
     print q.pop() # Item('grok')
    

    数据结构优缺点

     类型  优点  缺点
     数组  插入块,如果知道下标,可以非常快的存储 查找慢,删除慢,大小固定
     有序数组    比无序数组查找快    删除和插入慢,大小固定
     栈   提供后进先出方式的存取 效率低
     队列  提供先进先出的方式存取 效率低
     链表  插入,删除快  查找慢
     二叉树 查找,插入,删除都快  如果非平衡就很慢,删除的算法复杂
     红黑树 查找,插入,删除都快  算法复杂
     哈希表 如果关键字已知则存取极快,插入块    删除慢,如果不知道关键字则存取很慢,对存储空间使用不充分
     堆   插入,删除快,对最大数据项的存取很快  对其他存储项很慢
    
  • set 是在哪个版本成为 build-in types 的?举一个你在以往项目中用到这种数据结构的问题(不限是于 python 的 set ,可以是其它语言的相关实现),并说明为什么当时选择了 set 这种数据结构。

    set跟list一样可以用{}来定义,但是pyton -v 版本 >2.7
    set的数据格式:

     [html] view plaincopy
     s1={"abc","def"}      #{} 自己定义  
     >>> print s1  
     set(['abc', 'def'])    
     >>> s2=set("abcdef")  #set 函数用string进行初始化  
     >>> print s2  
     set(['a', 'c', 'b', 'e', 'd', 'f'])  
     >>> s3=set(["abc",123,"def"])  #set 函数用list进行初始化  
     >>> print s3  
     set([123, 'abc', 'def'])  
    
  • 有一个排好序地 list 对象 alist,查找其中是否有某元素 a(尽可能地使用标准库函数)。

    index() 函数用于从列表中找出某个值第一个匹配项的索引位置。

     list.index(obj) # obj -- 查找的对象。
    

    该方法返回查找对象的索引位置,如果没有找到对象则抛出异常。

    count() 方法用于统计某个元素在列表中出现的次数。

     list.count(obj) # obj -- 列表中统计的对象。
    

    返回元素在列表中出现的次数。

  • 说说 dict 的 items() 方法与 iteritems() 方法的不同。

     #字典items()的使用
     dict = {"a" : "apple", "b" : "banana", "c" : "grape", "d" : "orange"}
     #每个元素是一个key和value组成的元组,以列表的方式输出
     print dict.items()
     #调用items()实现字典的遍历
     dict = {"a" : "apple", "b" : "banana", "g" : "grape", "o" : "orange"}
     for (k, v) in dict.items():
         print "dict[%s] =" % k, v
     #调用iteritems()实现字典的遍历
     dict = {"a" : "apple", "b" : "banana", "c" : "grape", "d" : "orange"}
     print dict.iteritems()
     for k, v in dict.iteritems():
         print "dict[%s] =" % k, v
     for (k, v) in zip(dict.iterkeys(), dict.itervalues()):
         print "dict[%s] =" % k, v
    

    python3.0以上,不存在dict.iteritems()这个函数。

  • 写一段程序逐行读入一个文本文件,并在屏幕上打印出来。

     file_object = open('thefile.txt')  
     try:  
          for line in file_object:
              print line.rstrip()
     finally:  
          file_object.close()
    
  • 默写尽可能多的 str 对象的方法。

    在python 中任何事物都是对象,就是万物皆对象,同时字符串也是一个对象,当你调用一些基本的操作方法时,会自动调用类定义的内建方法,在python中方法主要三种

    1. 一般的工友方法(默认)命名:和一般的函数命名规则相同

    2. 私有方法命名:一般以__开始

    3. 内建的方法,有时你也需要重写或重载 比如init构造方法
      下面具体来看一下str的类方法

      class str(basestring)

      | str(object) ->string
      |
      | Return a nice stringrepresentation of the object.
      | If the argument is a string,the return value is the same object.
      |
      | Method resolutionorder:
      | str
      | basestring
      | object
      |
      | Methods defined here:
      |
      | add(...)
      | x.add(y) <==> x+y
      |
      | contains(...)
      | x.contains(y) <==> y in x
      |
      | eq(...)
      | x.eq(y) <==> x==y
      |
      | format(...)
      | S.format(format_spec) -> unicode
      |
      | ge(...)
      | x.ge(y) <==>x>=y
      |
      | getattribute(...)
      | x.getattribute('name') <==>x.name
      |
      | getitem(...)
      | x.getitem(y) <==> x[y]
      |
      | getnewargs(...)
      |
      | getslice(...)
      | x.getslice(i, j) <==>x[i:j]
      |
      | Use of negative indices is not supported.
      |
      | gt(...)
      | x.gt(y) <==>x>y
      |
      | hash(...)
      | x.hash() <==> hash(x)
      |
      | le(...)
      | x.le(y) <==>x<=y
      |
      | len(...)
      | x.len() <==> len(x)
      |
      | lt(...)
      | x.lt(y) <==>x<y
      |
      | mod(...)
      | x.mod(y) <==> x%y
      |
      | mul(...)
      | x.mul(n) <==> xn
      |
      | ne(...)
      | x.ne(y) <==> x!=y
      |
      | repr(...)
      | x.repr() <==> repr(x)
      |
      | rmod(...)
      | x.rmod(y) <==> y%x
      |
      | rmul(...)
      | x.rmul(n) <==> n
      x
      |
      | sizeof(...)
      | S.sizeof() -> size of S in memory, inbytes
      |
      | str(...)
      | x.str() <==> str(x)
      |
      | capitalize(...)
      | S.capitalize() -> string
      |
      | Return a copy of the string S with only its first character
      | capitalized.
      |
      | center(...)
      | S.center(width[, fillchar]) -> string
      |
      | Return S centered in a string of length width. Padding is
      | done using the specified fill character (default is a space)
      |
      | count(...)
      | S.count(sub[, start[, end]]) -> int
      |
      | Return the number of non-overlapping occurrences of substring subin
      | string S[start:end]. Optional arguments start andend are interpreted
      | as in slice notation.
      |
      | decode(...)
      | S.decode([encoding[,errors]]) -> object
      |
      | Decodes S using the codec registered for encoding. encodingdefaults
      | to the default encoding. errors may be given to set a differenterror
      | handling scheme. Default is 'strict' meaning that encoding errorsraise
      | a UnicodeDecodeError. Other possible values are 'ignore' and'replace'
      | as well as any other name registered with codecs.register_errorthat is
      | able to handle UnicodeDecodeErrors.
      |
      | encode(...)
      | S.encode([encoding[,errors]]) -> object
      |
      | Encodes S using the codec registered for encoding. encodingdefaults
      | to the default encoding. errors may be given to set a differenterror
      | handling scheme. Default is 'strict' meaning that encoding errorsraise
      | a UnicodeEncodeError. Other possible values are 'ignore', 'replace'and
      | 'xmlcharrefreplace' as well as any other name registered with
      | codecs.register_error that is able to handleUnicodeEncodeErrors.
      |
      | endswith(...)
      | S.endswith(suffix[, start[, end]]) -> bool
      |
      | Return True if S ends with the specified suffix, Falseotherwise.
      | With optional start, test S beginning at that position.
      | With optional end, stop comparing S at that position.
      | suffix can also be a tuple of strings to try.
      |
      | expandtabs(...)
      | S.expandtabs([tabsize]) -> string
      |
      | Return a copy of S where all tab characters are expanded usingspaces.
      | If tabsize is not given, a tab size of 8 characters isassumed.
      |
      | find(...)
      | S.find(sub [,start [,end]]) -> int
      |
      | Return the lowest index in S where substring sub is found,
      | such that sub is contained within s[start:end]. Optional
      | arguments start and end are interpreted as in slice notation.
      |
      | Return -1 on failure.
      |
      | format(...)
      | S.format(*args, **kwargs) -> unicode
      |
      | index(...)
      | S.index(sub [,start [,end]]) -> int
      |
      | Like S.find() but raise ValueError when the substring is notfound.
      |
      | isalnum(...)
      | S.isalnum() -> bool
      |
      | Return True if all characters in S are alphanumeric
      | and there is at least one character in S, False otherwise.
      |
      | isalpha(...)
      | S.isalpha() -> bool
      |
      | Return True if all characters in S are alphabetic
      | and there is at least one character in S, False otherwise.
      |
      | isdigit(...)
      | S.isdigit() -> bool
      |
      | Return True if all characters in S are digits
      | and there is at least one character in S, False otherwise.
      |
      | islower(...)
      | S.islower() -> bool
      |
      | Return True if all cased characters in S are lowercase and thereis
      | at least one cased character in S, False otherwise.
      |
      | isspace(...)
      | S.isspace() -> bool
      |
      | Return True if all characters in S are whitespace
      | and there is at least one character in S, False otherwise.
      |
      | istitle(...)
      | S.istitle() -> bool
      |
      | Return True if S is a titlecased string and there is at leastone
      | character in S, i.e. uppercase characters may only followuncased
      | characters and lowercase characters only cased ones. ReturnFalse
      | otherwise.
      |
      | isupper(...)
      | S.isupper() -> bool
      |
      | Return True if all cased characters in S are uppercase and thereis
      | at least one cased character in S, False otherwise.
      |
      | join(...)
      | S.join(sequence) -> string
      |
      | Return a string which is the concatenation of the strings inthe
      | sequence. The separator between elements isS.
      |
      | ljust(...)
      | S.ljust(width[, fillchar]) -> string
      |
      | Return S left-justified in a string of length width. Paddingis
      | done using the specified fill character (default is a space).
      |
      | lower(...)
      | S.lower() -> string
      |
      | Return a copy of the string S converted to lowercase.
      |
      | lstrip(...)
      | S.lstrip([chars]) -> string or unicode
      |
      | Return a copy of the string S with leading whitespaceremoved.
      | If chars is given and not None, remove characters in charsinstead.
      | If chars is unicode, S will be converted to unicode beforestripping
      |
      | partition(...)
      | S.partition(sep) -> (head, sep, tail)
      |
      | Search for the separator sep in S, and return the part beforeit,
      | the separator itself, and the part after it. Ifthe separator is not
      | found, return S and two empty strings.
      |
      | replace(...)
      | S.replace (old, new[, count]) -> string
      |
      | Return a copy of string S with all occurrences of substring
      | old replaced by new. If the optional argumentcount is
      | given, only the first count occurrences are replaced.
      |
      | rfind(...)
      | S.rfind(sub [,start [,end]]) -> int
      |
      | Return the highest index in S where substring sub is found,
      | such that sub is contained within s[start:end]. Optional
      | arguments start and end are interpreted as in slice notation.
      |
      | Return -1 on failure.
      |
      | rindex(...)
      | S.rindex(sub [,start [,end]]) -> int
      |
      | Like S.rfind() but raise ValueError when the substring is notfound.
      |
      | rjust(...)
      | S.rjust(width[, fillchar]) -> string
      |
      | Return S right-justified in a string of length width. Paddingis
      | done using the specified fill character (default is a space)
      |
      | rpartition(...)
      | S.rpartition(sep) -> (tail, sep, head)
      |
      | Search for the separator sep in S, starting at the end of S, andreturn
      | the part before it, the separator itself, and the part afterit. If the
      | separator is not found, return two empty strings and S.
      |
      | rsplit(...)
      | S.rsplit([sep [,maxsplit]]) -> list of strings
      |
      | Return a list of the words in the string S, using sep as the
      | delimiter string, starting at the end of the string andworking
      | to the front. If maxsplit is given, at mostmaxsplit splits are
      | done. If sep is not specified or is None, any whitespacestring
      | is a separator.
      |
      | rstrip(...)
      | S.rstrip([chars]) -> string or unicode
      |
      | Return a copy of the string S with trailing whitespaceremoved.
      | If chars is given and not None, remove characters in charsinstead.
      | If chars is unicode, S will be converted to unicode beforestripping
      |
      | split(...)
      | S.split([sep [,maxsplit]]) -> list of strings
      |
      | Return a list of the words in the string S, using sep as the
      | delimiter string. If maxsplit is given, at mostmaxsplit
      | splits are done. If sep is not specified or is None, any
      | whitespace string is a separator and empty strings areremoved
      | from the result.
      |
      | splitlines(...)
      | S.splitlines([keepends]) -> list of strings
      |
      | Return a list of the lines in S, breaking at line boundaries.
      | Line breaks are not included in the resulting list unlesskeepends
      | is given and true.
      |
      | startswith(...)
      | S.startswith(prefix[, start[, end]]) -> bool
      |
      | Return True if S starts with the specified prefix, Falseotherwise.
      | With optional start, test S beginning at that position.
      | With optional end, stop comparing S at that position.
      | prefix can also be a tuple of strings to try.
      |
      | strip(...)
      | S.strip([chars]) -> string or unicode
      |
      | Return a copy of the string S with leading and trailing
      | whitespace removed.
      | If chars is given and not None, remove characters in charsinstead.
      | If chars is unicode, S will be converted to unicode beforestripping
      |
      | swapcase(...)
      | S.swapcase() -> string
      |
      | Return a copy of the string S with uppercase characters
      | converted to lowercase and vice versa.
      |
      | title(...)
      | S.title() -> string
      |
      | Return a titlecased version of S, i.e. words start withuppercase
      | characters, all remaining cased characters have lowercase.
      |
      | translate(...)
      | S.translate(table [,deletechars]) -> string
      |
      | Return a copy of the string S, where all characters occurring
      | in the optional argument deletechars are removed, and the
      | remaining characters have been mapped through the given
      | translation table, which must be a string of length 256.
      |
      | upper(...)
      | S.upper() -> string
      |
      | Return a copy of the string S converted to uppercase.
      |
      | zfill(...)
      | S.zfill(width) -> string
      |
      | Pad a numeric string S with zeros on the left, to fill afield
      | of the specified width. The string S is nevertruncated.

  • 打乱一个排好序的 list 对象 alist。

     import random
     b = ['a', 'a', 'b', 'c', 'd']
     random.shuffle(b)
    
  • 有二维的 list 对象(即它的每一个元素都是一个 list 对象)alist,假定其中的所有元素都具有相同的长度(把 alist 想象成一个表格),写一段程序根据元素的第二个元素排序(即对表格的第二列字段排序)。

     a = [['3', 'b'], ['2', 'd'], ['1', 'c'], ['4', 'a']]
     sorted(a, key=lambda a:a[1])
    

    参考:python中sorted内建函数的用法

  • 实现一个 stack。

     class Stack :
    
         # Creates an empty stack.
         def __init__( self ):
             self._theItems = list()
    
         # Returns True if the stack is empty or False otherwise.
         def isEmpty( self ):
             return len( self ) == 0
    
         # Returns the number of items in the stack.
         def __len__ ( self ):
             return len( self._theItems )
    
         # Returns the top item on the stack without removing it.
         def peek( self ):
             assert not self.isEmpty(), "Cannot peek at an empty stack"
             return self._theItems[-1]
    
         # Removes and returns the top item on the stack.
         def pop( self ):
             assert not self.isEmpty(), "Cannot pop from an empty stack"
             return self._theItems.pop()
    
         # Push an item onto the top of the stack.
         def push( self, item ):
             self._theItems.append( item )
    
  • 编写一个简单的 ini 文件解释器。

    ConfigParser 是用来读取配置文件的包。配置文件的格式如下:中括号“[ ]”内包含的为section。section 下面为类似于key-value 的配置内容。

     [db]
     db_host = 127.0.0.1
     db_port = 22
     db_user = root
     db_pass = rootroot
     
     [concurrent]
     thread = 10
     processor = 20
    

    中括号“[ ]”内包含的为section。紧接着section 为类似于key-value 的options 的配置内容。

    ConfigParser 初始工作
    使用ConfigParser 首选需要初始化实例,并读取配置文件:

     cf = ConfigParser.ConfigParser()
     cf.read("配置文件名")
    

    ConfigParser 常用方法

    1. 获取所有sections。也就是将配置文件中所有“[ ]”读取到列表中:

       s = cf.sections()
       print 'section:', s
      

      将输出(以下将均以简介中配置文件为例):

       section: ['db', 'concurrent']
      
    2. 获取指定section 的options。即将配置文件某个section 内key 读取到列表中:

       o = cf.options("db")
       print 'options:', o
      

      将输出:

       options: ['db_host', 'db_port', 'db_user', 'db_pass']
      
    3. 获取指定section 的配置信息。

       v = cf.items("db")
       print 'db:', v
      

      将输出:

       db: [('db_host', '127.0.0.1'), ('db_port', '22'), ('db_user', 'root'), ('db_pass', 'rootroot')]
      
    4. 按照类型读取指定section 的option 信息。
      同样的还有getfloat、getboolean。

       #可以按照类型读取出来
       db_host = cf.get("db", "db_host")
       db_port = cf.getint("db", "db_port")
       db_user = cf.get("db", "db_user")
       db_pass = cf.get("db", "db_pass")
       
       # 返回的是整型的 
       threads = cf.getint("concurrent", "thread")
       processors = cf.getint("concurrent", "processor")
      
       print "db_host:", db_host
       print "db_port:", db_port
       print "db_user:", db_user
       print "db_pass:", db_pass
       print "thread:", threads
       print "processor:", processors
      

      将输出:

       db_host: 127.0.0.1
       db_port: 22
       db_user: root
       db_pass: rootroot
       thread: 10
       processor: 20
      
    5. 设置某个option 的值。(记得最后要写回)

       cf.set("db", "db_pass", "zhaowei")
       cf.write(open("test.conf", "w"))
      

    6.添加一个section。(同样要写回)

         cf.add_section('liuqing')
         cf.set('liuqing', 'int', '15')
         cf.set('liuqing', 'bool', 'true')
         cf.set('liuqing', 'float', '3.1415')
         cf.set('liuqing', 'baz', 'fun')
         cf.set('liuqing', 'bar', 'Python')
         cf.set('liuqing', 'foo', '%(bar)s is %(baz)s!')
         cf.write(open("test.conf", "w"))
    
    1. 移除section 或者option 。(只要进行了修改就要写回的哦)

       cf.remove_option('liuqing','int')
       cf.remove_section('liuqing')
       cf.write(open("test.conf", "w"))
      
  • 现有 N 个纯文本格式的英文文件,实现一种检索方案,即做一个小搜索引擎。

  • python自动连接ssh的代码

    python自动连接ssh的代码:

     #!/usr/bin/python
     #-*- coding:utf-8 -*-
    
     import sys, time, os
    
     try:
         import pexpect
     except ImportError:
         print """
             You must install pexpect module
         """
         sys.exit(1)
    
     addr_map = {
         'v3' :('root@192.168.1.162', 'sina@2009'),
         'dev':('test016@192.168.1.136', 'test016'),
         }
    
     try:
         key = sys.argv[1]
         host = addr_map[key]
     except:
         print """
             argv error, use it link
             jssh v3, v3 must defined in addr_map
         """
     sys.exit(1)
    
     server = pexpect.spawn('/usr/bin/ssh %s' % host[0])
     server.expect('.*ssword:')
     server.sendline(host[1])
     server.interact()
    
  • 用Python写一个小小的爬虫程序

    Python有一个urllib的库,可以很方便的从给定的url抓取网页,以下这段程序实现了抓取一个url并存到指定文件的功能:

     def downURL(url, filename):
         try:
             fp = urllib2.rulopen(url)
         except:
             print 'download exception'
             return 0
         while 1:
             s = fp.read()
             if not s:
                 break
             op.write(s)
         
         fp.close()
         op.close()
    

    爬虫工作的基本原理就是,给定一个初始的url,下载这个url的网页,然后找出网页上所有满足下载要求的链接,然后把这些链接对应的url下载下来,然后再找下载下来的这些网页的url,我们可以用广度优先搜索实现这个算法,不过,首先得有一个函数找出网页上所有的满足要求的url,下面这个例子用正则表达式找出url。

     def getURL(url):
         try:
             fp = urllib2.urlopen(url)
         except:
             print 'get url exception'
             return []
    
         pattern = re.compile(""http://sports.sina.com.cn/[^\>]+.shtml")
         while 1:
             s = fp.read()
             if not s:
                 break
             urls = pattern.findall(s)
         fp.close()
         return urls
    

    最后就是广度优先搜索了,这个实现起来也很简单:

     def spider(startURL, times):
         urls = []
         urls.append(startURL)
         i = 0
         while 1:
             if i>times:
                 break;
             if len(urls)>0:
                 url = urls.pop(0)
                 print url, len(urls)
                 downURL(url,str(i)+'.htm')
                 i = i + 1
                 if len(urls)<times:
                     urllist = getURL(url)
                     for url in urllist:
                         if urls.count(url) == 0:
                             urls.append(url)
             else:
                 break
         return 1
    
  • 输出一个[1,2,3,...,100]的序列,不用循环、控制语句、函数等。

     l = range(1,101)
     print l
    

部分from 豆瓣


做一件事需要几个步骤

大约是13年的10月开始,我在公司里从事着黑盒测试的工作。当时我的任务是要对服务端的接口进行测试。为了能更好(偷懒)的完成好工作,我开发了一个简单的自动化接口测试程序personal,她可以根据我提交的测试数据、接口文档,自动发送报文进行测试并收集测试结果,然后生成报表发邮件通知我。这本来也没什么值得可说的,本来没打算有大用的小程序,随着被头头的喜爱而不断对其的功能进行扩充。于是,本来没有太经过设计规划的代码喜闻乐见的越来越冗余,连我自己都不忍落目。

于是,在一次次下决心之后,我打算对之前的小程序进行重新设计、重写。这也算是对以前工作的一个重新思考、总结,也期待经过这样一次回顾后,我能对python、自动化测试、框架有更深的理解。当然,这些都是垃圾话,问题是,怎样的一个设计才能更灵活,并且在不同项目之间,也能很快的移植、定制。

我果然又标题党了么 (●´ϖ`●) ?这些貌似跟标题没多大的关系,在说这个之前,我想先谈谈qml中关于Rectangle的若干思考。


自从大约是去年6月左右转了Qt开发之后,就掉进了qml的世界。刚接触时,第一眼觉得qml真的跟css长的很像很像,再加上曾经有用PyQt库的经验,学起来还是不是很难理解的。这半年以来,对qml的理解越来越深,觉得qml真的是很有趣的一个东西。在qml里第一个接触到的组件就是Rectangle,矩形,其实就是一个方块嘛,但是在很多可视的控件设计中都少不了它。

Rectangle

唔,好吧,其实我只是手欠,所以画了个Rectangle的示意图。

刚上手Qt的时候,是在老手的带领下,拼装拼装小组件,拼装拼装页面啥的。用“拼装”这个词来描述可是一点都不虚。我那会所做的就是简单的把组件和组件组合在一起,然后就行啦。于是,对那时的我来说,Rectangle就是一个神奇玩意了,为什么这么说呢。比如,你想自己做一个按钮,一被点击就触发一个事件。(我知道还有一个叫做button的控件,但是让我们忽略它。)那就可以画一个Rectangle上面在盖一个MouseArea,就可以了。ヾ( ´ ▽ ‘ )ノ

Button代码示例

Button

//MyButton.qml
import QtQuick 2.4

Rectangle {
    id:button
    implicitWidth: 100
    implicitHeight: 62
    color:"red"

    signal clicked //点击事件

    MouseArea {
        anchors.fill: parent

        onClicked: {
            button.forceActiveFocus()
            button.clicked()
        }
    }
}

再比如说,你打算弄个霸气大板砖形的输入框,最简单的方法就是弄个Rectangle上面放个TextInput,当然也可以通过定制style来实现,不过总觉得麻烦,不如这样简单粗暴。(=。= )

TextinputBar代码示例

TextinputBar

//MyTextinputBar.qml
import QtQuick 2.4

Rectangle {
    id:textinputbar
    implicitWidth: 100
    implicitHeight: 62
    color:"yellow"
    clip:true

    TextInput {
        anchors.fill: parent
    }
}

在每个qml文件里,组件们被串成了一棵树。在久了之后,有时候我就会想知道,为什么是一种树形结构,或者说这种结构有什么样的好处。并且,在每个qml页面里,起码要有一个根组件,也就是说,你不能创建一个全空白的qml,而这又是为何?

当我试图换个角度来重新看待Rectangle这件事时,我觉得我又对qml有了更深的理解。每个qml文件的根组件就好比是一个类,在其中的其他组件就是那些组件类的一个实例,各种继承、各种封装。Rectangle、Text等是继承Item的,ListView各种wiew是继承Flickable的,Flickable也是继承Item。Item是继承QtObject的……于是,一个qml组件的金字塔一层层的展现出来。


那么,回到我那个倒霉悲催的personal程序上,在这一次的重写计划中,我一直在思考,从qml中学习到的东西,有没有我可以加以借鉴学习的。

personal流程

当初的整个personal程序的大体流程就是如此。我的整个程序的输入是用户的测试用例(集),以及由于是要对接口和后台服务进行测试,我需要读取与服务器通讯的接口配置文档。得到之后,根据用例集以及用例顺序,有序的组装报文,以便于进行测试。当得到报文后,发送报文到被测程序开始测试。被测后台服务会根据接口给我返回报文,我收获返回报文后,对报文进行解析,判断报文格式是否正确,报文内的数据是否与用户之前预留的一致,并将结果记录下来。整个测试结束后,开始统计测试结果、计算通过率、绘制图表,然后生成测试报告,打包将其发送到测试人员邮箱。

当时的我,并没有对程序进行仔细的结构设计,于是我就按照流程,就那么面向过程的实现了整个程序还一度沾沾自喜。于是问题来了,当我有序(悠闲)的用这个程序进行着测试工作时,头头觉得我写的这个很方便,并且每天下班后,服务器自己还可以默默的开始几轮测试简直是太攒了之后。小小的personal程序的需求突然变的开始爆炸,更多的接口、不同的报文格式、验证返回报文内容加上逻辑运算、嵌套多层的测试数据等等,为了适应这些需求,程序变得越来越难改、越改越不好用,我开始头疼了…… (๑´灬`๑)

其实,如果在站的高点来看整个pensonal程序,她所做的事不过就是准备测试开始测试测试结果分析,这三大部分。在准备测试里,读取各种数据、组装报文、得到真实用例集;开始测试里,发送报文并接收返回报文、对返回报文进行验证、收集结果;测试结果分析里,统计结果、根据结果生成各种报表等、发送结果。整个流程和每层内部都看着即熟悉又陌生,有那么一点点相似。如果在站的高一点呢,其实我把每个部分都分成了3个部分,即pre、do、after。

do one thing

于是,我可以再抽象一下,定义一个类。这个类它做一件事,并将此事可以分为3个步骤,分别为准备做开始做后续处理。在此基础上,我可以定义上面三大部分里的每一个小类、以及准备测试、开始测试、测试结果分析等等。这样,就像qml的金字塔一样,一层层的搭起来我的测试程序。

(ง •̀_•́)ง 当然这只是我现在最初的构想,细节部分完全没有涉及、譬如插件系统、并发等等,但是总归要一步一步不是,这一次,我定要想好在动笔。哦,回到那个最初的问题上,做一件事需要几个步骤?对于当下的我来说,应该是3步吧~~ (//▽//)


又是年末,晚安2014

2014qqMail--by mail.qq.com

诸多开心、忧伤、烦恼、不如意一起晚安,
我的2014……晚安。

bgm: 乐活女王 -- 龙宽


修改Typecho程序解决Gravatar被墙

我素来不是辣么暴力的一个人。当Gravatar刚被墙的时候,我只是简单的在主题文件中对Gravatar地址进行了修改。这原本是一件十分简单又美好的事情,我也没有破坏te程序。但紧接着,我后面蛋疼的开始调整新皮、换主题,于是简单而美好的方法让我最终饱受其痛苦,我总是在最后才想起要修改Gravatar地址。

于是,在简洁主义的带领下,我直接对te程序进行了修改( ˘ ³˘)♥,嗯,下面把方法记录于下。


typecho(0.9)
打开 /var/Widget/Abstract/Comments.php
然后搜索$url = $host . '/avatar/'
大概在413行左右的位置,修改如下

 //$url = $host . '/avatar/';
 $url = 'https://secure.gravatar.com/avatar/';

然后保存离开就OK啦,( •́ .̫ •̀ )

这本该也是一个简单又美好的事情,但是我今天又闲的DT的升级了typecho程序,升级到了typecho1.0(141010)。当我开打comments.php文件,想要再次习惯性的修改那行代码,然后见证奇迹的时候,尼玛发现,我去,那行代码呢,去哪了~然后在熟悉的位置上,我看到了,$url = Typecho_Common::gravatarUrl($this->mail, $size, $rating, $default, $this->request->isSecure()); ,我揍、莫要欺负我读书少,尼玛你把gravatarUrl方法收集到哪里去了!!!

(●´∀`●)不过,哼,鱼唇的中原人啊,像寡人这么天资聪慧、肿么可能找不到,想到这,我用我智慧满满的CPU猜了下文件的位置,哦呵呵呵哈哈哈哈哈哈……


typecho(1.0)
打开 /var/Typecho/Common.php
然后搜索 gravatarUrl
大概在937行左右的位置,找到了gravatarUrl方法,修改如下

//$url = $isSecure ? 'https://secure.gravatar.com' : 'http://www.gravatar.com';
$url = $isSecure ? 'https://secure.gravatar.com' : 'https://secure.gravatar.com';

然后保存离开就可以啦~(๑乛◡乛๑)

最后,原谅我,实在是懒得改了,才用这么暴力的方法解决问题~


p.s. 最近有点想看看php的书换换口味,有没有好的入门级的php书可推荐的~


一年记。

这就是一年了罢、从建站到现在,对于像我这种做事毫无持久性的人来说,也算是值得赞赏的一件事了。

这一年发生了不少的事情,于是如果按照一般的总结写法,在一堆废话之后,该说一句总结如下,然后开始1、2、3了。不过,像我这么懒的人来说,这么写简直是太!麻!烦!了。所以,还是按照吐槽的一般标准来写吧~

我是一个很怕回头看的人,在思考一遍当时的情节与发展,总会让我再一次处在当时的心情里。

3月,时间终究是带走了我的亲人,刚知道消息的时候,大哭了一场,后面慢慢回归平静,一遍遍对自己说,这是正常的生命旅行的终点而已、仅此而已。本以为我能冷酷的说再见,而在遗体告别的最后一刻前,终究还是克制不了满溢的泪水,一遍遍、一遍遍...我不知道,在真正生命尽头的地点到底会经历什么,是否上苍真的有神明存在,今天的我只愿,在那一刻,感受不到病痛、安详而温暖的沉睡、消散在天地间、回归虚无...

6月,开始不断的加班,日子感觉一眼望不到头,留在视线中的只有烫金的加班二字。从那会开始,基本每天都是8.30-19.30下班,单休,有时候周日也不休。当然,在boss极度的压榨工作之下,虽然是刚转去Qt开发的我,是进步大大滴。虽然直到现在我仍认为,这种进步对我下份工作的帮助甚微。通俗点说就是,我使用了大量的技能点,却点亮了各种各样的技能,但是每样技能都没点到满,=。=这听起来就有这种淡淡的惆怅。

10月,终于不断的加班加到的高潮,好不容易上一个项目眼看就到到底了,可以轻松几个日子了。我们又被叫回来做另外的活了,于是开始了噩梦一般的封闭开发。哎、一周七天,天天9点多上班到晚上11点多。还不让出去,天天就让对着个电脑干活啊啥的,日子简直都没法过下去了的感觉。当时,想要跳槽的心都有了,如果用%来表示的话,就是99.98%,不过在懒惰大神的指引下,还是忍住了。

今天,我仍然坐在公司里我的位置上,打着代码发着呆、嚼着口香糖加着永远加不完的班、反思着我为啥还不走这一事实。哎,我咋那么懒...

转眼,又见年根。


容我冬个眠

好多月没吐槽了。
实在是因为……懒。
最近想对主题动一下刀。
不过,容我先翻个身,再睡一觉~