Py西游攻關之模塊


模塊&包(* * * * *)

模塊(modue)的概念:

在計算機程序的開發過程中,隨着程序代碼越寫越多,在一個文件里代碼就會越來越長,越來越不容易維護。

為了編寫可維護的代碼,我們把很多函數分組,分別放到不同的文件里,這樣,每個文件包含的代碼就相對較少,很多編程語言都采用這種組織代碼的方式。在Python中,一個.py文件就稱之為一個模塊(Module)

使用模塊有什么好處?

最大的好處是大大提高了代碼的可維護性。

其次,編寫代碼不必從零開始。當一個模塊編寫完畢,就可以被其他地方引用。我們在編寫程序的時候,也經常引用其他模塊,包括Python內置的模塊和來自第三方的模塊。

所以,模塊一共三種:

  • python標准庫
  • 第三方模塊
  • 應用程序自定義模塊

另外,使用模塊還可以避免函數名和變量名沖突。相同名字的函數和變量完全可以分別存在不同的模塊中,因此,我們自己在編寫模塊時,不必考慮名字會與其他模塊沖突。但是也要注意,盡量不要與內置函數名字沖突。

模塊導入方法

1 import 語句

import module1[, module2[,... moduleN]

當我們使用import語句的時候,Python解釋器是怎樣找到對應的文件的呢?答案就是解釋器有自己的搜索路徑,存在sys.path里。  

['', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', 
'/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']  

因此若像我一樣在當前目錄下存在與要引入模塊同名的文件,就會把要引入的模塊屏蔽掉。

2  from…import 語句

from modname import name1[, name2[, ... nameN]]

這個聲明不會把整個modulename模塊導入到當前的命名空間中,只會將它里面的name1或name2單個引入到執行這個聲明的模塊的全局符號表。

3  From…import* 語句

from modname import *

這提供了一個簡單的方法來導入一個模塊中的所有項目。然而這種聲明不該被過多地使用。大多數情況, Python程序員不使用這種方法,因為引入的其它來源的命名,很可能覆蓋了已有的定義。

4 運行本質 

#1 import test
#2 from test import add  

無論1還是2,首先通過sys.path找到test.py,然后執行test腳本(全部執行),區別是1會將test這個變量名加載到名字空間,而2只會將add這個變量名加載進來。  

包(package)

如果不同的人編寫的模塊名相同怎么辦?為了避免模塊名沖突,Python又引入了按目錄來組織模塊的方法,稱為包(Package)。

舉個例子,一個abc.py的文件就是一個名字叫abc的模塊,一個xyz.py的文件就是一個名字叫xyz的模塊。

現在,假設我們的abcxyz這兩個模塊名字與其他模塊沖突了,於是我們可以通過包來組織模塊,避免沖突。方法是選擇一個頂層包名:

                                           

引入了包以后,只要頂層的包名不與別人沖突,那所有模塊都不會與別人沖突。現在,view.py模塊的名字就變成了hello_django.app01.views,類似的,manage.py的模塊名則是hello_django.manage

請注意,每一個包目錄下面都會有一個__init__.py的文件,這個文件是必須存在的,否則,Python就把這個目錄當成普通目錄(文件夾),而不是一個包。__init__.py可以是空文件,也可以有Python代碼,因為__init__.py本身就是一個模塊,而它的模塊名就是對應包的名字

調用包就是執行包下的__init__.py文件

 注意點(important)

1--------------

在nod1里import  hello是找不到的,有同學說可以找到呀,那是因為你的pycharm為你把myapp這一層路徑加入到了sys.path里面,所以可以找到,然而程序一旦在命令行運行,則報錯。有同學問那怎么辦?簡單啊,自己把這個路徑加進去不就OK啦:

import sys,os
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
import hello
hello.hello1()

2 --------------

if __name__=='__main__':
    print('ok')

“Make a .py both importable and executable”

      如果我們是直接執行某個.py文件的時候,該文件中那么”__name__ == '__main__'“是True,但是我們如果從另外一個.py文件通過import導入該文件的時候,這時__name__的值就是我們這個py文件的名字而不是__main__。

      這個功能還有一個用處:調試代碼的時候,在”if __name__ == '__main__'“中加入一些我們的調試代碼,我們可以讓外部模塊調用的時候不執行我們的調試代碼,但是如果我們想排查問題的時候,直接執行該模塊文件,調試代碼能夠正常運行!s

3   

##-------------cal.py
def add(x,y):

    return x+y
##-------------main.py
import cal      #from module import cal

def main():

    cal.add(1,2)
    
##--------------bin.py
from module import main

main.main()
# from module import cal 改成 from . import cal同樣可以,這是因為bin.py是我們的執行腳本,
# sys.path里有bin.py的當前環境。即/Users/yuanhao/Desktop/whaterver/project/web這層路徑,
# 無論import what ,  解釋器都會按這個路徑找。所以當執行到main.py時,import cal會找不到,因為
# sys.path里沒有/Users/yuanhao/Desktop/whaterver/project/web/module這個路徑,而
#  from  module/.  import cal 時,解釋器就可以找到了。
注意

time模塊(* * * *)

三種時間表示

在Python中,通常有這幾種方式來表示時間:

  • 時間戳(timestamp) :         通常來說,時間戳表示的是從1970年1月1日00:00:00開始按秒計算的偏移量。我們運行“type(time.time())”,返回的是float類型。
  • 格式化的時間字符串
  • 元組(struct_time)   :         struct_time元組共有9個元素共九個元素:(年,月,日,時,分,秒,一年中第幾周,一年中第幾天,夏令時)
import time

# 1 time() :返回當前時間的時間戳
time.time()  #1473525444.037215

#----------------------------------------------------------

# 2 localtime([secs])
# 將一個時間戳轉換為當前時區的struct_time。secs參數未提供,則以當前時間為准。
time.localtime() #time.struct_time(tm_year=2016, tm_mon=9, tm_mday=11, tm_hour=0,
# tm_min=38, tm_sec=39, tm_wday=6, tm_yday=255, tm_isdst=0)
time.localtime(1473525444.037215)

#----------------------------------------------------------

# 3 gmtime([secs]) 和localtime()方法類似,gmtime()方法是將一個時間戳轉換為UTC時區(0時區)的struct_time。

#----------------------------------------------------------

# 4 mktime(t) : 將一個struct_time轉化為時間戳。
print(time.mktime(time.localtime()))#1473525749.0

#----------------------------------------------------------

# 5 asctime([t]) : 把一個表示時間的元組或者struct_time表示為這種形式:'Sun Jun 20 23:21:05 1993'。
# 如果沒有參數,將會將time.localtime()作為參數傳入。
print(time.asctime())#Sun Sep 11 00:43:43 2016

#----------------------------------------------------------

# 6 ctime([secs]) : 把一個時間戳(按秒計算的浮點數)轉化為time.asctime()的形式。如果參數未給或者為
# None的時候,將會默認time.time()為參數。它的作用相當於time.asctime(time.localtime(secs))。
print(time.ctime())  # Sun Sep 11 00:46:38 2016

print(time.ctime(time.time()))  # Sun Sep 11 00:46:38 2016

# 7 strftime(format[, t]) : 把一個代表時間的元組或者struct_time(如由time.localtime()和
# time.gmtime()返回)轉化為格式化的時間字符串。如果t未指定,將傳入time.localtime()。如果元組中任何一個
# 元素越界,ValueError的錯誤將會被拋出。
print(time.strftime("%Y-%m-%d %X", time.localtime()))#2016-09-11 00:49:56

# 8 time.strptime(string[, format])
# 把一個格式化時間字符串轉化為struct_time。實際上它和strftime()是逆操作。
print(time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X'))

#time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6,
#  tm_wday=3, tm_yday=125, tm_isdst=-1)

#在這個函數中,format默認為:"%a %b %d %H:%M:%S %Y"。


# 9 sleep(secs)
# 線程推遲指定的時間運行,單位為秒。

# 10 clock()
# 這個需要注意,在不同的系統上含義不同。在UNIX系統上,它返回的是“進程時間”,它是用秒表示的浮點數(時間戳)。
# 而在WINDOWS中,第一次調用,返回的是進程運行的實際時間。而第二次之后的調用是自第一次調用以后到現在的運行
# 時間,即兩次時間差。

              

help(time)
help(time.asctime)

random模塊(* *)

import random

print(random.random())#(0,1)----float

print(random.randint(1,3))  #[1,3]

print(random.randrange(1,3)) #[1,3)

print(random.choice([1,'23',[4,5]]))#23

print(random.sample([1,'23',[4,5]],2))#[[4, 5], '23']

print(random.uniform(1,3))#1.927109612082716


item=[1,3,5,7,9]
random.shuffle(item)
print(item)
import random

def v_code():

    code = ''
    for i in range(5):

        num=random.randint(0,9)
        alf=chr(random.randint(65,90))
        add=random.choice([num,alf])
        code += str(add)
    return code

print(v_code())
驗證碼

 os模塊(* * * *)

os模塊是與操作系統交互的一個接口

os.getcwd() 獲取當前工作目錄,即當前python腳本工作的目錄路徑
os.chdir("dirname")  改變當前腳本工作目錄;相當於shell下cd
os.curdir  返回當前目錄: ('.')
os.pardir  獲取當前目錄的父目錄字符串名:('..')
os.makedirs('dirname1/dirname2')    可生成多層遞歸目錄
os.removedirs('dirname1')    若目錄為空,則刪除,並遞歸到上一級目錄,如若也為空,則刪除,依此類推
os.mkdir('dirname')    生成單級目錄;相當於shell中mkdir dirname
os.rmdir('dirname')    刪除單級空目錄,若目錄不為空則無法刪除,報錯;相當於shell中rmdir dirname
os.listdir('dirname')    列出指定目錄下的所有文件和子目錄,包括隱藏文件,並以列表方式打印
os.remove()  刪除一個文件
os.rename("oldname","newname")  重命名文件/目錄
os.stat('path/filename')  獲取文件/目錄信息
os.sep    輸出操作系統特定的路徑分隔符,win下為"\\",Linux下為"/"
os.linesep    輸出當前平台使用的行終止符,win下為"\t\n",Linux下為"\n"
os.pathsep    輸出用於分割文件路徑的字符串 win下為;,Linux下為:
os.name    輸出字符串指示當前使用平台。win->'nt'; Linux->'posix'
os.system("bash command")  運行shell命令,直接顯示
os.environ  獲取系統環境變量
os.path.abspath(path)  返回path規范化的絕對路徑
os.path.split(path)  將path分割成目錄和文件名二元組返回
os.path.dirname(path)  返回path的目錄。其實就是os.path.split(path)的第一個元素
os.path.basename(path)  返回path最后的文件名。如何path以/或\結尾,那么就會返回空值。即os.path.split(path)的第二個元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是絕對路徑,返回True
os.path.isfile(path)  如果path是一個存在的文件,返回True。否則返回False
os.path.isdir(path)  如果path是一個存在的目錄,則返回True。否則返回False
os.path.join(path1[, path2[, ...]])  將多個路徑組合后返回,第一個絕對路徑之前的參數將被忽略
os.path.getatime(path)  返回path所指向的文件或者目錄的最后存取時間
os.path.getmtime(path)  返回path所指向的文件或者目錄的最后修改時間
View Code

sys模塊(* * *)

sys.argv           命令行參數List,第一個元素是程序本身路徑
sys.exit(n)        退出程序,正常退出時exit(0)
sys.version        獲取Python解釋程序的版本信息
sys.maxint         最大的Int值
sys.path           返回模塊的搜索路徑,初始化時使用PYTHONPATH環境變量的值
sys.platform       返回操作系統平台名稱

進度條:

import sys,time
for i in range(10):
    sys.stdout.write('#')
    time.sleep(1)
    sys.stdout.flush()
View Code

json & pickle(* * * *)

之前我們學習過用eval內置方法可以將一個字符串轉成python對象,不過,eval方法是有局限性的,對於普通的數據類型,json.loads和eval都能用,但遇到特殊類型的時候,eval就不管用了,所以eval的重點還是通常用來執行一個字符串表達式,並返回表達式的值。

import json
x="[null,true,false,1]"
print(eval(x))
print(json.loads(x))

什么是序列化?

我們把對象(變量)從內存中變成可存儲或傳輸的過程稱之為序列化,在Python中叫pickling,在其他語言中也被稱之為serialization,marshalling,flattening等等,都是一個意思。

序列化之后,就可以把序列化后的內容寫入磁盤,或者通過網絡傳輸到別的機器上。

反過來,把變量內容從序列化的對象重新讀到內存里稱之為反序列化,即unpickling。

json

如果我們要在不同的編程語言之間傳遞對象,就必須把對象序列化為標准格式,比如XML,但更好的方法是序列化為JSON,因為JSON表示出來就是一個字符串,可以被所有語言讀取,也可以方便地存儲到磁盤或者通過網絡傳輸。JSON不僅是標准格式,並且比XML更快,而且可以直接在Web頁面中讀取,非常方便。

JSON表示的對象就是標准的JavaScript語言的對象,JSON和Python內置的數據類型對應如下:

#----------------------------序列化
import json

dic={'name':'alvin','age':23,'sex':'male'}
print(type(dic))#<class 'dict'>

j=json.dumps(dic)
print(type(j))#<class 'str'>


f=open('序列化對象','w')
f.write(j)  #-------------------等價於json.dump(dic,f)
f.close()
#-----------------------------反序列化
import json f=open('序列化對象') data=json.loads(f.read())# 等價於data=json.load(f)
import json
#dct="{'1':111}"#json 不認單引號
#dct=str({"1":111})#報錯,因為生成的數據還是單引號:{'one': 1}

dct='{"1":"111"}'
print(json.loads(dct))

#conclusion:
#        無論數據是怎樣創建的,只要滿足json格式,就可以json.loads出來,不一定非要dumps的數據才能loads
注意點

pickle 

##----------------------------序列化
import pickle

dic={'name':'alvin','age':23,'sex':'male'}

print(type(dic))#<class 'dict'>

j=pickle.dumps(dic)
print(type(j))#<class 'bytes'>


f=open('序列化對象_pickle','wb')#注意是w是寫入str,wb是寫入bytes,j是'bytes'
f.write(j)  #-------------------等價於pickle.dump(dic,f)

f.close()
#-------------------------反序列化
import pickle
f=open('序列化對象_pickle','rb')

data=pickle.loads(f.read())#  等價於data=pickle.load(f)


print(data['age'])    

      Pickle的問題和所有其他編程語言特有的序列化問題一樣,就是它只能用於Python,並且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的數據,不能成功地反序列化也沒關系。

shelve模塊(* * *)

 shelve模塊比pickle模塊簡單,只有一個open函數,返回類似字典的對象,可讀可寫;key必須為字符串,而值可以是python所支持的數據類型

import shelve

f = shelve.open(r'shelve.txt')

# f['stu1_info']={'name':'alex','age':'18'}
# f['stu2_info']={'name':'alvin','age':'20'}
# f['school_info']={'website':'oldboyedu.com','city':'beijing'}
#
#
# f.close()

print(f.get('stu_info')['age'])

xml模塊(* *)

xml是實現不同語言或程序之間進行數據交換的協議,跟json差不多,但json使用起來更簡單,不過,古時候,在json還沒誕生的黑暗年代,大家只能選擇用xml呀,至今很多傳統公司如金融行業的很多系統的接口還主要是xml。

xml的格式如下,就是通過<>節點來區別數據結構的:

<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>
xml數據

xml協議在各個語言里的都 是支持的,在python中可以用以下模塊操作xml:

import xml.etree.ElementTree as ET
 
tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)
 
#遍歷xml文檔
for child in root:
    print(child.tag, child.attrib)
    for i in child:
        print(i.tag,i.text)
 
#只遍歷year 節點
for node in root.iter('year'):
    print(node.tag,node.text)
#---------------------------------------

import xml.etree.ElementTree as ET
 
tree = ET.parse("xmltest.xml")
root = tree.getroot()
 
#修改
for node in root.iter('year'):
    new_year = int(node.text) + 1
    node.text = str(new_year)
    node.set("updated","yes")
 
tree.write("xmltest.xml")
 
 
#刪除node
for country in root.findall('country'):
   rank = int(country.find('rank').text)
   if rank > 50:
     root.remove(country)
 
tree.write('output.xml')
View Code

自己創建xml文檔:

import xml.etree.ElementTree as ET
 
 
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'
 
et = ET.ElementTree(new_xml) #生成文檔對象
et.write("test.xml", encoding="utf-8",xml_declaration=True)
 
ET.dump(new_xml) #打印生成的格式
創建xml文檔

configparser模塊(* *)

來看一個好多軟件的常見文檔格式如下:

[DEFAULT]
ServerAliveInterval = 45
Compression = yes
CompressionLevel = 9
ForwardX11 = yes
 
[bitbucket.org]
User = hg
 
[topsecret.server.com]
Port = 50022
ForwardX11 = no

如果想用python生成一個這樣的文檔怎么做呢?

import configparser
 
config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
                      'Compression': 'yes',
                     'CompressionLevel': '9'}
 
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022'     # mutates the parser
topsecret['ForwardX11'] = 'no'  # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile: config.write(configfile)
import configparser

