人生苦短系列中级篇 : python 进阶技巧

2018-09-24  本文已影响0人  siuLimTau

python --version : 3.7.0
update : 2018/09/24

六层标题备忘 : (一) / 1. / (1) / <1> / (i) /<i>

(一)编码问题

1. 'abc' 和 b'abc'

>>> 'abc'.encode()
b'abc'
>>> b'abc'.decode()
'abc'

python3有两种字符序列类型: "str"和"bytes" ,分别对应字符串的"文本状态"和"字节流状态"。
python3中的字符串使用Unicode字符集进行存储,当其类型为"str"时,直接输出会显示对应的文本状态; 而需要查看其对应的字节流(二进制)时,需要对"str"进行编码(encode),需要选择方案,如utf-8,GBK等(python3中默认编码方案为utf-8); 反之由"bytes"类型向"str"转换(decode)时,需要声明之前的编码方案。

>>> s = '中'
>>> type(s)
<class 'str'>
>>> sb = s.encode() # equal to "sb = s.encode(encoding = "utf-8")"
>>> sb
b'\xe4\xb8\xad'
>>> type(sb)
<class 'bytes'>
>>> sb.decode() # means "sb.decode(encoding = "utf-8")"
'中'

2. base64编码

3 str * 8 bit --> 4 str * 6 bit

>>> import base64
>>> base64.b64encode('Life is short, you need python.'.encode())
b'TGlmZSBpcyBzaG9ydCwgeW91IG5lZWQgcHl0aG9uLg=='
>>> base64.b64decode(b'TGlmZSBpcyBzaG9ydCwgeW91IG5lZWQgcHl0aG9uLg==')
b'Life is short, you need python.'

(二)数制转换

1. python中的整数

python中的整数不设上限,可任意大,处理起来非常方便。
python中的整数有4种常用的表示形式,分别为十进制,二进制,八进制,十六进制,其中二、八、十六进制的前缀分别为'0b'、'0o'、'0x',四种形式输入IDLE,都被解释为十进制整数,是一回事。

>>> 65
65
>>> 0b1000001
65
>>> 0o101
65
>>> 0x41
65

2. 拥有字符形式的整数

设整数的十进制形式为n, 当32<=n<=126时,其也可以表示可见字符的ASCII码,可与对应字符相互转换。

>>> chr(65)
'A'
>>> ord('A')
65

3.内置数制转换函数

可以将上述任意数制转换为二、八、十六进制的函数为bin(x),oct(x),hex(x),输出为str。

>>> bin(65)
'0b1000001'
>>> oct(65) #八进制对应的str无前缀
'0101'
>>> hex(65)
'0x41'
>>> hex(0b1000001)
'0x41'

4.其他数制转换方法

(1) 将任意数制(str)转换为十进制 : int('num', base)

这一函数常用于将str强制类型转换成int。

>>> int('0x41',16)
65
>>> int('41',16)
65
>>> int('41') #默认base = 10
41

(2) 不带前缀的格式化输出 : "{:base}".format(x)

>>> "{:b}".format(65)
'1000001'
>>> "{:x}".format(65)
'41'
>>> "{:o}".format(65)
'101'

5.字符串转字节流

(1) binascii.hexlify()

有时需要将字符串与对应的十六进制字节流相互转换(如rtf文档的构造或解析), 使用自带库binascii的函数可轻松解决。

>>> import binascii
>>> binascii.hexlify(b'abc')
b'616263'
>>> binascii.unhexlify(b'616263')
b'abc'
>>> binascii.b2a_hex(b'abc')
b'616263'
>>> binascii.a2b_hex(b'616263')
b'abc'

hexlify()和b2a_hex()都可将字符串转为16进制字节流,
unhexlify()和a2b_hex()都可将16进制字节流转为字符串。

(2) python2的技巧(python3不适用)

在python2中一行代码即可搞定,注意此方法在python3中会报错("hex"编解码器已被删除)。

