2017-05-10
Python 代码实践小结

最近写了较多的 Python 脚本,将最近自己写的脚本进行一个总结,其中有些是 Python 独有的,有些是所有程序设计中共有的:

  1. 考虑使用 Logger(logger 怎么配置,需要输出哪些信息 – 可以反向考虑,自己看到这个 logger 的时候想了解什么信息)
  2. 传递的数据结构如何考虑(是否对调用方有先验知识的要求,比如返回一个 Tuple,则需要用户了解 tuple 中元素的顺序,这样情况是否应该进行封装;),数据结构定义清楚了,很多东西也就清楚了。
  3. 如何操作数据库(可以学习 sqlalchemy,包括 core 和 orm 两种 api)
  4. 异常如何处理(异常应该分开捕获 – 可以清楚的知道什么情况下导致的,异常之后应该打印日志说明出现什么问题,如果情况恶劣需要进行异常再次抛出或者报警)
  5. 所有获取资源的地方都应该做 check(a. 没有获取到会怎么办;b.获取到异常的怎么办)
  6. 所有操作资源的地方都应该检查是否操作成功
  7. 每个函数都应该简短,如果函数过长应该进行拆分(有个建议值,函数包含的行数应该在 20-30 行之间,具体按照这个规范做过一次之后就会发现这样真好)
  8. 使用 class 之后,考虑重构 __str__ 函数,用户打印输出,如果对象放到 collection 中之后,需要实现 __repr__ 函数,用于打印整个 collection 的时候,直观显示(如果不实现 __str__,会调用 __repr__)
  9. 如果有些资源会发生变化,可以单独抽取出来,做成函数,这样后续调用就可以不用改变了

上述总结肯定有片面的地方,也有不全的地方,欢迎指出

Read More

2012-10-08
Scheme & The Little Scheme

很早前就想学一门脚本语言来玩玩,看了一段时间的python,可是没有继续好好的学下去,导致现在python基
本不会。暑假的时候看到王垠的博客写了一篇文章,推荐了Scheme语言和SICP这本书,上网搜了下后面这本书,发现评论非常好,评价非常高,可以和TAOCP相比了。就打算看看这本神书,顺便做做后面的习题,网上很多大神已经写过题解,不过都是Scheme语言写的,所以就打算先学学Scheme语言。暑假看了《The Little Scheme》和《teach yourself scheme in fixnum days》的一部分,前面一本书是以Scheme语言为基础,主讲递归的思想(个人觉得讲的非常好,不过后面的章节需要一定的scheme语言基础)
后面这本书就是一本介绍scheme的书,比较薄,不过作为入门书还是可以的(用的scheme版本是R5RS)。
t-y Scheme里面首先也是讲数据类型 有boolean number string real等。在scheme里面最基本的东西就属
括号了,每一个过程都是用括号来表示,所以scheme的程序会有非常多的括号。而且表达式是前缀表达式,形如(+ 3 2)计算3+2的值,字符使用#\后面加上相应的字母来表示的,其他的和C语言差不多,
第三章讲述的是过程,类似于C语言中的函数,下面是一个例子


  1. (define area ;定义过程 名字叫做area
  2. (lambda (length breadth) ;两个参数 分别是length 和breadth
  3. (* length breadth) ;计算并返回
  4. )
  5. )
  6. (area 4 6) ;用area过程求值 结果为24=4*6