config = configparser.ConfigParser()

#---------------------------------------------查
print(config.sections())   #[]

config.read('example.ini')

print(config.sections())   #['bitbucket.org', 'topsecret.server.com']

print('bytebong.com' in config)# False

print(config['bitbucket.org']['User']) # hg

print(config['DEFAULT']['Compression']) #yes

print(config['topsecret.server.com']['ForwardX11'])  #no


for key in config['bitbucket.org']:
    print(key)


# user
# serveraliveinterval
# compression
# compressionlevel
# forwardx11


print(config.options('bitbucket.org'))#['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11']
print(config.items('bitbucket.org'))  #[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')]

print(config.get('bitbucket.org','compression'))#yes


#---------------------------------------------刪,改,增(config.write(open('i.cfg', "w")))


config.add_section('yuan')

config.remove_section('topsecret.server.com')
config.remove_option('bitbucket.org','user')

config.set('bitbucket.org','k1','11111')

config.write(open('i.cfg', "w"))
增刪改查

hashlib模塊(* *)

用於加密相關的操作,3.x里代替了md5模塊和sha模塊,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

import hashlib

m=hashlib.md5()# m=hashlib.sha256()

m.update('hello'.encode('utf8'))
print(m.hexdigest())  #5d41402abc4b2a76b9719d911017c592