>>> "abc".encode("hex")
'616263'
>>> '616263'.decode("hex")
'abc'

(三)输入输出

1. 格式化输出需加括号

print("My name is %s" %("yourDaddy"))

2. 格式化输出字符串的两种方式

(1) %

>>> n = 123
>>> s = "%d" % n # 等价于强制类型转换 s = str(n)
>>> s
'123'

(2) .format

<1> 常规填充

>>> "{} - {} cm".format('sandy',18)
'sandy - 18 cm'

<2> 数制转换

>>> '{:b}'.format(18) # to 2
'10010'
>>> '{:x}'.format(18) # to 16
'12'

2. python3 取消了raw_input, 但还可以用input接收输入

>>>message = input()
123
>>> message
'123'

3. sys.stdin.read()可以实现标准输入, IDLE下"enter + ctrl + d"可终止输入(linux下同样适用),windows cmd下为"enter + ctrl + z + enter"

>>>import sys
>>>s=sys.stdin.read()
123

>>>s
'123\n'

(四)命令行下输入参数的处理技巧

1. 获取命令行下输入的参数 : sys.argv

命令行下执行py脚本,后加一堆参数,则用sys.argv可将这些参数以列表形式存储,每个参数都是"str"类型,且列表首元素sys.argv[0] = "pythonFileName"(列表长度 = 输入参数 + 1)。

#test.py
import sys
parse = sys.argv
print(parse)

---

shell > test.py 1 2 3
['C:\\Users\\Administrator\\Desktop\\python3\\test.py','1','2','3']
shell > 

2. 带选项的输入 : getopt库

(1) 短选项模式

#getoptShortMode.py
import getopt
inputt = '-n cos -e -d 18cm add'.split()
print("Input: %s" % (inputt))
opts, args = getopt.getopt(inputt, 'n:ed:')
print("opts: %s" % (opts))
print("args: %s" % (args))

---

shell > getoptShortMode.py
Input: ['-n', 'cos',  '-e', '-d', '18cm', 'add']
opts: [('-n', 'cos'), ('-e', ''), ('-d', '18cm')]
args: ['add']

短选项模式假定py文件后面跟的都是形如"-选项 参数"的格式,其中"选项"为单字母(这就是为什么叫短选项),"参数"可以为空;
短模式函数引用形式为opts,args = getopt(input,shortOpts),input就是输入的"选项-参数"流,上例中的shortOpts = "n:ed:", 其首先将所有选项的字母收集进来,选项后如果有参数,则选项后跟冒号(如"n:"),否则不跟(如"e");
getopt依据shortOpts的规则将Input分成tuple,存入opts,Input中没在shortOpts中出现的部分划到args里。

注意shortopts里选项的顺序不一定非要和input里的选项顺序一致,最后opts里tuple的顺序是跟input里选项出现的先后顺序一致;
但没有选项的参数(如'add')一定要放到最后,否则其后的选项不被识别。

(3) 长选项模式

#getoptLongMode.py
import getopt
inputt = '--name=cos --dick=18cm --r unkown'.split()
print("Input: %s" % (inputt))
opts, args = getopt.getopt(inputt, '', ['name=', 'dick=', 'r'])
print("opts: %s" % (opts))
print("args: %s" % (args))
---
shell > getoptLongMode.py
Input: ['--name=cos', '--dick=18cm', '--r', 'unkown']
opts: [('--name', 'cos'), ('--dick', '18cm'), ('--r', '')]
args: ['unkown']

长选项假定后面跟的都是形如"--选项=参数"或"--选项"的格式,注意shortOpt=''

(3) 混合模式

