在嵌入式智能小車項目中,涉及到很多模塊的控制,比如小車的移動方式,避障以及循跡導航等,這就涉及到更高級的編程策略,需要用到模塊化編程,面向對象思想以及多線程運行方式。
1,模塊化編程相關內容:
在python中,將一些常用變量,方法等定義到.py文件中,之後在編程的時候通過import該文件,進而調用該文件中的方法的方式即爲模塊化編程,而這個被調用文件即爲模塊。python中有很多標準庫,可以直接拿來用,不用自己定義,比如sys,math,最爲出色的就是機器學習相關的一些庫,如scikit-learn,pandas等
在我們自定的模塊調用中,需要將待調用的文件放到當前文件目錄或者python的系統搜索路徑(import sys; print sys.path獲取)中,下面是對於標準庫和自定義模塊的示例:
代碼文件 | 測試輸出 |
#!/usr/bin/python3 # 文件名: using_sys.py import sys #標準庫 print('命令行參數如下:') for i in sys.argv: print(i) print('\n\nPython 路徑爲:', sys.path, '\n') |
$python using_sys.py param1 param2 -->output: 命令行參數如下: using_sys.py param1 param2 |
#!/usr/bin/python3 # 文件名: support.py #自定義模塊庫 def print_func( par ): print ("Hello : ", par) return #!/usr/bin/python3 # test.py 調用模塊 import support # 導入模塊 # 調用模塊裏包含的函數 support.print_func("Runoob") |
$python test.py -->output Hello: Runoob |
直接import modulename則可通過modulename.function()方式調用模塊函數,或者可以通過from .... import僅調用我們需要的模塊,比如斐波那契(fibonacci)數列模塊名爲fibo,包含函數fib(n) & fib2(n),用法1:import fibo ; fibo.fib(20) 調用 用法2:from fibo import fib ; fib(20)調用(from modulename import *則是導入該模塊中的所有函數)
- 特點:
__name__屬性:模塊被引入時,若要模塊中的某一程序塊不執行,可以用__name__屬性來使該程序塊僅在該模塊自身運行時執行。
dir()函數:內置的函數 dir() 可以找到模塊內定義的所有名稱。以一個字符串列表的形式返回: >>>dir(fibo) -->output: ['__name__', 'fib', 'fib2']
- 包:包是一種管理 Python 模塊命名空間的形式,採用"點模塊名稱"
比如一個模塊的名稱是 A.B, 那麼他表示一個包 A中的子模塊 B
比如下面對音頻處理的包結構:
sound/ | 頂層包 |
__init__.py formats/ __init__.py wavread.py wavwrite.py 。。。 |
初始化sound包 文件轉換格式子包
|
effects/ __init__.py echo.py 。。。 |
聲音效果子包
|
這樣我們就擁有了幾個功能耦合性較高的模塊組合,如我們可以採用import sound.effects.echo方式來導入echo模塊
2,python面向對象編程:顧名思義就是面向實體對象的編程,把需要用到的方法等和一個個對象實例——類結合起來
在python中類的定義以及參考示例如下表所示:
語法格式如下: class ClassName: <statement-1> . . . <statement-N> |
類對象支持兩種操作:屬性引用和實例化 屬性引用標準語法: object.name |
簡單示例: #!/usr/bin/python3 #類定義 class people: #定義基本屬性 name = '' age = 0 #定義私有屬性,私有屬性在類外部無法直接進行訪問 __weight = 0 #定義構造方法 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s 說: 我 %d 歲。" %(self.name,self.age)) # 實例化類 p = people('runoob',10,30) p.speak() #輸出:runoob 說: 我 10 歲 |
---類有一個名爲 __init__() 的特殊方法(構造方法)該方法在類實例化時會自動調用 ---類的方法與普通的函數只有一個特別的區別——它們必須有一個額外的第一個參數名稱, 按照慣例它的名稱是 self |
- python面向對象編程滿足一般面向對象編程的特點:繼承,方法重寫等,具體示例及說明如下表:
#!/usr/bin/python3 #類定義 class people: #定義基本屬性 name = '' age = 0 #定義私有屬性,私有屬性在類外部無法直接進行訪問 __weight = 0 #定義構造方法 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s 說: 我 %d 歲。" %(self.name,self.age)) #單繼承示例 class student(people): grade = '' def __init__(self,n,a,w,g): #調用父類的構函 people.__init__(self,n,a,w) self.grade = g def speak(self): #覆寫父類的方法 print("%s 說: 我 %d 歲了,我在讀 %d 年級"%(self.name,self.age,self.grade)) s = student('ken',10,60,3) s.speak() #輸出:ken 說: 我 10 歲了,我在讀 3 年級 |
類的繼承格式如下: class DerivedClassName(BaseClassName1): <statement-1> . . . <statement-N> BaseClassName(示例中的基類名)必須與派生類定義在一個作用域內。除了類,還可以用表達式,基類定義在另一個模塊中時這一點非常有用: class DerivedClassName(modname.BaseClassName):
PS:注意圓括號中基類的順序,若是基類中有相同的方法名,而在子類使用時未指定,python從左至右搜索 即方法在子類中未找到時,從左到右查找基類中是否包含方法 |
在上面示例中再加入一個類,演示多繼承: #另一個類,多重繼承之前的準備 class speaker(): topic = '' name = '' def __init__(self,n,t): self.name = n self.topic = t def speak(self): print("我叫 %s,我是一個演說家,我演講的主題是 %s"%(self.name,self.topic)) #多重繼承 class sample(speaker,student): a ='' def __init__(self,n,a,w,g,t): student.__init__(self,n,a,w,g) speaker.__init__(self,n,t) test = sample("Tim",25,80,4,"Python") test.speak() |
Python同樣有限的支持多繼承形式: class DerivedClassName(Base1, Base2, Base3): <statement-1> . . . <statement-N> !!圓括號中父類的順序,若是父類中有相同的方法名,而在子類使用時未指定,python從左至右搜索 即方法在子類中未找到時,從左到右查找父類中是否包含方法
#方法名同,默認調用的是在括號中排前地父類的方法: ---左邊程序輸出: 我叫 Tim,我是一個演說家,我演講的主題是 Python |
#!/usr/bin/python3 class Parent: # 定義父類 def myMethod(self): print ('調用父類方法') class Child(Parent): # 定義子類 def myMethod(self): print ('調用子類方法') c = Child() # 子類實例 c.myMethod() # 子類調用重寫方法 super(Child,c).myMethod() #用子類對象調用父類已被覆蓋的方法 |
如果父類方法不能滿足需求,就需要方法重寫, 示例如左邊示例所示 輸出結果: 調用子類方法 調用父類方法 |
- python類還有一些專有方法,相當於C/C++中的運算符函數,有:
專有方法 | 運算符重載示例 |
|
#!/usr/bin/python3 class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): return 'Vector (%d, %d)' % (self.a, self.b) def __add__(self,other): return Vector(self.a + other.a, self.b + other.b) v1 = Vector(2,10) v2 = Vector(5,-2) print (v1 + v2) 輸出:Vector(7,8) |
3,這一篇最後一部分是關於python的多線程總結:
Python的標準庫提供了兩個模塊:_thread
和threading
,_thread
是低級模塊,threading
是高級模塊,對_thread
進行了封裝。多數情況下,我們只需要用threading
模塊,啓動線程就是傳入函數,創建Thread實例,調用start運行,下面是一個示例:
import time, threading # 新線程執行的代碼: print('thread %s is running...' % threading.current_thread().name) |
輸出:
|
import time, threading balance = 0 lock = threading.Lock() def change_it(n): def run_thread(n): |
多線程中,所有變量都由所有線程共享,存在一個危險在於多個線程同時改一個變量,把內容給改亂了,這裏通過加鎖來防止髒數據的出現 |
在智能小車項目中最常使用的內容是面向對象得線程編程,涉及到模塊的線程啓動,暫停等操作,還需要注意一個無限循環的線程問題:
|
左邊是控制線程啓動暫停地demo |
|
左邊是實際小車控制發動機轉動的無限循環線程的控制方式,通過全局變量來控制線程調用函數得持續執行 |
python部分除了後面需要小車上的樹莓派主板與遠程控制桌面連接需要用到一點網絡編程得東西,基本上涉及到的內容就以上兩篇博客提到的內容了