Redis都做了信無雙註冊哪些“變態”設計
使用pro 安信6信無雙指定註冊地址 tobuf主要是兩個步驟,序列化和反序列化。 使用protobuf主要是兩個步驟,序列化和反序列化。
關於Proto有哪些資料型別,然後如何編寫,此處就不贅述了,百度一下有很多。
此文主要是總結,python使用protobuf的過程,如何序列化和反序列化,對不同型別的欄位如何進行賦值。
下面將一一列舉各資料型別,在python中如何正確賦值。
首先,得把編譯包給匯入
import test_pb2 as pb
我分為兩部分,分別為未被repeated
修飾的欄位 和 被repeated
修飾後的欄位
無修飾符#
字串#
test.proto
message SearchService { string type = 1; }
建立message物件,然後賦值即可。與python中,通過類建立例項,例項.屬性
的方式進行賦值類似
search_service = pb.SearchService()
search_service.type = "request"
數字型#
test.proto
message SearchService {
int32 id = 2;
}
與字串賦值一致
search_service = pb.SearchService()
search_service.id = 1
Message#
test.proto
message SearchService { // 定義一個message型別 message SearchRequest { string content = 1; string keyword = 2; } // 型別 欄位名 序號 SearchRequest searchRequest = 3; }
我們看到在SearchService
裡序號為3
的欄位的型別為SearchRequest
,這是我們新定義的message
如果把message看作是一個類,那麼我將其例項化,然後賦值給對應的欄位,可以嗎?
ok,這是不行的,錯誤示例:
search_service = pb.SearchService() # 例項化SearchRequest search_request = pb.SearchService.SearchRequest() # 為search_request內部欄位賦值 search_request.content = "hello protobuf" search_request.keyword = "mk" # 為search_service的searchRequest欄位賦值 search_service.searchRequest = search_request
不允許在協議訊息物件中分配複合字段“searchRequest”。
正確示例:
import test_pb2 as pb
search_service.searchRequest.content = "hello protobuf!"
search_service.searchRequest.keyword = "mk"
如果加上之前的那個欄位,那麼這樣的:
import test_pb2 as pb
search_service.type = "request"
search_service.id = 1
search_service.searchRequest.content = "hello protobuf!"
search_service.searchRequest.keyword = "mk"
Enum#
列舉型別,注意一點:必須包含一個含0的欄位
test.proto
syntax = "proto3";
message SearchService {
enum SearchType {
A = 0;
B = 1;
}
SearchType searchType = 4;
}
序號為4,型別為SearchType
的列舉類,名為searchType
的欄位
此處的列舉型別,你可以看作是網頁中的單選框,只能從給定的資料中選擇一個,不選則預設為0
# 手動選擇1
search_service.searchType = 1
# 或者是根據欄位名進行選擇
search_service.searchType = pb.SearchService.SearchType.A
被repeated修飾的欄位#
字串或數字#
test.proto
syntax = "proto3";
message SearchService {
# 修飾符 型別 欄位名 序號
repeated int32 uid = 5;
}
uid
的型別是int32
,然後被repeated
修飾,即這個欄位是可重複賦值的。
那麼,在python中應該怎麼賦值呢?
錯誤示例:
search_service.uid = 0
如果還是和之前一樣的賦值,就會報錯
AttributeError: Assignment not allowed to repeated field "uid" in protocol message object.
正確示例:
search_service.uid.append(1)
search_service.uid.append(2)
所以,你可以將被repeated
修飾的欄位看作是一個空列表,往裡新增值即可!
Message#
test.proto
syntax = "proto3";
message SearchService {
message Second {
string type = 1;
string word = 2;
}
repeated Second seconds = 6;
}
seconds
欄位是可重複的message
型別,在python中該如何賦值?
# 例項化一個second
second = search_service.Second()
# 為second物件賦值
second.type = 'abc'
second.word = 'world'
# 新增至seconds列表中
search_service.seconds.append(second)
或者,你也可以這樣
search_service.seconds.append(
search_service.Second(type='efg', word="world")
)
或者這樣:
seconds = [
search_service.Second(type='1', word="world"),
search_service.Second(type='2', word="world")
]
search_service.seconds.extend(seconds)
所以,repeated
修飾的欄位,在python中,就是一個列表
Enum#
test.ptoto
syntax = "proto3";
message SearchService {
enum SortOrder {
key1 = 0;
key2 = 1;
key3 = 2;
}
repeated SortOrder sortOrder = 7;
}
使用方法與之前的完全一致
sortFields = [
# 此處key1 根據關鍵詞,獲取列舉值
search_service.SortOrder.key1,
search_service.SortOrder.key2
]
search_service.sortOrder.extend(sortFields)
現在我們已經全部賦值好了,接著就是序列化了
b = search_service.SerializeToString()
print(b)
# b'\n\x07request\x10\x01\x1a\x15\n\x0fhello protobuf!\x12\x02mk
# \x02*\x02\x01\x022\x0c\n\x03abc\x12\x05world2\x0c\n\x03efg
# \x12\x05world2\n\n\x011\x12\x05world2\n\n\x012\x12\x05world:\x02\x00\x01'
SerializeToString
Serializes the protocol message to a binary string.
序列化此協議訊息為二進位制串
反序列化#
現在,我們是接收方,我們收到了一串二進位制。
首先,我們需要使用將其反序列化,同樣使用編譯包。
search_service = pb.SearchService()
b = b'\n\x07request\x10\x01\x1a\x15\n\x0fhello protobuf!\x12\x02mk \x02*\x02\x01\x022\x0c\n\x03abc\x12\x05world2\x0c\n\x03efg\x12\x05world2\n\n\x011\x12\x05world2\n\n\x012\x12\x05world:\x02\x00\x01'
search_service.ParseFromString(b)
# 訪問屬性值
print(search_service.type) # 輸出:request
ParseFromString
解析函式
此時,search_service
就已經含有傳輸過來的全部資料了。如果你不想使用物件.屬性
的方式呼叫,或者想使用類似json.loads
直接轉為python中的字典,那麼你可以使用protobuf_to_dict
將其轉為字典。
安裝protobuf3_to_dict`
pip install protobuf3_to_dict
# 呼叫
from protobuf_to_dict import protobuf_to_dict
b = b'\n\x07request\x10\x01\x1a\x15\n\x0fhello protobuf!\x12\x02mk \x02*\x02\x01\x022\x0c\n\x03abc\x12\x05world2\x0c\n\x03efg\x12\x05world2\n\n\x011\x12\x05world2\n\n\x012\x12\x05world:\x02\x00\x01'
search_service.ParseFromString(b)
# print(search_service.type)
d = protobuf_to_dict(search_service)
print(d, type(d))
# {'type': 'request', 'id': 1, 'searchRequest': {'content': 'hello protobuf!', 'keyword': 'mk'}, 'searchType': 2, 'uid': [1, 2], 'seconds': [{'type': 'abc', 'word': 'world'}, {'type': 'efg', 'word': 'world'}, {'type': '1', 'word': 'world'}, {'type': '2', 'word': 'world'}], 'sortOrder': [0, 1]} <class 'dict'>
小小嚐試#
本文中例子,我做了一個介面。
介面地址:http://47.101.154.110:8000/
使用protobuf主要是兩個步驟,序列化和反序列化。 關於Proto有哪些資料型別,然後如何編寫,此處就不贅述了,百度一下有很多。 此文主要是總結,python使用protobuf的過程,如何序列化和反序列化,對不同型別的欄位如何進行賦值。 序列化#下面將一一列舉各資料型別,在python中如何正確賦值。 首先,得把編譯包給匯入 importtest_pb2aspb 我分為兩部分,分別為未被 無修飾符#字串#
messageSearchService{ stringtype=1; } 建立message物件,然後賦值即可。與python中,通過類建立例項, search_service=pb.SearchService() search_service.type="request" 數字型#
messageSearchService{ int32id=2; } 與字串賦值一致 search_service=pb.SearchService() search_service.id=1 Message#
messageSearchService{ //定義一個message型別 messageSearchRequest{ stringcontent=1; stringkeyword=2; } //型別欄位名序號 SearchRequestsearchRequest=3; } 我們看到在 如果把message看作是一個類,那麼我將其例項化,然後賦值給對應的欄位,可以嗎? ok,這是不行的,錯誤示例: search_service=pb.SearchService()#例項化SearchRequestsearch_request=pb.SearchService.SearchRequest()#為search_request內部欄位賦值search_request.content="helloprotobuf"search_request.keyword="mk"#為search_service的searchRequest欄位賦值search_service.searchRequest=search_request
正確示例: importtest_pb2aspb search_service.searchRequest.content="helloprotobuf!"search_service.searchRequest.keyword="mk" 如果加上之前的那個欄位,那麼這樣的: importtest_pb2aspb search_service.type="request"search_service.id=1search_service.searchRequest.content="helloprotobuf!"search_service.searchRequest.keyword="mk" Enum# 列舉型別,注意一點:必須包含一個含0的欄位
syntax="proto3"; messageSearchService{ enumSearchType{ A=0; B=1; } SearchTypesearchType=4; } 序號為4,型別為 此處的列舉型別,你可以看作是網頁中的單選框,只能從給定的資料中選擇一個,不選則預設為0 #手動選擇1search_service.searchType=1#或者是根據欄位名進行選擇search_service.searchType=pb.SearchService.SearchType.A 被repeated修飾的欄位#字串或數字#
syntax="proto3"; messageSearchService{ #修飾符型別欄位名序號 repeatedint32uid=5; }
那麼,在python中應該怎麼賦值呢? 錯誤示例: search_service.uid=0 如果還是和之前一樣的賦值,就會報錯
正確示例: search_service.uid.append(1) search_service.uid.append(2) 所以,你可以將被 Message#
syntax="proto3"; messageSearchService{ messageSecond{ stringtype=1; stringword=2; } repeatedSecondseconds=6; }
#例項化一個secondsecond=search_service.Second()#為second物件賦值second.type='abc'second.word='world'#新增至seconds列表中search_service.seconds.append(second) 或者,你也可以這樣 search_service.seconds.append( search_service.Second(type='efg',word="world") ) 或者這樣: seconds=[ search_service.Second(type='1',word="world"), search_service.Second(type='2',word="world") ] search_service.seconds.extend(seconds) 所以, Enum#
syntax="proto3"; messageSearchService{ enumSortOrder{ key1=0; key2=1; key3=2; } repeatedSortOrdersortOrder=7; } 使用方法與之前的完全一致 sortFields=[#此處key1根據關鍵詞,獲取列舉值 search_service.SortOrder.key1, search_service.SortOrder.key2 ] search_service.sortOrder.extend(sortFields) 現在我們已經全部賦值好了,接著就是序列化了 b=search_service.SerializeToString() print(b)#b'\n\x07request\x10\x01\x1a\x15\n\x0fhelloprotobuf!\x12\x02mk#\x02*\x02\x01\x022\x0c\n\x03abc\x12\x05world2\x0c\n\x03efg#\x12\x05world2\n\n\x011\x12\x05world2\n\n\x012\x12\x05world:\x02\x00\x01'
反序列化#現在,我們是接收方,我們收到了一串二進位制。 首先,我們需要使用將其反序列化,同樣使用編譯包。 search_service=pb.SearchService() b=b'\n\x07request\x10\x01\x1a\x15\n\x0fhelloprotobuf!\x12\x02mk\x02*\x02\x01\x022\x0c\n\x03abc\x12\x05world2\x0c\n\x03efg\x12\x05world2\n\n\x011\x12\x05world2\n\n\x012\x12\x05world:\x02\x00\x01'search_service.ParseFromString(b)#訪問屬性值print(search_service.type)#輸出:request
此時, 安裝protobuf3_to_dict` pipinstallprotobuf3_to_dict #呼叫fromprotobuf_to_dictimportprotobuf_to_dict b=b'\n\x07request\x10\x01\x1a\x15\n\x0fhelloprotobuf!\x12\x02mk\x02*\x02\x01\x022\x0c\n\x03abc\x12\x05world2\x0c\n\x03efg\x12\x05world2\n\n\x011\x12\x05world2\n\n\x012\x12\x05world:\x02\x00\x01'search_service.ParseFromString(b)#print(search_service.type)d=protobuf_to_dict(search_service) print(d,type(d))#{'type':'request','id':1,'searchRequest':{'content':'helloprotobuf!','keyword':'mk'},'searchType':2,'uid':[1,2],'seconds':[{'type':'abc','word':'world'},{'type':'efg','word':'world'},{'type':'1','word':'world'},{'type':'2','word':'world'}],'sortOrder':[0,1]}<class'dict'> 小小嚐試#本文中例子,我做了一個介面。 介面地址:
你可以使用 也可以使用Python傳送請求 importrequests headers={'Content-Type':'application/grpc-web+proto'} b=b'\n\x07request\x10\x01\x1a\x15\n\x0fhelloprotobuf!\x12\x02mk\x02*\x02\x01\x022\x0c\n\x03abc\x12\x05world2\x0c\n\x03efg\x12\x05world2\n\n\x011\x12\x05world2\n\n\x012\x12\x05world:\x02\x00\x01'resp=requests.post('http://47.101.154.110:8000/',data=b,headers=headers) print(resp.text) 完整的 syntax="proto3"; messageSearchService{ stringtype=1; int32id=2; //定義一個message型別 messageSearchRequest{ stringcontent=1; stringkeyword=2; } //型別欄位名序號 SearchRequestsearchRequest=3; enumSearchType{ A=0; B=1; } SearchTypesearchType=4; repeatedint32uid=5; messageSecond{ stringtype=1; stringword=2; } repeatedSecondseconds=6; enumSortOrder{ key1=0; key2=1; key3=2; } repeatedSortOrdersortOrder=7; } 完整的賦值示例 importtest_pb2aspbfromprotobuf_to_dictimportprotobuf_to_dict search_service=pb.SearchService() search_service.type="request"search_service.id=1search_service.searchRequest.content="helloprotobuf!"search_service.searchRequest.keyword="mk"#search_service.searchType=pb.SearchService.SearchType.Asearch_service.searchType=2search_service.uid.append(1) search_service.uid.append(2) second=search_service.Second() second.type='abc'second.word='world'search_service.seconds.append(second) search_service.seconds.append(search_service.Second(type='efg',word="world")) seconds=[ search_service.Second(type='1',word="world"), search_service.Second(type='2',word="world") ] search_service.seconds.extend(seconds) sortFields=[ search_service.SortOrder.key1, search_service.SortOrder.key2 ] search_service.sortOrder.extend(sortFields) b=search_service.SerializeToString() print(b) 推薦模組#在使用編譯包時,沒有程式碼提示,還有點不習慣。 這裡,推薦安裝 pipinstallmypy-protobuf 使用方法: 在你使用 protoc--python_out=.--mypy-out=.test.proto 此時會生成兩個檔案,並將他們拖入專案中的同一目錄
效果演示: | ||||||||
---|---|---|---|---|---|---|---|---|
你可以使用postman
提交資料,來檢視結果
也可以使用Python傳送請求
import requests
headers = {
'Content-Type': 'application/grpc-web+proto'
}
b = b'\n\x07request\x10\x01\x1a\x15\n\x0fhello protobuf!\x12\x02mk \x02*\x02\x01\x022\x0c\n\x03abc\x12\x05world2\x0c\n\x03efg\x12\x05world2\n\n\x011\x12\x05world2\n\n\x012\x12\x05world:\x02\x00\x01'
resp = requests.post('http://47.101.154.110:8000/', data=b, headers=headers)
print(resp.text)
完整的test.proto
syntax = "proto3";
message SearchService {
string type = 1;
int32 id = 2;
// 定義一個message型別
message SearchRequest {
string content = 1;
string keyword = 2;
}
// 型別 欄位名 序號
SearchRequest searchRequest = 3;
enum SearchType {
A = 0;
B = 1;
}
SearchType searchType = 4;
repeated int32 uid = 5;
message Second {
string type = 1;
string word = 2;
}
repeated Second seconds = 6;
enum SortOrder {
key1 = 0;
key2 = 1;
key3 = 2;
}
repeated SortOrder sortOrder = 7;
}
完整的賦值示例
import test_pb2 as pb
from protobuf_to_dict import protobuf_to_dict
search_service = pb.SearchService()
search_service.type = "request"
search_service.id = 1
search_service.searchRequest.content = "hello protobuf!"
search_service.searchRequest.keyword = "mk"
# search_service.searchType = pb.SearchService.SearchType.A
search_service.searchType = 2
search_service.uid.append(1)
search_service.uid.append(2)
second = search_service.Second()
second.type = 'abc'
second.word = 'world'
search_service.seconds.append(second)
search_service.seconds.append(search_service.Second(type='efg', word="world"))
seconds = [
search_service.Second(type='1', word="world"),
search_service.Second(type='2', word="world")
]
search_service.seconds.extend(seconds)
sortFields = [
search_service.SortOrder.key1,
search_service.SortOrder.key2
]
search_service.sortOrder.extend(sortFields)
b = search_service.SerializeToString()
print(b)
推薦模組#
在使用編譯包時,沒有程式碼提示,還有點不習慣。
這裡,推薦安裝mypy-protobuf
pip install mypy-protobuf
使用方法:
在你使用protoc
命令編譯proto檔案時,新增一個引數mypy-out=
,就像這樣
protoc --python_out=. --mypy-out=. test.proto
此時會生成兩個檔案,並將他們拖入專案中的同一目錄
test_pb2.py
:我們需要匯入使用的編譯包
test_pb2.pyi
:存根檔案,在編輯器中會有程式碼提示(想了解存根檔案,可以看最下面的參考文章)
效果演示: