python本身添加了些全局變量python
print(vars()) """
結果: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00795650>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'C:/Users/Sullivan/PycharmProjects/q1/day12/global.py', '__cached__': None} """
這些全局變量的做用緩存
#__doc__ 包含py文件的註釋,文件的註釋在——文件內容的最上面用三引號引發來 print(__doc__) #__file__ 包含當前文件的路徑 print(__file__) #__package__ 對於單讀文件的package是沒有意義的,表明當前的py文件在哪幾個文件夾下 print(__package__)#當前文件沒有,會返回None from day2 import homework print(homework.__package__) #文件夾套文件夾時用點"."區分 #結果:day2 #__cached__ 緩存,對於py文件是能夠設置一個緩存的,python2裏沒有,瞭解便可 print(__cached__)#當前文件也有,會返回None from day2 import homework print(homework.__cached__) #結果:C:\Users\Sullivan\PycharmProjects\q1\day2\__pycache__\homework.cpython-36.pyc #__name__ 若是當前執行的是當前文件,它的__name__就是__main__,其它的不論是導入仍是其它的操做__name__就是文件名 print(__name__) #結果__main__ from day2 import homework print(homework.__name__) #結果:day2.homework #__builtins__ 裏邊放的就是內置函數 #__loader__和__spec__ 都是p3中新加的
# 由於程序的入口文件就是用戶當前執行的文件,因此之後寫主程序文件的時候 if __name__ == "__main__": execute() #防止其餘文件導入該文件時,執行主函數
#利用sys,os模塊和__file__變量,把路徑添加到system path中 import os,sys p1 = os.path.dirname(__file__) #獲取當前路徑 p2 = "bin" my_dir = os.path.join(p1,p2) #字符串拼接,拼接出新路徑 sys.path.append(my_dir) #添加到system path裏面
Python參數傳遞 有引用傳遞&值傳遞兩種併發
值傳遞:方法調用時,實際參數把它的值傳遞給對應的形式參數,方法執行中形式參數值的改變不影響實際參數的值。app
a1 = 520 a2 = a1 print(a1,a2) 結果:520 520 a2 = a1 + 1 print(a1,a2) 結果:520 521
引用傳遞:也稱地址傳遞,在方法調用時,其實是把參數的引用(傳的是地址,而不是參數的值)傳遞給方法中對應的形式參數,在方法執行中,對形式參數的操做實際上就是對實際參數的操做,方法執行中形式參數值的改變將會影響實際參數的值。ide
a1 = [1,2] a2 = a1 a2.append(3) print(a1) 結果:[1, 2, 3] print(a2) 結果:[1, 2, 3]
在Python中,數字、字符或者元組等不可變對象類型都屬於值傳遞,而字典dict或者列表list等可變對象類型屬於引用傳遞。函數
若是要想修改新賦值後原對象不變,則須要用到python的copy模塊,即對象拷貝。對象拷貝又包含淺拷貝和深拷貝。下面用例子來講明ui
例一spa
import copy l1 = [[1, 2], 3] l2 = copy.copy(l1) l2.append(4) #由於淺拷貝之拷貝第一層,因此對第一層操做不會影響l1 l2[0].append(5) #由於淺拷貝只拷貝的第一層,因此對第二層的操做仍是值傳遞,因此l1和l2中都有列表的第一個元素都會添加一個5 print(l1) print(l2) 結果: [[1, 2, 5], 3] [[1, 2, 5], 3, 4]
例二code
l1 = [[1, 2], 3] l3 = copy.deepcopy(l1) l3[0].append(6) print(l1) print(l3) #深拷貝所有拷貝,因此只是l3的值變了,l1並無改變 # 結果: [[1, 2], 3] [[1, 2, 6], 3]
從上例能夠看出,copy.copy屬於淺拷貝,拷貝的是第一層list,而copy.deepcopy屬於深拷貝,對list全部子元素都進行深拷貝。 orm
Python的字符串格式化有兩種方式: 百分號方式、format方式
百分號的方式相對來講比較老,而format方式則是比較先進的方式,企圖替換古老的方式,目前二者並存。
%[(name)][flags][width].[precision]typecode
注:Python中百分號格式化是不存在自動將整數轉換成二進制表示的方式
功能示例:
# %[(name)][flags][width].[precision]typecode s = ["i am %s,age %d" % ('ciri',18)] # (name) s = "i am %(n1)s,age %(n2)d" % {"n1":"ciri","n2":16} s = "i am %(n1)s,age %(n1)s" % {"n1":"ciri"} #也能夠兩個共用一個值 #flags和width通常放到一塊兒用,通常用不到 #字符 s = "i am %(n1)+10s ellie" % {"n1":"ciri"} s = "i am %(n1)-10s ellie" % {"n1":"ciri"} s = "i am %(n1) 10s ellie" % {"n1":"ciri"} s = "i am %(n1)010s ellie" % {"n1":"ciri"} #數字 s = "age %(n2)+10d ellie" % {"n2":16} s = "age %(n2)+10d ellie" % {"n2":-16} s = "age %(n2)-10d ellie" % {"n2":16} s = "age %(n2)-10d ellie" % {"n2":-16} s = "age %(n2) 10d ellie" % {"n2":16} s = "age %(n2) 10d ellie" % {"n2":-16} s = "age %(n2)010d ellie" % {"n2":16} s = "age %(n2)010d ellie" % {"n2":-16} #precision——默認輸出6位小數 s = "age %f ellie" % 1.2 s = "age %.2f ellie" % 1.2 #指定小數保留幾位
經常使用格式化:
tpl = "i am %s" % "alex" tpl = "i am %s age %d" % ("alex", 18) tpl = "i am %(name)s age %(age)d" % {"name": "alex", "age": 18} tpl = "percent %.2f" % 99.97623 tpl = "i am %(pp).2f" % {"pp": 123.425556, } tpl = "i am %.2f %%" % {"pp": 123.425556, }
[[fill]align][sign][#][0][width][,][.precision][type]
都是中括號[],因此參數均可以省略
經常使用格式化:
# [[fill]align][sign][#][0][width][,][.precision][type] tpl = "i am {}, age {}".format("seven", 18) tpl = "i am {}, age {}".format(*["seven", 18,'ciri']) #傳入列表,列表的元素能夠比前面的內容所 #能夠傳索引 tpl = "i am {0}, age {1}".format("seven", 18) tpl = "i am {0}, age {1}".format(*["seven", 18]) #經過name獲取 tpl = "i am {name}, age {age}".format(name="seven", age=18) tpl = "i am {name}, age {age}".format(**{"name": "seven", "age": 18})#傳字典要穿加上** #第一個0表示拿第幾個元素 tpl = "i am {0[0]}, age {0[1]}".format([1, 2, 3], [11, 22, 33]) #分別接收字符串、數字和浮點數 tpl = "i am {:s}, age {:d}, money {:f}".format("seven", 18, 88888.1) tpl = "i am {:s}, age {:d}".format(*["seven", 18]) tpl = "i am {name:s}, age {age:d}".format(name="seven", age=18) tpl = "i am {name:s}, age {age:d}".format(**{"name": "seven", "age": 18}) tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2) tpl = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15) tpl = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15)
# 先到 for x in range(10) 取元素,再把取出來的元素按照 前面的內容(x,x+1,x*2) 進行操做,而後把結果依次放到列表中
a = [x for x in range(10)] print(a) a = [x+1 for x in range(10)] print(a) a = [x*2 for x in range(10)] print(a) 結果: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10
賦值一種方法
t = ('ciri',8) a,b = t #值和變量的個數要相同,不然會報錯 print(a) print(b) 結果: ciri 8
方法一:小括號的方式
#把列表生成式的中括號,改爲小括號,就變成了一個生成器 s = (x for x in range(10)) print(s) # <generator object <genexpr> at 0x03726360> #輸出的是一個生成器對象,全部的值壓根就沒有被建立出來(重點)
以前的列表生成式生成了10個值,就至關於10盤菜,已經作出來了,想何時成就何時吃,想何時調動就何時調用,想吃第幾道就吃第幾道。
生成器就至關於,廚師腦子裏的10道菜,想吃的時候才作出來,你不吃就不會作出來,只能按順序吃(0,1...8,9),不能隔着吃,也不能倒着吃
方法二:yield方式
def func(): print('ok') yield 1 print('ok2') yield 2 print(func) # <function func at 0x03163540> 能夠看出func仍是一個函數 func() #不會執行函數,此時func()是一個生成器對象 print(func()) # <generator object func at 0x034764B0> 能夠看出 func加上括號() 是一個生成器對象
yield的執行過程
def func(): print('ok') yield 1 print('ok2') yield 2 next(func()) next(func()) 結果: ok ok2 for i in func(): print(i) 結果: ok 1 ok2 2
s = (x for x in range(10)) print(s) # 方法一: print(s.__next__())#內部特殊的方法,不建議用 # 方法二: #python3中新加的方法 print(next(s)) #之後就用這種方法 # 方法三: #python2中能夠直接調用next方法 print(s.next) # 方法四: for i in s: print(i) #for就是內部調用next方法
def fib(max): n,b,a = 0,0,1 while n<max: print(b) #最開始的值 yield b b, a = a, b + a #會先把b+a計算出來 n = n + 1 g = fib(8) next(g) next(g) next(g) next(g)
b, a = a, b + a爲何這個能夠,把a的值賦值給b,b+a的值賦值給a b = a a = b + a 這個不行 #由於b, a = a, b + a會先計算出來b+a的值
send和next的區別就是,send能夠給yield前面的變量傳值
def bar(): print('ok') count = yield 1 print(count) #第二次進來,就會直接把send的值,直接傳給yield前的參數count yield 2 b = bar() #b.send('ciri') 會報錯,由於第一次進來,執行到到yield就凍結了,出去了,因此第一次不知道給誰賦值,因此就不能用send傳參數 ret1 = b.send(None) #用send第一次進入時,只能這麼寫,等價於next(b) print(ret1) #結果 1 ret2 = b.send('ciri') print(ret2) #結果:2
#作和吃是同時發生的 import time def consumer(name): print("%s 準備吃包子啦!" % name) while True: baozi = yield print("包子[%s]來了,被[%s]吃了!" %(baozi,name)) def producer(name): c = consumer('A') c2 = consumer('B') next(c) next(c2) print("老子開始準備作包子了") for i in range(10): time.sleep(1) print("作了2個包子") c.send(i) c2.send(i) producer("ciri")
生成器都是迭代器,迭代器不必定是生成器
如何建立一個迭代器?
#iter方法就作一件事情,返回了一個迭代器對象 li = [1,2,3,4] d = iter(li) print(d) # <list_iterator object at 0x034A4770> iterator迭代器,iterable可迭代對象
什麼是迭代器?
知足兩個條件:1.有iter方法 2.有next方法
for循環後面加的是什麼?
可迭代對象
什麼是可迭代對象?
現象上——能進行 for循環的,都是可迭代對象
本質上——內部有iter方法的,就是可迭代對象
執行迭代器
li = [1,2,3,4] d = iter(li) #iter方法就作了一件事情,返回了一個迭代器對象 print(next(d)) print(next(d))
補充:for循環 執行時的內部操做三件事
實例:操做文件
f = open('abc.txt','r') for i in f.readlines(): #假如文件很大的話,會所有都放到內存中去 pass for i in f(): #這裏的f就是一個可迭代對象,節省內存空間 pass
練習:使用文件讀取,找出文件中最長的行
max(len(x.strip()) for x in open('/hello/abc','r'))
Python的字符串格式化有兩種方式: 百分號方式、format方式
百分號的方式相對來講比較老,而format方式則是比較先進的方式,企圖替換古老的方式,目前二者並存。