Python學習日記(十)—— 雜貨鋪(全局變量補充、Python參數傳遞、字符串格式化、迭代器、生成器)

全局變量補充

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()
    #防止其餘文件導入該文件時,執行主函數
name的實際應用
#利用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裏面
file的實際應用

Python參數傳遞

 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
  • (name)      可選,用於選擇指定的key
  • flags          可選,可供選擇的值有:
    • +       右對齊;正數前加正好,負數前加負號;只有這個會在輸出後給整數加上正號(+)
    • -        左對齊;正數前無符號,負數前加負號;
    • 空格    右對齊;正數前加空格,負數前加負號;
    • 0        右對齊;正數前無符號,負數前加負號;用0填充空白處
  • width         可選,佔有寬度
  • .precision   可選,小數點後保留的位數
  • typecode    必選
    • s,獲取傳入對象的__str__方法的返回值,並將其格式化到指定位置
    • r,獲取傳入對象的__repr__方法的返回值,並將其格式化到指定位置
    • c,整數:將數字轉換成其unicode對應的值,10進制範圍爲 0 <= i <= 1114111(py27則只支持0-255);字符:將字符添加到指定位置
    • o,將整數轉換成 八  進製表示,並將其格式化到指定位置
    • x,將整數轉換成十六進制表示,並將其格式化到指定位置
    • d,將整數、浮點數轉換成 十 進製表示,並將其格式化到指定位置
    • e,將整數、浮點數轉換成科學計數法,並將其格式化到指定位置(小寫e)
    • E,將整數、浮點數轉換成科學計數法,並將其格式化到指定位置(大寫E)
    • f, 將整數、浮點數轉換成浮點數表示,並將其格式化到指定位置(默認保留小數點後6位)
    • F,同上
    • g,自動調整將整數、浮點數轉換成 浮點型或科學計數法表示(超過6位數用科學計數法),並將其格式化到指定位置(若是是科學計數則是e;)
    • G,自動調整將整數、浮點數轉換成 浮點型或科學計數法表示(超過6位數用科學計數法),並將其格式化到指定位置(若是是科學計數則是E;)
    • %,當字符串中存在格式化標誌時,須要用 %%表示一個百分號

注: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, }

二、Format方式

[[fill]align][sign][#][0][width][,][.precision][type]
都是中括號[],因此參數均可以省略
  • fill           【可選】空白處填充的字符
  • align        【可選】對齊方式(需配合width使用)
    • <,內容左對齊
    • >,內容右對齊(默認)
    • =,內容右對齊,將符號放置在填充字符的左側,且只對數字類型有效。 即便:符號+填充物+數字
    • ^,內容居中
  • sign         【可選】有無符號數字
    • +,正號加正,負號加負;
    •  -,正號不變,負號加負;
    • 空格 ,正號空格,負號加負;
  • #            【可選】對於二進制、八進制、十六進制,若是加上#,會顯示 0b/0o/0x,不然不顯示
  • ,            【可選】爲數字添加分隔符,如:1,000,000
  • width       【可選】格式化位所佔寬度
  • .precision 【可選】小數位保留精度
  • type         【可選】格式化類型
    • 傳入」 字符串類型 「的參數
      • s,格式化字符串類型數據
      • 空白,未指定類型,則默認是None,同s
    • 傳入「 整數類型 」的參數
      • b,將10進制整數自動轉換成2進製表示而後格式化
      • c,將10進制整數自動轉換爲其對應的unicode字符
      • d,十進制整數
      • o,將10進制整數自動轉換成8進製表示而後格式化;
      • x,將10進制整數自動轉換成16進製表示而後格式化(小寫x)
      • X,將10進制整數自動轉換成16進製表示而後格式化(大寫X)
    • 傳入「 浮點型或小數類型 」的參數
      • e, 轉換爲科學計數法(小寫e)表示,而後格式化;
      • E, 轉換爲科學計數法(大寫E)表示,而後格式化;
      • f , 轉換爲浮點型(默認小數點後保留6位)表示,而後格式化;
      • F, 轉換爲浮點型(默認小數點後保留6位)表示,而後格式化;
      • g, 自動在e和f中切換
      • G, 自動在E和F中切換
      • %,顯示百分比(默認顯示小數點後6位)

 經常使用格式化:

# [[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)

生成器——generator

列表生成器

# 先到 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的值
補充:b, a = a, b + a爲何這個能夠

 send方法

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

實例:用yield實現僞併發

#作和吃是同時發生的
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")

迭代器——iterator  

生成器都是迭代器,迭代器不必定是生成器 

如何建立一個迭代器?

#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循環 執行時的內部操做三件事

  1.  調用可迭代對象的iter方法,返回一個迭代器對象
  2.  調用迭代器的next方法
  3.  處理stopiteration異常

實例:操做文件

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方式則是比較先進的方式,企圖替換古老的方式,目前二者並存。

相關文章
相關標籤/搜索