#mixMode.py
import getopt
inputt = '--name=cos -f handsome --rich --dick=18cm -h 185 -r add unkown'.split()
opts, args = getopt.getopt(inputt, 'f:rh:', ['name=', 'rich', 'dick='])
print("input: %s " % (inputt))
print("opts: %s " % (opts))
print("args: %s " % (args))
---
shell > mixMode.py
input: ['--name=cos', '-f', 'handsome', '--rich', '--dick=18cm', '-h', '185', '-r', 'add', 'unkown'] 
opts: [('--name', 'cos'), ('-f', 'handsome'), ('--rich', ''), ('--dick', '18cm'), ('-h', '185'), ('-r', '')] 
args: ['add', 'unkown']
shell > 

3. 自动生成使用帮助 : argparse库

python 2.7以后弃用optparse模块,改用argparse替代。

(1) 用法

#test2.py
import argparse
parser = argparse.ArgumentParser(description = "argparse test")
parser.add_argument("-t", help="target IP")
cmdInput = parser.parse_args()
---
shell> test2.py -h
usage: test2.py [-h] [-t T]

argparse test

optional arguments:
  -h, --help  show this help message and exit
  -t T        target IP

命令行下输入".py文件" + "-h"自动生成用法帮助信息;
关键函数是add_args,其向命令行添加输入选项,帮助信息存放于help参数中(当然也可以不要)。

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.add_argument("-t")
_StoreAction(option_strings=['-t'], dest='t', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)

(2) add_args函数参数详解

<1> 可选参数 : option_strings = "-t" 或 option_strings = "-p", "--port"

用法: shell> test2.py -p 4444shell>test2.py --port 4444

#test2.py
import argparse
parser = argparse.ArgumentParser()

parser.add_argument("-t")
parser.add_argument("-p","--port")

