應用環境
- windows7
- pycharm2018 profession
- python3.6
- django2.0
我們在pycharm 啟動django項目時,常常有這么一個命令操作:
- python manage.py runserver
這里的意思是執行python命令,傳入的參數為 manage.py runserver。這兩個參數就會被保存到sys.argv 列表中。如下,新建一個demo.py
import sys print('hello sys.argv') print(type(sys.argv)) for arg in sys.argv: print(arg)
在terminal窗口執行 python demo.py runserver # 循環遍歷sys.argv 輸出參數
PS:這里解釋sys.argv 是因為在manage.py中,會用到。
打開我們的manage.py文件,可以看到,這里調用的是:
-
execute_from_command_line(sys.argv)
可以看到這里傳入的就是我們執行python 命令傳入的參數(這里是manage.py runserver)。
我們進入到 execute_from_command_line 函數,可以看到的是執行
-
utility.execute()
在execute這個函數中有這么一行代碼,讀取子命令,也即是讀取sys.argv列表中第二個元素runserver,如下圖
同時,在execute函數中,我們需要重點關注的是最后這一行代碼:
-
self.fetch_command(subcommand).run_from_argv(self.argv)
這里傳入的上面的讀取的子命令sys.argv[1] 以及self.argv(這里的self.argv 是在構造函數中傳入的sys.argv)。
我們進入到 fetch_command 函數,這里最后返回的一個Command class instance 。也就是說
-
self.fetch_command(subcommand).run_from_argv(self.argv)
這行代碼的意思是 執行返回的實體類必然包含 run_from_argv函數。
在fetch_command中,最終調用的是
-
import_module('%s.management.commands.%s' % (app_name, name))
這里的注釋:
Given a command name and an application name, return the Command
class instance.
通過名字返回實例,這里類似net中IL編程:動態導入(動態生成程序集)【這是本篇博文的重點】。
通過:
print('%s.management.commands.%s' % (app_name, name))
我們發現動態導入的實例是:
-
django.contrib.staticfiles.management.commands.runserver
而我們的 import_module 函數最終執行的也是python標准庫 importlib下importlib._bootstrap中的gcd_import。如圖:
通過上面的分析,我們知道最終執行的是模塊:
-
django.contrib.staticfiles.management.commands.runserver
下的run_from_argv 函數。
我們打開runserver.py文件,也確是沒有找到該函數,而在其父類中找到:
從上圖看出,這個函數最終執行的是execute函數。而在execute中最終執行卻又是:
-
output = self.handle(*args, **options)
這里的handle是:
def handle(self, *args, **options): """ The actual logic of the command. Subclasses must implement this method. """ raise NotImplementedError('subclasses of BaseCommand must provide a handle() method')
我們從注釋可以知道,這個方法需要由子類實現的,也即最后,最后,最后執行的runserver中handle函數。
分析到這里,已基本很明了,最終執行的是在本地的8000端口啟動一個socketserver監聽程序。
分析所得:
- get到python如何進行動態的導入
- sys.argv 存儲了全局中輸入參數
- sys.moduls注冊了程序運行已經導入模塊
- if 賦值的優雅寫法 subcommand = 'runserver' if 1== 'condition' else 'hello'
這里一行代碼等價於這么寫:
if 1=='condition' :
subcommand = 'runserver'
else:
subcommand = 'hello'
這里一行代碼搞定,看起來不錯。
希望這篇文字可以幫助到大家。剛接觸python,若是有不對的地方,歡迎指出。謝謝。