m.update('alvin'.encode('utf8'))

print(m.hexdigest())  #92a7e713c30abbb0319fa07da2a5c4af

m2=hashlib.md5()
m2.update('helloalvin'.encode('utf8'))
print(m2.hexdigest()) #92a7e713c30abbb0319fa07da2a5c4af

以上加密算法雖然依然非常厲害,但時候存在缺陷,即:通過撞庫可以反解。所以,有必要對加密算法中添加自定義key再來做加密。

import hashlib

# ######## 256 ########

hash = hashlib.sha256('898oaFs09f'.encode('utf8'))
hash.update('alvin'.encode('utf8'))
print (hash.hexdigest())#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7

python 還有一個 hmac 模塊,它內部對我們創建 key 和 內容 再進行處理然后再加密:

import hmac
h = hmac.new('alvin'.encode('utf8'))
h.update('hello'.encode('utf8'))
print (h.hexdigest())#320df9832eab4c038b6c1d7ed73a5940

subprocess模塊(* * * *)

      當我們需要調用系統的命令的時候,最先考慮的os模塊。用os.system()和os.popen()來進行操作。但是這兩個命令過於簡單,不能完成一些復雜的操作,如給運行的命令提供輸入或者讀取命令的輸出,判斷該命令的運行狀態,管理多個命令的並行等等。這時subprocess中的Popen命令就能有效的完成我們需要的操作。

      subprocess模塊允許一個進程創建一個新的子進程,通過管道連接到子進程的stdin/stdout/stderr,獲取子進程的返回值等操作。 

