Python 一些有趣的技巧,包括協程例

1. 路徑操做

比起 os 模塊的 path 方法,python3 標準庫的 pathlib 模塊的 Path 處理起路徑更加的容易。 ####獲取當前文件路徑 前提導入 os 和 pathlib 包。。 os 版:php

print(os.path.dirname(__file__)) print(os.getcwd()) 

pathlib 版:css

print(pathlib.Path.cwd()) 

看着好像沒啥區別,而後看下面這個。html

獲取上兩級文件目錄

os 版python

print(os.path.dirname(os.path.dirname(os.getcwd()))) 

pathlib 版算法

print(pathlib.Path.cwd().parent.parent) 

拼接路徑

os 版編程

print(os.path.join(os.path.dirname(os.path.dirname(os.getcwd())),"yamls","a.yaml")) 

pathlib 版json

parts=["yamls","a.yaml"] print(pathlib.Path.cwd().parent.parent.joinpath(*parts)) 

運行時拼接路徑

os 版bash

os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'yamls',f'{site_name}.yaml') 

pathlib 版markdown

parts=["yamls","a.yaml"] print(pathlib.Path(__file__).resolve().parent.parent.joinpath(*parts)) 

另外 pathlib 生成的是個對象<class 'pathlib.PosixPath'>,在 open 文件操做中能夠直接運行的可是若是看成字符串操做會出現錯誤,此時須要對其進行轉換,使用 os.fspath()便可,不過通常不多有操做路徑字符串的習慣。 綜合起來,仍是 pathlib 拼接路徑方便。cookie

 

2. 保存標準格式的 yaml 文件

編程免不了要寫配置文件,怎麼寫配置也是一門學問。 YAML 是專門用來寫配置文件的語言,很是簡潔和強大,遠比 JSON 格式方便。 YAML 在 python 語言中有 PyYAML 安裝包。 前提安裝第三方庫

pip install pyaml pip install ruamel.yaml 

關於 yaml 的讀取知識網上一堆了我就不說了,這裏主要說寫入。

from ruamel import yaml data={"age":23,"sex":"男","name":"牛皮"} with open(conf_file, "w", encoding='utf-8') as fs: yaml.dump(data, fs, Dumper=yaml.RoundTripDumper, allow_unicode=True) 

yaml 寫文件和 json 同樣也是使用 dump。

 

3. 同時迭代兩個列表

之前的時候我是這麼解決的

a = ["a", "b", "c", "d"] b = [1, 2, 3] # 空的補充 None for index, a_item in enumerate(a): b_item = None if len(b) - 1 <= index: pass else: b_item = b[index] print({a_item:b_item}) 

如今我經過 itertools 標準庫的 zip 升級版 zip_longest 解決,能夠經過 fillvalue 參數補充缺失值。固然若是比較的元素個數相同能夠直接用 zip。




from itertools import zip_longest a = ["a", "b", "c", "d","e"] b = [1, 2, 3] # 空的補充 None for a_item, b_item in zip_longest(a,b,fillvalue=0): print({a_item:b_item})

4. 三元表達式還能這麼用?

通常的咱們這樣寫

a="hello" if 2>1 else "bye" print(a) 

咱們知道 python 中 false 實際式 0,true 是 1,因此對於上面的式子咱們就能夠這麼寫了。

a=["hello","bye"][2<1] print(a) 

由於 2<1 是 false 也就是 0,因此輸出了第一個元素 hello。

 

5.簡單的類使用 namedtuple 代替

先來一個簡單的例子

import collections # Person=collections.namedtuple('Person','name age') # 若是使用 python 中的關鍵字會出現錯誤,此時使用 rename 字段。 # 按照元素在元組中的下標賦值。class 就是_2,def 是_3 Person = collections.namedtuple('Person', ['name', 'age', 'class', 'def', 'name', 'name'], rename=True) p = Person(name='lisa', age='12', _2="class2", _3="def", _4="name2", _5="name3") print(p) # 若是出現相同的字段第二次出現的時候也是用其下標,參考上面的例子。 # _fields 查看字段名,能夠發現內置模塊和重複的字段標記爲_加下標的形式 print(p._fields) # 使用_asdict 將 namedtuple 轉爲 OrderedDict。 od = p._asdict() print(od) # 而後能夠轉爲字典 print(dict(od)) # _replace()方法構建一個新實例,由於 namedtuple 是不可變類型因此這個方法能夠返回一個新的對象。 new_p = p._replace(name="samJ") print(new_p) print(new_p is p) # 能夠看到不是同一個對象。 