cmdInput = parser.parse_args()
print("target input: %s %s" % (cmdInput.t,type(cmdInput.t)))
print("port input: %s" % (cmdInput.port)


shell>test2.py -t 127.0.0.1 --port 4444
target input: 127.0.0.1 <class 'str'>
port input: 4444 

当指定选项名为形如"-t"这样的短选项时,后面跟的具体参数会以字符串类型保存于"parse_args().t"中;
而当选项名为"-p"+"--port"长短结合的形式,参数会保存于"parse_args().port"中,当然长短形式的选项都可以使用。

<2> 位置参数 : option_strings = "target"

用法: shell> test2.py 127.0.0.1

#test2.py
import argparse
parser = argparse.ArgumentParser()

parser.add_argument("target")

cmdInput = parser.parse_args()
print("target: %s " % (cmdInput.target))

---
shell> test2.py 127.0.0.1
target: 127.0.0.1

使用位置参数时,无需输入选项,直接输入参数,参数会保存在"parse_args().target"中。

<3> 不需要参数的选项 : action = "store_true"

用法: shell> test2.py -t

#test2.py
import argparse
parser = argparse.ArgumentParser()

parser.add_argument("-t", action="store_true")

cmdInput = parser.parse_args()
print(cmdInput.t)
print(type(cmdInput.t))

---
shell> test2.py -t
True
<class 'bool'>

参数action是用来处理当捕获到输入参数后下一步的动作,默认为 action = "store",即将参数保存到指定变量;
action = "store_true"表示选项后无需输入参数,默认参数为bool型的"True",将其存入变量中。

<4> 其他参数


(五)进程处理技巧

1. 进程中开启多线程 : threading库

  • 进程(process)就是一个应用程序的一次执行过程,线程(thread)是进程中执行运算的最小单位。
  • 操作系统把资源分配给进程,而线程可以在其中独立运行和调度。
  • 一个进程可以有多个线程,一个线程必须属于某个进程。
  • 若一个进程是单线程的,若此进程要执行三个任务,则只能串行执行(即单线程按任务顺序依次执行);多线程是指若一进程有三个线程,要执行三个任务,则三个线程可同时并行处理(CPU在同一时间只能处理一条线程,之所以可以多线程并行处理CPU在多条线程间可以快速切换,造成了同时进行的假象)。

(1) 用法

#Usage:
import threading
threadd = threading.Thread(target = function, args = (funcParameter1,funcParameter1)) #create thread,execute target(function) with/without arguments
threadd.start()

(2) 简单示例

#multiThread.py
import threading

def printNum(Num,Counts):
    for i in range(Counts):
        print(str(Num)*Counts)

counts = 5
thread1 = threading.Thread(target = printNum, args = (1,counts))
thread2 = threading.Thread(target = printNum, args = (0,counts))
thread1.start()
thread2.start()

---
========== RESTART: C:\Users\Administrator\Desktop\python3\multiThread.py ==========
11111
11111
1111100000
>>> 

11111
11111
00000
00000
00000
00000

2. 由窗口到进程 : ctypes.windll.user32.GetWindowThreadProcessId()

  • PID : 进程在被创建时系统内核会为其分配一个固定不变的序列号(PID),供函数或其他进程调用,进程终止后会被回收进行二次分配。
  • 进程句柄(号) : 是指针,动态变化,当访问该进程时得到,用完必须释放。
  • 窗口 : 一个进程可以有多个窗口(想象firefox.exe开两个窗口上网),窗口也有对应的窗口句柄(号)供系统调用,同样是指针,每次调用也动态变化。
#tryCtypes.py
import ctypes

#get window handle
handle = ctypes.windll.user32.GetForegroundWindow()

#get window title
windowTitle = ctypes.create_string_buffer(("\x00" * 512).encode())
length = ctypes.windll.user32.GetWindowTextA(handle, ctypes.byref(windowTitle), 512)

#get PID
pid = ctypes.c_ulong(0)
ctypes.windll.user32.GetWindowThreadProcessId(handle, ctypes.byref(pid))

#get process name
peName = ctypes.create_string_buffer(("\x00" * 512).encode())
hProcess = ctypes.windll.kernel32.OpenProcess(0x400 | 0x10, False, pid)
ctypes.windll.psapi.GetModuleBaseNameA(hProcess,None, ctypes.byref(peName), 512)

kernel32.CloseHandle(handle)
kernel32.CloseHandle(hProcess)


print("[*] current window:")
print("[*] window handle: %s" % handle)
print("[*] pid(process ID): %s" % pid.value)
print("[*] process name: %s" % peName.value.decode())
print("[*] window title: %s" % windowTitle.value.decode())

---
>>> 
========== RESTART: C:\Users\Administrator\Desktop\python3\tryCtypes.py ==========
[*] current window:
[*] window handle: 2360406
[*] pid(process ID): 4172
[*] process name: pythonw.exe
[*] window title: *Python 3.7.0 Shell*
>>> 

(六) windows进阶

1. windows消息机制和钩子 : pyHook库

(1) windows的窗口程序基于消息机制,并由事件驱动。

(2) 钩子(函数)

(3) 应用 : 键盘/鼠标记录

#example.py
import pyHook

def OnMouseEvent(event):
    print('MessageName:',event.MessageName)
    print('Message:',event.Message)
    print('Time:',event.Time)
    print('Window:',event.Window)
    print('WindowName:',event.WindowName)
    print('Position:',event.Position)
    print('Wheel:',event.Wheel)
    print('Injected:',event.Injected)
    print('---')

    # return True to pass the event to other handlers
    # return False to stop the event from propagating
    return True

def OnKeyboardEvent(event):
    print('MessageName:',event.MessageName)
    print('Message:',event.Message)
    print('Time:',event.Time)
    print('Window:',event.Window)
    print('WindowName:',event.WindowName)
    print('Ascii:', event.Ascii, chr(event.Ascii))
    print('Key:', event.Key)
    print('KeyID:', event.KeyID)
    print('ScanCode:', event.ScanCode)
    print('Extended:', event.Extended)
    print('Injected:', event.Injected)
    print('Alt', event.Alt)
    print('Transition', event.Transition)
    print('---')

    # return True to pass the event to other handlers
    # return False to stop the event from propagating
    return True

# create the hook mananger
hm = pyHook.HookManager()
# register two callbacks
hm.MouseAllButtonsDown = OnMouseEvent
hm.KeyDown = OnKeyboardEvent

# hook into the mouse and keyboard events
hm.HookMouse()
hm.HookKeyboard()

if __name__ == '__main__':
    import pythoncom
    pythoncom.PumpMessages()

---

>>> 
 RESTART: C:\Program Files (x86)\Python37-32\Lib\site-packages\pyHook\example.py 
MessageName: mouse left down
Message: 513
Time: 179313024
Window: 65680
WindowName: Running applications
Position: (278, 1015)
Wheel: 0
Injected: 0
---
MessageName: key down
Message: 256
Time: 179317158
Window: 1312710
WindowName: Administrator: Command Prompt
Ascii: 73 I
Key: I
KeyID: 73
ScanCode: 23
Extended: 0
Injected: 0
Alt 0
Transition 0


2. 设备描述表(未完待续)

#pywin32 library
import win32gui
import win32ui
import win32con
import win32api

#1.获取当前桌面的句柄和像素尺寸
hdesktop = win32gui.GetDesktopWindow() 

width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)