The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes.

This module intends to replace several other, older modules and functions, such as: os.system、os.spawn*、os.popen*、popen2.*、commands.*

 

這個模塊一個類:Popen。

#Popen它的構造函數如下:

subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None,stderr=None, preexec_fn=None, close_fds=False, shell=False,
cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
# 參數args可以是字符串或者序列類型(如:list,元組),用於指定進程的可執行文件及其參數。
# 如果是序列類型,第一個元素通常是可執行文件的路徑。我們也可以顯式的使用executeable參
# 數來指定可執行文件的路徑。在windows操作系統上,Popen通過調用CreateProcess()來創
# 建子進程,CreateProcess接收一個字符串參數,如果args是序列類型,系統將會通過
# list2cmdline()函數將序列類型轉換為字符串。
# 
# 
# 參數bufsize:指定緩沖。我到現在還不清楚這個參數的具體含義,望各個大牛指點。
# 
# 參數executable用於指定可執行程序。一般情況下我們通過args參數來設置所要運行的程序。如
# 果將參數shell設為True,executable將指定程序使用的shell。在windows平台下,默認的
# shell由COMSPEC環境變量來指定。
# 
# 參數stdin, stdout, stderr分別表示程序的標准輸入、輸出、錯誤句柄。他們可以是PIPE,
# 文件描述符或文件對象,也可以設置為None,表示從父進程繼承。
# 
# 參數preexec_fn只在Unix平台下有效,用於指定一個可執行對象(callable object),它將
# 在子進程運行之前被調用。
# 
# 參數Close_sfs:在windows平台下,如果close_fds被設置為True,則新創建的子進程將不會
# 繼承父進程的輸入、輸出、錯誤管道。我們不能將close_fds設置為True同時重定向子進程的標准
# 輸入、輸出與錯誤(stdin, stdout, stderr)。
# 
# 如果參數shell設為true,程序將通過shell來執行。
# 
# 參數cwd用於設置子進程的當前目錄。
# 
# 參數env是字典類型,用於指定子進程的環境變量。如果env = None,子進程的環境變量將從父
# 進程中繼承。
# 
# 參數Universal_newlines:不同操作系統下,文本的換行符是不一樣的。如:windows下
# 用’/r/n’表示換,而Linux下用’/n’。如果將此參數設置為True,Python統一把這些換行符當
# 作’/n’來處理。
# 
# 參數startupinfo與createionflags只在windows下用效,它們將被傳遞給底層的
# CreateProcess()函數,用於設置子進程的一些屬性,如:主窗口的外觀,進程的優先級等等。
parameter

簡單命令:

import subprocess

a=subprocess.Popen('ls')#  創建一個新的進程,與主進程不同步

print('>>>>>>>',a)#a是Popen的一個實例對象

'''
>>>>>>> <subprocess.Popen object at 0x10185f860>
__init__.py
__pycache__
log.py
main.py

'''

# subprocess.Popen('ls -l',shell=True)

# subprocess.Popen(['ls','-l'])

subprocess.PIPE

在創建Popen對象時,subprocess.PIPE可以初始化stdin, stdout或stderr參數。表示與子進程通信的標准流。