一個實用的例子 pyppeteer 的例子感覺下

import asyncio import pyppeteer from collections import namedtuple Response = namedtuple("rs", "title url html cookies headers history status") async def get_html(url, timeout=30): # 默認 30s browser = await pyppeteer.launch(headless=True, args=['--no-sandbox']) page = await browser.newPage() res = await page.goto(url, options={'timeout': int(timeout * 1000)}) data = await page.content() title = await page.title() resp_cookies = await page.cookies() resp_headers = res.headers resp_history = None resp_status = res.status response = Response(title=title, url=url, html=data, cookies=resp_cookies, headers=resp_headers, history=resp_history, status=resp_status) return response if __name__ == '__main__': url_list = ["http://www.10086.cn/index/tj/index_220_220.html", "http://www.10010.com/net5/011/", "http://python.jobbole.com/87541/"] task = (get_html(url) for url in url_list) loop = asyncio.get_event_loop() results = loop.run_until_complete(asyncio.gather(*task)) for res in results: print(res.title) 

6 使用枚舉讓數字變得更易懂。

import enum


# 枚舉
@enum.unique
class Sex(enum.Enum):
    man = 12
    woman = 13

    # 由於加了惟一值的裝飾器因此下面添加屬性會報錯
    # boy=12


print(Sex.man.name)
print(Sex.woman.value)

# 遍歷
for item in Sex:
    print(item.name)
    print(item.value)
print("-" * 40)
# 其餘使用方式
words = enum.Enum(
    value='item',
    names=('a b c d e f'),
)
# 輸出元素 c,必須是上面 names 裏含有的值
print(words.c)
print(words.f)
# 由於 names 不含有 w 因此報錯
try:
    print(words.w)
except AttributeError as e:
    print(e.args)
print("-" * 40)
for word in words:
    print(word.name, word.value)  # 默認賦值爲、從 1 開始自增。
print("-" * 40)
# 若是自定義元素的值嘖改成一下元組的形式
words2 = enum.Enum(
    value='item2',
    names=[('a', 23), ('b', 56), ("c", 12), ("d", 333)]
)
for word2 in words2:
    print(word2.name, word2.value)

7 鏈式合併字典 chainmap 的使用

 

from collections import ChainMap

# ChainMap

d1 = {'a': 1, 'b': 2}
d2 = {'a2': 3, 'b2': 4}
d3 = {'a3': 5, 'b3': 6}
d4 = {'a4': 7, 'b4': 8}
c = ChainMap(d1, d2, d3, d4)  # 多個字典合併爲一個
for k, v in c.items():
    print(k, v)
print(c.maps)  # 要搜索的索引列表

c.maps = list(reversed(c.maps))  # 逆轉映射列表
print(c)

# 由於 c 和 d1-d4 對應的索引位置實際是一個因此,修改 c 的時候會影響到 d1 到 d4 其中餓的一個值,同理修改
# d1-d4 的時候也會影響到 c。
# 因此使用 new_child 建立一個新的映射。再修改就影響不到底層的數據了。
c2 = c.new_child()
c2["a4"] = 100
print(c)
print(c2)
# 輸出發現 c 的值沒有發生變化,只要 c2 變化。
d5 = {"a5": 34, "b5": 78}
c2 = c2.new_child(d5)  # 能夠在原來的映射基礎上添加新的映射
print(c2)

8 在不打亂列表順序的基礎上插入元素

import bisect

""" bisect 模塊,用於維護有序列表。 bisect 模塊實現了一個算法用於插入元素到有序列表。 在一些狀況下,這比反覆排序列表或構造一個大的列表再排序的效率更高。 Bisect 是二分法的意思,這裏使用二分法來排序,它會將一個元素插入到一個有序列表的合適位置, 這使得不須要每次調用 sort 的方式維護有序列表。 """
values = [14, 85, 77, 26, 50, 45, 66, 79, 10, 3, 84, 77, 1]
print("New Pos Content")
print("--- --- -------")
l = []
for i in values:
    postion = bisect.bisect(l, i)  # 返回插入的位置
    bisect.insort(l, i)  # 等於 insort_right
    print('{:3}{:3}'.format(i, postion), l)

""" Bisect 模塊提供的函數有: bisect.bisect_left(a,x, lo=0, hi=len(a)) : 查找在有序列表 a 中插入 x 的 index。lo 和 hi 用於指定列表的區間,默認是使用整個列表。若是 x 已經存在,在其左邊插入。返回值爲 index。 bisect.bisect_right(a,x, lo=0, hi=len(a)) bisect.bisect(a, x,lo=0, hi=len(a)) : 這 2 個函數和 bisect_left 相似,但若是 x 已經存在,在其右邊插入。 bisect.insort_left(a,x, lo=0, hi=len(a)) : 在有序列表 a 中插入 x。和 a.insert(bisect.bisect_left(a,x, lo, hi), x) 的效果相同。 bisect.insort_right(a,x, lo=0, hi=len(a)) bisect.insort(a, x,lo=0, hi=len(a)) : 和 insort_left 相似,但若是 x 已經存在,在其右邊插入。 Bisect 模塊提供的函數能夠分兩類:bisect* 只用於查找 index, 不進行實際的插入; 而 insort* 則用於實際插入。該模塊比較典型的應用是計算分數等級: """

8 關於字典的邏輯運算你瞭解多少

 

# 使用&操做符查看字典的相同之處
#字典鍵支持常見的集合操做,並集交集差集。
a = {'x': 1, 'y': 2, 'z': 3}
b = {'w': 2, 'z': 4, 'x': 3, 'z': 3}

# 獲取相同的鍵
c = a.keys() & b.keys()
print(c)
# 獲取相同的鍵值對
d = a.items() & b.items()
print(d)
# 建立一個新的字典並刪除某些鍵

e = {k: a[k] for k in a.keys() - {'z', 'x'}}
print(e)

9 給切片起個名字

a="safr3.14"
print(a[-4:])
#上面能夠改成
pie=slice(len(a)-4,len(a))
print(a)

10 獲取出現頻率高的元素

from collections import Counter

text = "abcdfegtehto;grgtgjri"  # 可迭代對象
lis = ["a", "c", "d", "t", "b"]
dic = {"a": 1, "b": 4, "c": 2, "d": 9}  # 字典也能夠
c = Counter()  # 能夠定義空容器而後 update
c.update(text)
c2 = Counter()
c2.update(dic)

c3 = Counter(lis)  # 也能夠直接傳入對象
print(c)
print(c2)
print(c3)

# 使用 c.most_comman(n)獲取前 n 出現頻率最高的元素,列表元組類型
print(c.most_common(4))

import enum # 枚舉@enum.uniqueclass Sex(enum.Enum): man = 12 woman = 13# 由於加了惟一值的裝飾器因此下面添加屬性會報錯# boy=12 print(Sex.man.name) print(Sex.woman.value) # 遍歷for item in Sex: print(item.name) print(item.value) print("-" * 40) # 其餘使用方式 words = enum.Enum( value='item', names=('a b c d e f'), ) # 輸出元素 c,必須是上面 names 裏含有的值 print(words.c) print(words.f) # 由於 names 不含有 w 因此報錯try: print(words.w) except AttributeError as e: print(e.args) print("-" * 40) for word in words: print(word.name, word.value) # 默認賦值爲、從 1 開始自增。 print("-" * 40) # 若是自定義元素的值嘖改成一下元組的形式 words2 = enum.Enum( value='item2', names=[('a', 23), ('b', 56), ("c", 12), ("d", 333)] ) for word2 in words2: print(word2.name, word2.value)

相關文章
相關標籤/搜索