过程可以用匿名过程,就是没有define那一行,其他地方都一样
第四章讲述的是各种判断,if、when等


  • (define p 80)

  • (if (> p 70)
  • ‘safe ;如果p > 70
  • ‘unsafe ;else
  • )


  • ;unless 貌似是不会循环的 ,我试验的结果是只运行了一次


  • (unless (> p 90)

  • ; (begin
  • (set! p (+ p 1)) ;
  • (display p)
  • ; )
  • )


  • when和unless类似,另外我们可以用过程来写递归或者循环,这里面的递归貌似都是尾递归的。不过循环还有
    一种表达方式就是do表达式,语法如下
    (do ((var1 val1 update1)…)(test res …) exp …)
    ;说明:类似于C语言的for循环。先将val1赋值给var1,…之后循环开始,在每次循环的开始,先执行表达式
    test,
    ;如果返回布尔值真,则循环终止,并返回结果res,如果表达式test返回#f,则运行表达式exp…,之后依次
    ;用update1…的值来为变量var1…重新赋值
    例子如下:


  • (define do-test ;定义过程

  • (lambda (n) ;一个参数 为n
  • (do ((sum 0 (+ sum i)) (i 1 (+ i 1)) ) ;sum 和i都赋初值,然后每次循环分别用 (+ sum i)和 (+ i 1)来改变
  • ((> i n) sum) ;如果i > n则推出循环 返回sum
  • (display sum) ;如果i <= n 则循环
  • )
  • )
  • )


  • 第五章讲的是变量的作用域,一般定义的是全局变量,在函数里面定义的只能在函数里面用,而且会屏蔽全局
    同名变量,可以用let和let来确定一个变量的作用域,let里面局部变量赋初值的时候不能用let里面定义的
    变量,但是let
    里面定义的局部变量可以用let*前面已经定义的局部变量来赋初值。例子如下


  • (define x 20)

  • (let (
  • (x 2)
  • (y x) ;let:a reference to x in the initialization will refer to the global,not the local x
  • )
  • (+ x y) ;结果是20+2
  • )
  • (let* (
  • (x 1)
  • (z 2)
  • (y x)
  • )
  • (+ x y) ;结果是1+1
  • )


  • 第六章里面讲了多个函数相互调用的递归和letrec,letrec和let,let的功能类似,不过let里面的赋初值
    只能用前面已经出现过的局部变量,但是不能用没有出现过的,letrec却可以用后面才出现的局部变量和局部
    过程。例子如下:


  • (letrec ((local-even? (lambda (n) (if (= n 0) #t (local-odd? (- n 1)))))

  • ;如果用let* 那么上面的local-odd?过程就会是未定义的
  • (local-odd? (lambda (n) (if (= n 0) #f (local-even? (- n 1))))))
  • (list (local-even? 23) (local-odd? 23)))


  • 这一章还讲了一个用来翻转list的过程,不过由于R6RS中已经不能用set-cdr!了,所以只能用R5RS来实现,过
    程如下:


  • (define reverse!

  • (lambda (s)
  • (let loop ((s s) (r ‘())) ;定义s 和r 并赋初值
  • (if (null? s) r
  • (let ((d (cdr s))) ;定义d 并赋初值
  • (set-cdr! s r)
  • (loop d s)
  • )
  • )
  • )
  • )
  • )


  • 还有for-each 和 map两个东西,例子如下


  • (for-each display

  • (list “one” “two” “buckle my shoe”) ;输出onetwobuckle my shoe
  • )
  • (display (map cons ‘(1 2 3 4) ‘(10 20 30 ()))) ;输出((1.10) (2.20) (3.30) (4));注意这里连接的两部分元素必须一样多


  • 第七章讲述了文件的基本操作,默认打开的是控制台,可以用open-input-file filename来打开输入文件,
    open-output-file filename来打开输出文件,最后一定要关闭,不然操作的数据不会对文件进行相应的操作(
    特指写功能),可以用call-with-input-file call-with-output-file来代替,这样的话可以不需要自己关
    闭文件,处理完当前的任务就会自动关闭相应的文件,如果用open-output-file打开一个已经存在的文件的时
    候,不加其他参数的话,是会报错的,如果想打开已经存在的文件可以加参数 #:extis ‘update/‘truncate
    update的话是直接在原文件上从头开始修改,而truncate则是删掉旧文件,重新建一个新文件。例子如下


  • (define i (open-input-file “hello.txt”)) ;打开文件

  • (read-char i) ;读取一个字符
  • (define j (read i)) ;定义j为读取剩下的所有字符的一个字符串
  • (define o (open-output-file “greeting.txt” #:exists ‘update)) ;以update方式打开一个文件
  • (display “hello” o) ;输出hello
  • (write-char #\space o) ;输出空格
  • (display ‘world o) ;输出world
  • (newline o) ;输出空行

  • 如果greeting.txt文件里面的文字原来是”abcdefthijklmn”的话,那么上述操作会使得文件的内容变成”hello
    worldlmn”,但是如果用truncate方式打开的话,那么就会变成”hello world”

    顺便把The Little Scheme的commandment贴在这

    First: When recurring on a list of atoms, lat, ask two questions about it: (null? lat) and else.
    When recurring on a number, n, ask two questions about it: (zero? n) and else.
    When recurring on a list of S-expressions, l, ask three questions about it: (null? l), (atom? (car l)), and else.

    Second: Use cons to build lists.

    Third: When building a list, describe the first typical element, and then cons it onto the natural recursion.

    Fourth: Always change at least one argument while recurring .When recurring on a list of atoms, lat, use(cdr lat). When recurring on a number, n, user (sub1 n). And when recurring on a list of S-expressions, l, use (car l) and (cdr l) if neither (null? l) nor (atom? (car l)) are true.
    It must be changed to be closer to termination. The changing argument must be tested in the termination condition:
    when using cdr, test termination with null? and
    when using sub1, test termination with zero?.

    Fifth: When building a value with + , always use 0 for the value of the terminating line, for adding 0 does not change the value of an addition.
    When building a value with x[multiply] , always use 1 for the value of the terminating line, for multiplying by 1 does not change the value of a multiplication.
    Sixth: Simplify only after the function is correct.

    Seventh: Recur on the subparts that are of the smae nature:
    On the sublists of a list.
    On the subexpressions of an arithmetic expression.

    Eighth: Use help functions to abstract from representations.

    Ninth: Abstract common patterns with a new function.

    Tenth: Build functions to collect more than one value at a time.
    这书断断续续的看了一段时间,打算现在开始边看t-y-scheme边看SICP,然后把SICP的每一章课后习题都做了
    ,也好督促自己好好学习。