import subprocess

# subprocess.Popen('ls')
p=subprocess.Popen('ls',stdout=subprocess.PIPE)#結果跑哪去啦?

print(p.stdout.read())#這這呢:b'__pycache__\nhello.py\nok.py\nweb\n'

這是因為subprocess創建了子進程,結果本在子進程中,if 想要執行結果轉到主進程中,就得需要一個管道,即 : stdout=subprocess.PIPE

subprocess.STDOUT

創建Popen對象時,用於初始化stderr參數,表示將錯誤通過標准輸出流輸出。

Popen的方法

Popen.poll() 
用於檢查子進程是否已經結束。設置並返回returncode屬性。

Popen.wait() 
等待子進程結束。設置並返回returncode屬性。

Popen.communicate(input=None)
與子進程進行交互。向stdin發送數據,或從stdout和stderr中讀取數據。可選參數input指定發送到子進程的參數。 Communicate()返回一個元組:(stdoutdata, stderrdata)。注意:如果希望通過進程的stdin向其發送數據,在創建Popen對象的時候,參數stdin必須被設置為PIPE。同樣,如 果希望從stdout和stderr獲取數據,必須將stdout和stderr設置為PIPE。

Popen.send_signal(signal) 
向子進程發送信號。

Popen.terminate()
停止(stop)子進程。在windows平台下,該方法將調用Windows API TerminateProcess()來結束子進程。

Popen.kill()
殺死子進程。

Popen.stdin 
如果在創建Popen對象是,參數stdin被設置為PIPE,Popen.stdin將返回一個文件對象用於策子進程發送指令。否則返回None。

Popen.stdout 
如果在創建Popen對象是,參數stdout被設置為PIPE,Popen.stdout將返回一個文件對象用於策子進程發送指令。否則返回 None。

Popen.stderr 
如果在創建Popen對象是,參數stdout被設置為PIPE,Popen.stdout將返回一個文件對象用於策子進程發送指令。否則返回 None。

Popen.pid 
獲取子進程的進程ID。

Popen.returncode 
獲取進程的返回值。如果進程還沒有結束,返回None。
View Code

supprocess模塊的工具函數

supprocess模塊提供了一些函數,方便我們用於創建進程來實現一些簡單的功能。

subprocess.call(*popenargs, **kwargs)
運行命令。該函數將一直等待到子進程運行結束,並返回進程的returncode。如果子進程不需要進行交 互,就可以使用該函數來創建。

subprocess.check_call(*popenargs, **kwargs) 
與subprocess.call(*popenargs, **kwargs)功能一樣,只是如果子進程返回的returncode不為0的話,將觸發CalledProcessError異常。在異常對象中,包 括進程的returncode信息。

check_output(*popenargs, **kwargs)
與call()方法類似,以byte string的方式返回子進程的輸出,如果子進程的返回值不是0,它拋出CalledProcessError異常,這個異常中的returncode包含返回碼,output屬性包含已有的輸出。

getstatusoutput(cmd)/getoutput(cmd)
這兩個函數僅僅在Unix下可用,它們在shell中執行指定的命令cmd,前者返回(status, output),后者返回output。其中,這里的output包括子進程的stdout和stderr。
import subprocess

#1
# subprocess.call('ls',shell=True)
'''
hello.py
ok.py
web
'''
# data=subprocess.call('ls',shell=True)
# print(data)
'''
hello.py
ok.py
web
0
'''

#2
# subprocess.check_call('ls',shell=True)

'''
hello.py
ok.py
web
'''
# data=subprocess.check_call('ls',shell=True)
# print(data)
'''
hello.py
ok.py
web
0
'''
# 兩個函數區別:只是如果子進程返回的returncode不為0的話,將觸發CalledProcessError異常



#3
# subprocess.check_output('ls')#無結果

# data=subprocess.check_output('ls')
# print(data)  #b'hello.py\nok.py\nweb\n'
演示

 交互命令:

終端輸入的命令分為兩種:

  • 輸入即可得到輸出,如:ifconfig
  • 輸入進行某環境,依賴再輸入,如:python

需要交互的命令示例

待續

logging模塊(* * * * *)

一 (簡單應用)

import logging  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message')  

輸出:

WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message

可見,默認情況下Python的logging模塊將日志打印到了標准輸出中,且只顯示了大於等於WARNING級別的日志,這說明默認的日志級別設置為WARNING(日志級別等級CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默認的日志格式為日志級別:Logger名稱:用戶輸出消息。

 

二  靈活配置日志級別,日志格式,輸出位置

import logging  
logging.basicConfig(level=logging.DEBUG,  
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',  
                    datefmt='%a, %d %b %Y %H:%M:%S',  
                    filename='/tmp/test.log',  
                    filemode='w')  
  
logging.debug('debug message')  
logging.info('info message')  
logging.warning('warning message')  
logging.error('error message')  
logging.critical('critical message')

查看輸出:
cat /tmp/test.log 
Mon, 05 May 2014 16:29:53 test_logging.py[line:9] DEBUG debug message
Mon, 05 May 2014 16:29:53 test_logging.py[line:10] INFO info message
Mon, 05 May 2014 16:29:53 test_logging.py[line:11] WARNING warning message
Mon, 05 May 2014 16:29:53 test_logging.py[line:12] ERROR error message
Mon, 05 May 2014 16:29:53 test_logging.py[line:13] CRITICAL critical message

可見在logging.basicConfig()函數中可通過具體參數來更改logging模塊默認行為,可用參數有
filename:用指定的文件名創建FiledHandler(后邊會具體講解handler的概念),這樣日志會被存儲在指定的文件中。
filemode:文件打開方式,在指定了filename時使用這個參數,默認值為“a”還可指定為“w”。
format:指定handler使用的日志顯示格式。
datefmt:指定日期時間格式。
level:設置rootlogger(后邊會講解具體概念)的日志級別
stream:用指定的stream創建StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者文件(f=open('test.log','w')),默認為sys.stderr。若同時列出了filename和stream兩個參數,則stream參數會被忽略。

format參數中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 數字形式的日志級別
%(levelname)s 文本形式的日志級別
%(pathname)s 調用日志輸出函數的模塊的完整路徑名,可能沒有
%(filename)s 調用日志輸出函數的模塊的文件名
%(module)s 調用日志輸出函數的模塊名
%(funcName)s 調用日志輸出函數的函數名
%(lineno)d 調用日志輸出函數的語句所在的代碼行
%(created)f 當前時間,用UNIX標准的表示時間的浮 點數表示
%(relativeCreated)d 輸出日志信息時的,自Logger創建以 來的毫秒數
%(asctime)s 字符串形式的當前時間。默認格式是 “2003-07-08 16:49:45,896”。逗號后面的是毫秒
%(thread)d 線程ID。可能沒有
%(threadName)s 線程名。可能沒有
%(process)d 進程ID。可能沒有
%(message)s用戶輸出的消息

 

三  logger對象

    上述幾個例子中我們了解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分別用以記錄不同級別的日志信息),logging.basicConfig()(用默認日志格式(Formatter)為日志系統建立一個默認的流處理器(StreamHandler),設置基礎配置(如日志級別等)並加到root logger(根Logger)中)這幾個logging模塊級別的函數,另外還有一個模塊級別的函數是logging.getLogger([name])(返回一個logger對象,如果沒有指定名字將返回root logger)

     先看一個最簡單的過程:

import logging

logger = logging.getLogger()
# 創建一個handler,用於寫入日志文件
fh = logging.FileHandler('test.log')

# 再創建一個handler,用於輸出到控制台
ch = logging.StreamHandler()

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter)
ch.setFormatter(formatter)

logger.addHandler(fh) #logger對象可以添加多個fh和ch對象
logger.addHandler(ch)

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')

      先簡單介紹一下,logging庫提供了多個組件:Logger、Handler、Filter、Formatter。Logger對象提供應用程序可直接使用的接口,Handler發送日志到適當的目的地,Filter提供了過濾日志信息的方法,Formatter指定日志顯示格式。

     (1)

      Logger是一個樹形層級結構,輸出信息之前都要獲得一個Logger(如果沒有顯示的獲取則自動創建並使用root Logger,如第一個例子所示)。
      logger = logging.getLogger()返回一個默認的Logger也即root Logger,並應用默認的日志級別、Handler和Formatter設置。
當然也可以通過Logger.setLevel(lel)指定最低的日志級別,可用的日志級別有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。
      Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()輸出不同級別的日志,只有日志等級大於或等於設置的日志級別的日志才會被輸出。 

logger.debug('logger debug message')  
logger.info('logger info message')  
logger.warning('logger warning message')  
logger.error('logger error message')  
logger.critical('logger critical message')  

只輸出了
2014-05-06 12:54:43,222 - root - WARNING - logger warning message
2014-05-06 12:54:43,223 - root - ERROR - logger error message
2014-05-06 12:54:43,224 - root - CRITICAL - logger critical message
     從這個輸出可以看出logger = logging.getLogger()返回的Logger名為root。這里沒有用logger.setLevel(logging.Debug)顯示的為logger設置日志級別,所以使用默認的日志級別WARNIING,故結果只輸出了大於等於WARNIING級別的信息。

     (2) 如果我們再創建兩個logger對象: 

##################################################
logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)

logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO)

logger1.addHandler(fh)
logger1.addHandler(ch)

logger2.addHandler(fh)
logger2.addHandler(ch)

logger1.debug('logger1 debug message')
logger1.info('logger1 info message')
logger1.warning('logger1 warning message')
logger1.error('logger1 error message')
logger1.critical('logger1 critical message')
  
logger2.debug('logger2 debug message')
logger2.info('logger2 info message')
logger2.warning('logger2 warning message')
logger2.error('logger2 error message')
logger2.critical('logger2 critical message')

結果:

      

這里有兩個個問題:

      <1>我們明明通過logger1.setLevel(logging.DEBUG)將logger1的日志級別設置為了DEBUG,為何顯示的時候沒有顯示出DEBUG級別的日志信息,而是從INFO級別的日志開始顯示呢?

       原來logger1和logger2對應的是同一個Logger實例,只要logging.getLogger(name)中名稱參數name相同則返回的Logger實例就是同一個,且僅有一個,也即name與Logger實例一一對應。在logger2實例中通過logger2.setLevel(logging.INFO)設置mylogger的日志級別為logging.INFO,所以最后logger1的輸出遵從了后來設置的日志級別。

      <2>為什么logger1、logger2對應的每個輸出分別顯示兩次?
       這是因為我們通過logger = logging.getLogger()顯示的創建了root Logger,而logger1 = logging.getLogger('mylogger')創建了root Logger的孩子(root.)mylogger,logger2同樣。而孩子,孫子,重孫……既會將消息分發給他的handler進行處理也會傳遞給所有的祖先Logger處理。

        ok,那么現在我們把

# logger.addHandler(fh)

# logger.addHandler(ch)  注釋掉,我們再來看效果:

 

因為我們注釋了logger對象顯示的位置,所以才用了默認方式,即標准輸出方式。因為它的父級沒有設置文件顯示方式,所以在這里只打印了一次。

孩子,孫子,重孫……可逐層繼承來自祖先的日志級別、Handler、Filter設置,也可以通過Logger.setLevel(lel)、Logger.addHandler(hdlr)、Logger.removeHandler(hdlr)、Logger.addFilter(filt)、Logger.removeFilter(filt)。設置自己特別的日志級別、Handler、Filter。若不設置則使用繼承來的值。

