Python代码优化及技巧笔记(一) 前言 版权说明 1.Python实现全排列 2.遍历文件夹下所有子文件夹和文件 3.针对字符串的进制转化 4.IP的点分型和整形数字之间的转化 5.Python获得Linux控制台中的输出信息 6.使用enumerate()函数获取序列迭代的索引和值 7.i+=1与++i有区别 8.使用DeprecationWarning定义过时方法 9.使用Counter进行计数统计 10.准确判断文件类型 Ref:

这里是记录一些本人在开发过程中遇到的一些细节问题,与君共勉。

版权说明

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:Coding-Naga
链接:http://blog.csdn.net/lemon_tree12138/article/details/50736887

来源:CSDN


1.Python实现全排列

方案一:

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
result = list(itertools.permutations(a, 9))
方案二:
上面是使用python的内建函数itertools.permutations对于只有9个元素的全排列速度上是惊人的。
如果是我们自己来写全排列逻辑,可以是下面这样的:
# get full permutation list
def full_permutation(l):
    if(len(l) <= 1):
        return [l]


    r = []
    for i in range(len(l)):
        s = l[:i] + l[i + 1:] # 将l的前三项以及l的第i+1后的字串赋给s
        p = full_permutation(s)
        for x in p:
            r.append(l[i : i + 1] + x)


    return r
所有在项目中还是建议使用Python内建的全排列函数,其中的第二个参数可以是1-9之间的任何一个整数,非常方便。


2.遍历文件夹下所有子文件夹和文件

  在Python中可以很方便地对文件目录进行循环遍历,检查文件及目录,代码如下:

import os
import os.path

def cycle_visiting(root_dir=None):
    for parent, folder_names, file_names in os.walk(root_dir):
        for folder_name in folder_names:
            print 'folder: ' + folder_name
        for file_name in file_names:
            print 'file: ' + os.path.join(parent, file_name)


3.针对字符串的进制转化

  如果你有其他语言的编程功底,可能你已对进制转化十分熟悉。不过我这里要说的进制转化可不是简单从十进制转化为二进制或是转成十六进制。下面你可以试着来解决下面几个问题:
  a.将a = 'ff'的十六进制数转成十进制的255
  b.将a = 14的十进制数转成十六进制的0e
解决方法:
  a.这里需要用一个参数指明原来的进制数
decstr = int(a, 16)
  b.这里需要用一个切片操作用来去掉前缀'0x'
decstr = hex(a)[2:]
if len(decstr) % 2 == 1:
    decstr = '0' + decstr


4.IP的点分型和整形数字之间的转化

  首先需要import两个模块:socket和struct
  1.将ip1 = '172.123.156.241'转化为ip2 = 2893782257L
    ip2 = socket.ntohl(struct.unpack("I",socket.inet_aton(ip1))[0])
  2.将ip2 = 2893782257L转化为ip1 = '172.123.156.241'
    ip1 = socket.inet_ntoa(struct.pack('I',socket.htonl(ip2)))


5.Python获得Linux控制台中的输出信息

  可以通过两种方式来解决这个问题,分别如下:
  方法一:
import subprocess
import os
output = os.popen('cat /proc/cpuinfo | grep model')
print output.read()
  方法二:
status, model = commands.getstatusoutput(shell)
print model


6.使用enumerate()函数获取序列迭代的索引和值

  有时我们在对序列进行迭代的时候,不单单是只要知道序列中的值,还想要知道这个值在序列的什么位置。

  如果要使用代码实现,的确不难。不过会显得多余,因为Python已经为我们做了这些工作。如下:

def test_enumerate():
    array = [1, 2, 3, 4, 5, 6]
    for index, data in enumerate(array):
        print("%d: %d" % (index, data))

    e = enumerate(array)
    print(e.next())
    print(e.next())
    print(e.next())

7.i+=1与++i有区别

  我们知道Python中是不支持自增操作的。所以,你是不是就会以为这里的++i会抛出一个语法错误呢?

  很可惜,这里并不会抛出语法错误。对于i++的确是有这样的问题,不过对于++i则不会。例如在PyCharm编辑器中,我们可以看到如下现象:

  Python代码优化及技巧笔记(一)
前言
版权说明
1.Python实现全排列
2.遍历文件夹下所有子文件夹和文件
3.针对字符串的进制转化
4.IP的点分型和整形数字之间的转化
5.Python获得Linux控制台中的输出信息
6.使用enumerate()函数获取序列迭代的索引和值
7.i+=1与++i有区别
8.使用DeprecationWarning定义过时方法
9.使用Counter进行计数统计
10.准确判断文件类型
Ref:

  在上面的图示中,我们可以看到PyCharm对a++抛出了一个错误提示,对于++a则是一个警告。

  原因是在Python里,++a会被看成是+(+a),也就是说,“+”被理解成了一个正符号。所以,++a的结果还是a。同理,--a的结果也是a.


8.使用DeprecationWarning定义过时方法

  Python中也有类似Java中一样的注解方法。这里我们就以过时注解为例,代码如下:

@DeprecationWarning
def test_dep(name):
    print("Hi, %s." % name)

  与Java不同的是,在Python中使用过时注解,程序被抛出异常而终止运行。如下:

  Python代码优化及技巧笔记(一)
前言
版权说明
1.Python实现全排列
2.遍历文件夹下所有子文件夹和文件
3.针对字符串的进制转化
4.IP的点分型和整形数字之间的转化
5.Python获得Linux控制台中的输出信息
6.使用enumerate()函数获取序列迭代的索引和值
7.i+=1与++i有区别
8.使用DeprecationWarning定义过时方法
9.使用Counter进行计数统计
10.准确判断文件类型
Ref:


9.使用Counter进行计数统计

  如何实现对一个列表进行计数统计呢?

  遍历、打表、集合,还有呢?然而,这些操作对于Python而言却并不那么优雅。下面就是一段比较优雅的操作方式,使用了Python自带的Counter实现。代码如下:

from collections import Counter

def get_counter(data):
    print(data)
    print(Counter(data))


if __name__ == '__main__':
    get_counter(['d', 'a', 'd', 'a', 's', 'e', 'f', 'h', 'w', 'e', 'q', 'd', 'e', 'w', 'f', 's', 'd', 'a'])
  程序执行的结果如下所示:

  Python代码优化及技巧笔记(一)
前言
版权说明
1.Python实现全排列
2.遍历文件夹下所有子文件夹和文件
3.针对字符串的进制转化
4.IP的点分型和整形数字之间的转化
5.Python获得Linux控制台中的输出信息
6.使用enumerate()函数获取序列迭代的索引和值
7.i+=1与++i有区别
8.使用DeprecationWarning定义过时方法
9.使用Counter进行计数统计
10.准确判断文件类型
Ref:


10.准确判断文件类型

  如果准确判断一个文件的类型呢?这里所说的类型例如:png、jpg、doc、csv等等。

  不要说从文件的后缀中获得。如果真的是这样,这个问题就没有任何意义了。而且,我们知道在日常的开发中,我们遇到的文件经常是没有后缀的。这个时候可还怎么用后缀去判断呢?

  可是,万变不离其宗。同一种类型的文件的文件头都是一样的,不同类型的文件的头部是不同的。通过这一点,就可以判断出不同的文件类型了。代码也很好写,如下:

import struct

# 支持文件类型
# 用16进制字符串的目的是可以知道文件头是多少字节
# 各种文件头的长度不一样,少则2字符,长则8字符
def type_list_table():
    return {
        "FFD8FF": "JPEG",
        "89504E47": "PNG",
        "47494638": "GIF",
        "49492A00": "TIFF",
        "424D": "BMP",
        "41433130": "CAD",
        "38425053": "Adobe Photoshop",
        "7B5C727466": "Rich Text Format(rtf)",
        "3C3F786D6C": "XML",
        "68746D6C3E": "HTML",
        "D0CF11E0": "MS Word/Excel (xls.or.doc)",
        "5374616E64617264204A": "MS Access (mdb)",
        "4357530A": "Flash data [swf]"
    }

# ----------------------------------------- #
# 字节码转16进制字符串                         #
# ----------------------------------------- #
def bytes2hex(byte_array):
    num = len(byte_array)
    hex_string = u""
    for i in range(num):
        t = u"%x" % byte_array[i]
        if len(t) % 2:
            hex_string += u"0"
        hex_string += t
    return hex_string.upper()

# ----------------------------------------- #
# 获取文件类型                                #
# ----------------------------------------- #
def file_type(file_name):
    file_reader = open(file_name, 'rb')     # 必须二制制读取
    type_list = type_list_table()
    type_label = 'unknown'
    for value in type_list.keys():
        num_of_bytes = len(value) / 2       # 需要读多少字节
        file_reader.seek(0)                 # 每次读取都要回到文件头,不然会一直往后读取
        hbytes = struct.unpack_from("B" * num_of_bytes, file_reader.read(num_of_bytes))  # 一个“B”表示一个字节
        type_code = bytes2hex(hbytes)
        if type_code == value:
            type_label = type_list[value]
            break
    file_reader.close()
    return type_label

if __name__ == '__main__':
    print file_type('xxx/xxx.jpg')


Ref:

  1. 《编写高质量代码:改善Python程序的91个建议》
  2. 编程中遇到