一、前言
在開發過程中,遇到了這樣一個情況:我們需要在腳本中通過 suprocess.call方法來啟動另外一個腳本(腳本 B),當然啦,還得傳遞一些參數。在這些參數中,有一個需要傳遞的是一個執行個體化後的對象。我們知道,通過指令行的方式傳遞參數是基于字元格式的,也就是說腳本 B 隻能接收到字元串格式的參數,那麼如何接收啟動腳本傳遞過來的執行個體化後的對象呢?
今天就來聊聊我使用的兩種笨方法:使用 eval以及使用 pickle和 base64子產品。
方法一:使用 eval
其實在代碼中使用 eval應該不算是 good practice,不過既然可以暫時解決問題,何不拿來試試?其實使用這種方法并不能在指令行中傳遞執行個體化後的對象,隻是将執行個體化的過程放在腳本 B 中進行了。
以下是啟動腳本:
import subprocess
class Student(object):
def __init__(self):
self.name = 'Chris'
self.age = 30
def __str__(self):
return '\n'.join('{}:{}'.format(k_, v_) for k_, v_ in self.__dict__.items()
if not k_.startswith('_'))
def start_script():
# 我們把執行個體化的過程延遲
commands = ['python3', '/home/chris/Projects/Python/movie_wisdom/script.py',
'Student()']
subprocess.call(commands)
if __name__ == '__main__':
start_script()
以下是被啟動的腳本,即腳本 B 代碼:
from starter import Student
def main():
student_obj = sys.argv[-1]
# 進行執行個體化,進而達到“傳遞”對象的目的
print(eval(student_obj))
main()
方法二:使用 pickle 和 base64 子產品
這種方法采用的思路描述如下:
1、啟動腳本:pickle子產品的 dumps方法可以将一個 Python 對象序列化成位元組串;
2、啟動腳本:base64子產品的 encodebytes方法可以将二進制的位元組串編碼為字元串;
3、被啟動腳本:base64子產品的 decodebytes方法用于将使用 base64編碼的字元串轉換成為 pickle子產品 dumps後的位元組串;
4、被啟動腳本:pickle子產品的 loads方法将上一步的位元組串轉換成對象執行個體。
看起來上述過程似乎挺麻煩的,但是通常隻需要兩行關鍵代碼就可以解決問題了,不過我們在這兒給封裝到函數中了。
函數的代碼編寫如下:
def pickle_dumps_to_str(obj):
try:
return base64.encodebytes(pickle.dumps(obj)).decode()
except pickle.PicklingError:
pass
def pickle_loads_from_str(obj_str):
try:
return pickle.loads(base64.decodebytes(obj_str.encode()))
except pickle.UnpicklingError:
pass
下面,我們來看看怎麼借助上述兩個函數在指令行中傳遞執行個體化後的 Student對象。
啟動代碼改寫成下面這樣:
def start_script():
student = Student()
student.name = 'Mary'
# 此時傳遞的将是序列化後的 Student 對象執行個體(注意和使用 `eval` 的差別)
commands = ['python3', '/home/chris/Projects/Python/movie_wisdom/script.py',
pickle_dumps_to_str(student)]
subprocess.call(commands)
被啟動的腳本代碼改寫如下:
def main():
student_obj = sys.argv[-1]
# 載入 Student 對象執行個體
print(pickle_loads_from_str(student_obj))
總結
以上就是這篇文章的全部内容了,其實關于這種需要在參數中傳遞執行個體化後的對象的方法不僅限于此,不過這應該算是比較特殊的一種應用情景了吧。如果大家有更好的方法,還望有大神指點。希望這篇文章對有需要的朋友們能有所幫助。