<3>Filter
     限制只有滿足過濾規則的日志才會輸出。
     比如我們定義了filter = logging.Filter('a.b.c'),並將這個Filter添加到了一個Handler上,則使用該Handler的Logger中只有名字帶          a.b.c前綴的Logger才能輸出其日志。

 

     filter = logging.Filter('mylogger') 

     logger.addFilter(filter)

     這是只對logger這個對象進行篩選

     如果想對所有的對象進行篩選,則:

      filter = logging.Filter('mylogger') 

      fh.addFilter(filter)

      ch.addFilter(filter)

      這樣,所有添加fh或者ch的logger對象都會進行篩選。

完整代碼1:

import logging

logger = logging.getLogger()
# 創建一個handler,用於寫入日志文件
fh = logging.FileHandler('test.log')

# 再創建一個handler,用於輸出到控制台
ch = logging.StreamHandler()

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

fh.setFormatter(formatter)
ch.setFormatter(formatter)

# 定義一個filter
filter = logging.Filter('mylogger')
fh.addFilter(filter)
ch.addFilter(filter)

# logger.addFilter(filter)
logger.addHandler(fh)
logger.addHandler(ch)




logger.setLevel(logging.DEBUG)

logger.debug('logger debug message')
logger.info('logger info message')
logger.warning('logger warning message')
logger.error('logger error message')
logger.critical('logger critical message')

##################################################
logger1 = logging.getLogger('mylogger')
logger1.setLevel(logging.DEBUG)

logger2 = logging.getLogger('mylogger')
logger2.setLevel(logging.INFO)

logger1.addHandler(fh)
logger1.addHandler(ch)

logger2.addHandler(fh)
logger2.addHandler(ch)

logger1.debug('logger1 debug message')
logger1.info('logger1 info message')
logger1.warning('logger1 warning message')
logger1.error('logger1 error message')
logger1.critical('logger1 critical message')

logger2.debug('logger2 debug message')
logger2.info('logger2 info message')
logger2.warning('logger2 warning message')
logger2.error('logger2 error message')
logger2.critical('logger2 critical message')
View Code

       完整代碼2:

#coding:utf-8  
import logging  
  
# 創建一個logger    
logger = logging.getLogger()  
  
logger1 = logging.getLogger('mylogger')  
logger1.setLevel(logging.DEBUG)  
  
logger2 = logging.getLogger('mylogger')  
logger2.setLevel(logging.INFO)  
  
logger3 = logging.getLogger('mylogger.child1')  
logger3.setLevel(logging.WARNING)  
  
logger4 = logging.getLogger('mylogger.child1.child2')  
logger4.setLevel(logging.DEBUG)  
  
logger5 = logging.getLogger('mylogger.child1.child2.child3')  
logger5.setLevel(logging.DEBUG)  
  
# 創建一個handler,用於寫入日志文件    
fh = logging.FileHandler('/tmp/test.log')  
  
# 再創建一個handler,用於輸出到控制台    
ch = logging.StreamHandler()  
  
# 定義handler的輸出格式formatter    
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  
fh.setFormatter(formatter)  
ch.setFormatter(formatter)  
  
#定義一個filter  
#filter = logging.Filter('mylogger.child1.child2')  
#fh.addFilter(filter)    
  
# 給logger添加handler    
#logger.addFilter(filter)  
logger.addHandler(fh)  
logger.addHandler(ch)  
  
#logger1.addFilter(filter)  
logger1.addHandler(fh)  
logger1.addHandler(ch)  
  
logger2.addHandler(fh)  
logger2.addHandler(ch)  
  
#logger3.addFilter(filter)  
logger3.addHandler(fh)  
logger3.addHandler(ch)  
  
#logger4.addFilter(filter)  
logger4.addHandler(fh)  
logger4.addHandler(ch)  
  
logger5.addHandler(fh)  
logger5.addHandler(ch)  
  
# 記錄一條日志    
logger.debug('logger debug message')  
logger.info('logger info message')  
logger.warning('logger warning message')  
logger.error('logger error message')  
logger.critical('logger critical message')  
  
logger1.debug('logger1 debug message')  
logger1.info('logger1 info message')  
logger1.warning('logger1 warning message')  
logger1.error('logger1 error message')  
logger1.critical('logger1 critical message')  
  
logger2.debug('logger2 debug message')  
logger2.info('logger2 info message')  
logger2.warning('logger2 warning message')  
logger2.error('logger2 error message')  
logger2.critical('logger2 critical message')  
  
logger3.debug('logger3 debug message')  
logger3.info('logger3 info message')  
logger3.warning('logger3 warning message')  
logger3.error('logger3 error message')  
logger3.critical('logger3 critical message')  
  
logger4.debug('logger4 debug message')  
logger4.info('logger4 info message')  
logger4.warning('logger4 warning message')  
logger4.error('logger4 error message')  
logger4.critical('logger4 critical message')  
  
logger5.debug('logger5 debug message')  
logger5.info('logger5 info message')  
logger5.warning('logger5 warning message')  
logger5.error('logger5 error message')  
logger5.critical('logger5 critical message')  
View Code

應用:     

import os
import time
import logging
from config import settings


def get_logger(card_num, struct_time):

    if struct_time.tm_mday < 23:
        file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon, 22)
    else:
        file_name = "%s_%s_%d" %(struct_time.tm_year, struct_time.tm_mon+1, 22)

    file_handler = logging.FileHandler(
        os.path.join(settings.USER_DIR_FOLDER, card_num, 'record', file_name),
        encoding='utf-8'
    )
    fmt = logging.Formatter(fmt="%(asctime)s :  %(message)s")
    file_handler.setFormatter(fmt)

    logger1 = logging.Logger('user_logger', level=logging.INFO)
    logger1.addHandler(file_handler)
    return logger1
View Code

 re模塊(* * * * *)