#2.获取当前桌面的设备描述表,用以创建截图用的设备描述表
desktopDC = win32gui.GetWindowDC(hdesktop)
imgDC = win32ui.CreateDCFromHandle(desktopDC)

memDC = imgDC.CreateCompatibleDC()

screenshot = win32ui.CreateBitmap()
screenshot.CreateCompatibleBitmap(imgDC, width, height)

memDC.SelectObject(screenshot)

memDC.BitBlt((0, 0), (width, height), imgDC, (left, top), win32con.SRCCOPY)
screenshot.SaveBitmapFile(memDC, 'C:\\Users\\Administrator\\Desktop\\screenshot.bmp')

memDC.DeleteDC()
win32gui.DeleteObject(screenshot.GetHandle())
python实现全屏截图(两个程序对比着看,继续学习这部分内容)
import time
import os, win32gui, win32ui, win32con, win32api

def window_capture():
    hwnd = 0
    hwndDC = win32gui.GetWindowDC(hwnd)
    mfcDC=win32ui.CreateDCFromHandle(hwndDC)
    saveDC=mfcDC.CreateCompatibleDC()
    saveBitMap = win32ui.CreateBitmap()
    MoniterDev=win32api.EnumDisplayMonitors(None,None)
    w = MoniterDev[0][2][2]
    h = MoniterDev[0][2][3]
    print w,h
    saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
    saveDC.SelectObject(saveBitMap)
    saveDC.BitBlt((0,0),(w, h) , mfcDC, (0,0), win32con.SRCCOPY)
    bmpname=win32api.GetTempFileName(".","")[0]+'.bmp'
    saveBitMap.SaveBitmapFile(saveDC, bmpname)
    return bmpname

os.system(window_capture())

3. pywin32库(pip)

import pythoncom
import win32clipboard


4. ctypes库


5. 命令行下与shell交互的处理技巧

(1) 如何与命令行交互(脚本命令放入命令行执行,结果返回)

(2) subprocess库


(七)导入模块的三种方法的区别

1. import module

方法型引用

>>> import math
>>> math.pi
3.141592653589793

2. from module import *

将模块下所有名字引入当前名称空间,直接引用。

>>> from math import *
>>> pi
3.141592653589793

3. import module as xxx

用xxx来代替module进行引用

>>> import math as m
>>> m.pi
3.141592653589793

(八)待研究问题

1.深拷贝与浅拷贝

  1. !!!!!!!!!!!! 类 class !!!!!
  2. py文件封装成exe : XXX库
  3. 爬虫
  4. GUI编程 : PyQt
  5. json
  6. 正则表达式
上一篇下一篇

猜你喜欢

热点阅读