1.斷言
Python 的斷言語句是一種調試輔助功能,不是用來處理運行時錯誤的機制。python
assert 在條件爲 False 的時候觸發,後面的內容是報錯信息。緩存
import sys
assert sys.version_info >= (3, 7), "請在Python3.7及以上環境執行"
若是這個項目要求最低是 Python3.7 的環境,那麼若是使用 Python3.6 來運行這個項目,就會出現這個錯誤信息。數據結構
Traceback (most recent call last):
File "/Users/chennan/pythonproject/demo/nyandemo.py", line 3, in <module>
assert sys.version_info > (3, 7), "請在Python3.7以上環境執行"
AssertionError: 請在Python3.7以上環境執行
提早停止項目app
合理的格式化列表裏面的元素,更容易維護ssh
通常咱們在寫列表的時候會這樣ide
l = ["apple", "banana", "orange"]
使用下面的方式能夠更加清晰的區分每個項目,習慣性的在末尾加個逗號,防止下次添加元素遺漏了逗號,看着也更 Pythonic函數
l = [
"apple",
"banana",
"orange",
]
1.是一種約定,前置單下劃線的方法和變量只在內部使用命令行
2.在使用通配符導包的使用 from xx import * 這種,不用導入前置單下劃線的變量,除非定義了 __all__ 覆蓋了這個行爲。PEP8 通常不建議經過這種方式導包。翻譯
若是使用的變量名被 Python 中的關鍵字佔用,好比要聲明 class 這個變量,咱們這時候能夠在其後面加個單下劃線 class_調試
這個也是 PEP8 里約定的
前置雙下劃線會讓 Python 解釋器重寫屬性名稱,防止被子類中的命名覆蓋。
class Test:
def __init__(self):
self.foo = 11
self.__bar = 2
t = Test()
print(dir(t))
查看類的屬性能夠發現 self.__bar 變爲了 _Test__bar,這也稱之爲名稱改寫 (name mangling),解釋器會更改變量的名稱,防止拓展這個類型時命名衝突。
['_Test__bar', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'foo']
這個時候若是想訪問 __bar, 怎麼辦呢,咱們能夠經過 t._Test__bar進行訪問。
若是咱們繼承一下Test而後重寫 __bar會咋樣呢
class ExtendTest(Test):
def __init__(self):
super().__init__()
self.foo = "overridden"
self.__bar = "overridden"
et = ExtendTest()
print(et.foo)
print(et.__bar)
發現出現了錯誤
AttributeError: 'ExtendTest' object has no attribute '__bar'
緣由就是前面的同樣,由於解釋器把 __bar的名字給改了防止父類的這個變量被改寫了。
咱們能夠分別訪問這兩個類的 __bar發現他們是同時存在的,確實沒有被覆蓋。
print(et._Test__bar)
print(et._ExtendTest__bar)
獲得結果
2
overridden
順便說下 __bar 在英語中通常都是叫作 dunderbar。
除了雙下劃線的變量,雙下劃線的方法名也能夠被解釋器名稱改寫。
class ManglingMethod:
def __mangled(self):
return 42
def call_it(self):
return self.__mangled()
md = ManglingMethod()
md.call_it()
md.__mangled()
運行以後獲得出錯信息
AttributeError: 'ManglingMethod' object has no attribute '__mangled'
所謂的魔法方法,它的名稱不會被解釋器所改變,可是就命名約定而言最好避免使用這種形式變量和方法名
1._ 能夠表示變量是臨時的或者是可有可無的
for _ in rang(5):
print("hello")
2.在數字以前使用還能夠看成是千位分隔符
for i in range(1000_000):
print(i)
3.在解包元組的時候能夠看成是佔位符。
car = ("red", "auto", 12, 332.4 )
color,_,_,mileage = car
print(color)
print(_mileage)
4.若是使用命令行模式的話,_ 能夠獲取先前計算的結果
>>> 20+5
25
>>> _
25
>>> print(_)
25
咱們有如下代碼
def validate(name):
if len(name) < 10:
raise ValueError
若是在其餘文件中調用這個方法,
validate("lisa")
在不理解這個方法的做用的時候,若是名字驗證失敗時,調用棧會打印出如下信息
Traceback (most recent call last):
File "/Users/chennan/pythonproject/demo/nyandemo.py", line 57, in <module>
validate("lisa")
File "/Users/chennan/pythonproject/demo/nyandemo.py", line 55, in validate
raise ValueError
ValueError
這個棧調試回溯中的信息指出了,出現了錯誤的值,可是並不知道爲何出錯了,因此這個時候就須要跟進這個 validate 一探究竟,
這個時候咱們就能夠本身定義一個異常類
class NameTooShortException(ValueError):
def __str__(self):
return "輸入的名字長度必須大於等於10"
def validate(name):
if len(name) < 10:
raise NameTooShortException(name)
validate("lisa")
這樣若是再出現錯誤,就能夠知道爲何錯了,同時調用法也方便捕獲指定的異常,不用再使用 ValueError。
try:
validate("lisa")
except NameTooShortException as e:
print(e)
Cpython 解釋器執行時,首先將其翻譯成一系列的字節碼指令。字節碼是 Python 虛擬機的中間語言,能夠提升程序的執行效率
Cpython 不直接執行人類可讀的源碼,而是執行由編譯器解析和語法語義分析產生的緊湊的數、變量和引用。
這樣,再次執行相同程序時能節省時間和內存。由於編譯步驟產生的字節碼會以 .pyc 和 .pyo 文件的形式緩存在硬盤上,因此執行字節碼比再次執行相同的Python文件速度更快。
def greet(name):
return 'hello, ' + name + '!'
#__code__能夠獲取greet函數用到的虛擬機指令,常量和變量
gc = greet.__code__
print(gc.co_code) # 指令流
print(gc.co_consts) # 常量
print(gc.co_varnames) # 傳過來的參數
dis.dis(greet)
結果
b'd\x01|\x00\x17\x00d\x02\x17\x00S\x00'
(None, 'hello, ', '!')
('name',)
70 0 LOAD_CONST 1 ('hello, ')
2 LOAD_FAST 0 (name)
4 BINARY_ADD
6 LOAD_CONST 2 ('!')
8 BINARY_ADD
10 RETURN_VALUE
解釋器在索引1處('hello, ')查找常量,並放入棧中,而後將 name 的變量內容放入棧
Cpython 虛擬機是基於棧式虛擬機,棧就是虛擬機的內部數據結構。
棧只支持兩種動做:入棧和出棧
入棧:將一個值添加到棧頂
出棧:刪除並返回棧頂的值。
假設棧初始爲空,在執行前兩個操做碼(opcode)以後,虛擬的內容(0是最上面的元素)
好比咱們傳入的name爲lisa.
0: 'lisa'
1: 'hello, '
BINARY_ADD 指令從棧中彈出兩個字符串值,並將他們鏈接起來
而後再次將結果壓入棧中。
0:'hello, lisa'
而後由下一個 LOAD_CONST 將'!'壓入棧。
此時的結果
0:'!'
1:'hello, lisa'
下一個 BINARY_ADD 操做碼再次將這兩個字符串從棧中彈出並鏈接以後壓入棧,生成最終結果
0:'hello, lisa!'
最後字節碼 RETURN_VALUE ,告訴虛擬機當前位於棧頂的是該函數的返回值。