就其本質而言,正則表達式(或 RE)是一種小型的、高度專業化的編程語言,(在Python中)它內嵌在Python中,並通過 re 模塊實現。正則表達式模式被編譯成一系列的字節碼,然后由用 C 編寫的匹配引擎執行。

字符匹配(普通字符,元字符):

1 普通字符:大多數字符和字母都會和自身匹配
              >>> re.findall('alvin','yuanaleSxalexwupeiqi')
                      ['alvin'] 

2 元字符:. ^ $ * + ? { } [ ] | ( ) \

元字符之. ^ $ * + ? { }

import re

ret=re.findall('a..in','helloalvin')
print(ret)#['alvin']


ret=re.findall('^a...n','alvinhelloawwwn')
print(ret)#['alvin']


ret=re.findall('a...n$','alvinhelloawwwn')
print(ret)#['awwwn']


ret=re.findall('a...n$','alvinhelloawwwn')
print(ret)#['awwwn']


ret=re.findall('abc*','abcccc')#貪婪匹配[0,+oo]   
print(ret)#['abcccc']

ret=re.findall('abc+','abccc')#[1,+oo]
print(ret)#['abccc']

ret=re.findall('abc?','abccc')#[0,1]
print(ret)#['abc']


ret=re.findall('abc{1,4}','abccc')
print(ret)#['abccc'] 貪婪匹配

注意:前面的*,+,?等都是貪婪匹配,也就是盡可能匹配,后面加?號使其變成惰性匹配

ret=re.findall('abc*?','abcccccc')
print(ret)#['ab']

元字符之字符集[]:

#--------------------------------------------字符集[]
ret=re.findall('a[bc]d','acd')
print(ret)#['acd']

ret=re.findall('[a-z]','acd')
print(ret)#['a', 'c', 'd']

ret=re.findall('[.*+]','a.cd+')
print(ret)#['.', '+']

#在字符集里有功能的符號: - ^ \

ret=re.findall('[1-9]','45dha3')
print(ret)#['4', '5', '3']

ret=re.findall('[^ab]','45bdha3')
print(ret)#['4', '5', 'd', 'h', '3']

ret=re.findall('[\d]','45bdha3')
print(ret)#['4', '5', '3']

元字符之轉義符\

反斜杠后邊跟元字符去除特殊功能,比如\.
反斜杠后邊跟普通字符實現特殊功能,比如\d

\d  匹配任何十進制數;它相當於類 [0-9]。
\D 匹配任何非數字字符;它相當於類 [^0-9]。
\s  匹配任何空白字符;它相當於類 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相當於類 [^ \t\n\r\f\v]。
\w 匹配任何字母數字字符;它相當於類 [a-zA-Z0-9_]。
\W 匹配任何非字母數字字符;它相當於類 [^a-zA-Z0-9_]
\b  匹配一個特殊字符邊界,比如空格 ,&,#等

ret=re.findall('I\b','I am LIST')
print(ret)#[]
ret=re.findall(r'I\b','I am LIST')
print(ret)#['I']

現在我們聊一聊\,先看下面兩個匹配:

#-----------------------------eg1:
import re
ret=re.findall('c\l','abc\le')
print(ret)#[]
ret=re.findall('c\\l','abc\le')
print(ret)#[]
ret=re.findall('c\\\\l','abc\le')
print(ret)#['c\\l']
ret=re.findall(r'c\\l','abc\le')
print(ret)#['c\\l']

#-----------------------------eg2:
#之所以選擇\b是因為\b在ASCII表中是有意義的
m = re.findall('\bblow', 'blow')
print(m)
m = re.findall(r'\bblow', 'blow')
print(m)

                       

元字符之分組()

m = re.findall(r'(ad)+', 'add')
print(m)

ret=re.search('(?P<id>\d{2})/(?P<name>\w{3})','23/com')
print(ret.group())#23/com
print(ret.group('id'))#23

元字符之|

ret=re.search('(ab)|\d','rabhdg8sd')
print(ret.group())#ab

re模塊下的常用方法

import re
#1
re.findall('a','alvin yuan')    #返回所有滿足匹配條件的結果,放在列表里
#2
re.search('a','alvin yuan').group()  #函數會在字符串內查找模式匹配,只到找到第一個匹配然后返回一個包含匹配信息的對象,該對象可以
                                     # 通過調用group()方法得到匹配的字符串,如果字符串沒有匹配,則返回None。

#3
re.match('a','abc').group()     #同search,不過盡在字符串開始處進行匹配

#4
ret=re.split('[ab]','abcd')     #先按'a'分割得到''和'bcd',在對''和'bcd'分別按'b'分割
print(ret)#['', '', 'cd']

#5
ret=re.sub('\d','abc','alvin5yuan6',1)
print(ret)#alvinabcyuan6
ret=re.subn('\d','abc','alvin5yuan6')
print(ret)#('alvinabcyuanabc', 2)

#6
obj=re.compile('\d{3}')
ret=obj.search('abc123eeee')
print(ret.group())#123
import re
ret=re.finditer('\d','ds3sy4784a')
print(ret)        #<callable_iterator object at 0x10195f940>

print(next(ret).group())
print(next(ret).group())

注意:

import re

ret=re.findall('www.(baidu|oldboy).com','www.oldboy.com')
print(ret)#['oldboy']     這是因為findall會優先把匹配結果組里內容返回,如果想要匹配結果,取消權限即可

ret=re.findall('www.(?:baidu|oldboy).com','www.oldboy.com')
print(ret)#['www.oldboy.com']

補充:

import re

print(re.findall("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>"))
print(re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>"))
print(re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>"))
View Code

補充2

#匹配出所有的整數
import re

#ret=re.findall(r"\d+{0}]","1-2*(60+(-40.35/5)-(-4*3))")
ret=re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")
ret.remove("")

print(ret)
View Code

 

  

  

  

  

 

 

 

 

 

 

 

 

  

 

  

 

 

 

 

 

 

 

          


       

     

     

       

    


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM