Pythonic---------詳細講解

做者:半載流殤
連接:https://zhuanlan.zhihu.com/p/35219750
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

Pythonic,簡言之就是以Python這門語言獨特的方式寫出既簡潔又優美的代碼!筆者精心整理了許多實用的Python tricks,想要提升效率、寫出高質量的Python代碼的話此文必看。 注:請將Python更新到3.6版,方能完美運行本文的全部代碼。字符串格式化字符串在字符串前加f,就能夠在裏面用大括號嵌入變量了(能夠代替format函數)>>> a = 5
>>> b = 10
>>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'
'Five plus ten is 15 and not 30.'
字符串拼接>>> text = ['I', ' Love ', 'Python!']
>>> print(''.join(text))
I Love Python!
字符串的contains>>> 'ov' in 'love'
True
反轉元素>>> 'Love'[::-1]
'evoL'
>>> for e in reversed([1,3,5]): print(e)
5 3 1
去除非法字符串保存文件時,咱們必須去除一些非法字符串,此處利用any函數實現def rectify(name):
    if any(symbol in name for symbol in ['?', '<', '>', '|', '*', '"', ":"]):
        name = ''.join([c for c in name if c not in ['?', '<', '>', '|', '*', '"', ":"]])
    return name
HTML轉義>>> import html
>>> html.unescape('&lt')
'<'
>>> html.escape('<')
'&lt;'
函數可變參數*args:任意數量的位置參數,可被打包成元組。**kwargs:任意數量的關鍵詞參數,可被打包成字典。打包def foo(*args, **kwargs):
     print(f"args: {args}")
     print(f"kwargs: {kwargs}")

>>> foo(1,2,3,4, a=1,b=2,c=3)
args: (1, 2, 3, 4)
kwargs: {'a': 1, 'b': 2, 'c': 3}
解包def foo(x, y):
    print(x, y)

alist = [1, 2]
adict = {'x': 1, 'y': 2}

>>> foo(*alist)
1, 2
>>> foo(**adict)
1, 2
裝飾器裝飾器的主要用途:打印日誌、檢測性能、數據庫事務、URL路由它本質上就是一個高階函數,它接收一個函數做爲參數,而後,返回一個新函數。想理解裝飾器,就得知道如下兩點:1. 函數皆對象2. 閉包特性(內函數能捕捉到外函數的環境變量)簡單的日誌函數from datetime import datetime
import functools
def log(f):
    @functools.wraps(f)
    def wr(*args, **kwargs):
            print(f'call {f.__name__}() at {datetime.now()}')
            return f(*args, **kwargs)
    return wr

@log
def square(x):
    return x ** 2

>>> square(2)
call square() at 2018-01-24 11:01:19.547516
4
注意到爲了讓@deco自適應任何參數定義的函數,咱們將可變參數args, *kwargs做爲了wr的參數@functools.wraps(f)爲了防止wr的函數屬性覆蓋掉原函數的屬性,咱們必須利用@functools.wraps(f)來把原函數的全部屬性複製到新函數裏# 不加@functools.wraps(f)的狀況下
>>> square.__name__
'wr'
# 加了@functools.wraps(f)的狀況下
>>> square.__name__
'square'
若是想給裝飾器傳遞參數,那麼你必須利用閉包特性再嵌套一層函數,不過這並不經常使用。函數性能檢測def perf(f):
    @functools.wraps(f)
    def wr(*args, **kwargs):
            start = time.time()
            r = f(*args, **kwargs)
            end = time.time()
            print(f'call {f.__name__}() in {end - start}')
            return r
    return wr

@perf
def test(x):
    time.sleep(2)
    return x

>>> test(5)
call test() in 2.0007083415985107
5
數據庫的cursordef link_mysql(fun):
    def wr(*args, **kwargs):
        with pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=dbname, charset=charset) as cur:
            fun(cur, *args, **kwargs)
    return wr

@link_mysql
def insert_data(cur, ...):
    # execute your sql here.
上下文管理器應用文件操做(超經常使用)、進程互斥鎖和支持上下文的其餘對象目的是爲了代替try語句和簡化語法以文件操做爲例:利用它,文件會自動打開和關閉with open('/path/to/file', 'r') as f:
    handle_f
上下文語句支持嵌套(nested)例如將a文件的源數據寫入b文件裏:with open('a.txt') as i, open('b.txt') as o:
    o.write(i.read())
實質經過上下文管理協議__enter__和__exit__來實現Python有個庫contextlib利用生成器簡化了這種實現,如下是大致框架from contextlib import contextmanager

@contextmanager
def make_context() :
    # enter
    try:
        yield <value>
    except Exception as e:
        # handle_err
    finally:
        # exit

with make_context() as <value>:
    # handle_value
如下是with語句操做文件的實質因爲自定義,函數名用my_open,但功能和open幾乎同樣@contextmanager
def my_open(filename, mode):
    f = open(filename, mode)
    try:
        yield f
    except Exception as e:
        raise e
    finally:
        f.close()

with my_open('/path/to/file', 'r') as f:
    handle_f
偏函數partial()用於把一個函數的某些參數給固定住(也就是設置默認值),並返回一個新的函數。def int2(x, base=2):
    return int(x, base)
至關於:import functools
int2 = functools.partial(int, base=2)
數據結構元組元組是一個immutable對象,有如下重要性:- 性能優化- 線程安全- 能夠做爲dict的key(hashable)- 拆包特性元組拆包a, b = b, a兩個數字交換的原理就是它。如下是利用它來獲取文件名及其擴展名>>> import os
>>> filename, ext = os.path.splitext('patch.exe')
>>> filename
'patch'
>>> ext
'exe'
更多的解包方式(_表明捨棄,*表明可變長元組)>>> t = (1, 2, 3, 4)
>>> first, *middle, last = t
>>> middle
[2, 3]
>>> _, *rest = t
>>> rest
[2, 3, 4]
列表切片若是想要獲取列表的多個元素,就得用到切片list[start:stop:step]
你甚至能夠給切片命名,加強複用性和可讀性:s = slice(start,stop,step)
list[s]
切片的原理是序列協議class Seq:
    def __getitem__(self, index):
            return index

>>> s = Seq()
>>> s[1:5:2]
slice(1, 5, 2)
以上實現的是不可變序列協議,若是可變的話還要添加__setitem__()若是在運行時添加協議的話也行,這叫猴子補丁>>> def set_item(self, key, value):
        self[key] = value
>>> classname.__setitem__ = set_item
列表推導式這是Python最強大的幾個特徵之一。格式也很簡單,其中if條件能夠省略,for循環能夠有多個[i for i in iterable if condition]
10-20全部偶數的平方:[i*i for i in range(10, 21) if i % 2 == 0 ]
一行實現快排def qsort(arr):
    return arr if len(arr) <= 1 else qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]])
索引迭代enumerate()能夠把一個list變成索引-元素對。for i, value in enumerate(['A', 'B', 'C']):
    print(i, value) 
0 A 1 B 2 C
zipzip()能夠將可迭代的對象做爲參數,將對象中對應的元素打包成一個個元組,並返回一個迭代器,經常使用於同時遍歷兩個可迭代對象。>>> li1 = ['Python' ,'JavaScript', 'Java']
>>> li2 = [1, 2, 3]
>>> nl = zip(li1, li2)
<zip object at memory>
>>> list(nl)
[('Python', 1), ('JavaScript', 2), ('Java', 3)]
配合dict能夠生成字典>>> l1 = ['A', 'B', 'C']
>>> l2 = [1, 2, 3]
>>> dict(zip(l1, l2))
{'A': 1, 'B': 2, 'C': 3}
append和extend>>> x = [1, 2, 3]
>>> x.extend([4, 5])
>>> x
[1, 2, 3, 4, 5]
>>> x.append([6, 7])
>>> x
[1, 2, 3, 4, 5, [6, 7]]
集合運算首先將要比較的兩個list轉換爲set,再轉回list就好了>>> l1 = [1, 2, 3, 4]
>>> l2 = [2, 3, 5, 7]
>>> list(set(l1) & set(l2))
[2, 3]
>>> list(set(l1) | set(l2))
[1, 2, 3, 4, 5, 7]
>>> list(set(l1) ^ set(l2))
[1, 4, 5, 7]
字典本質是鍵值對哈希表get用來獲取某個鍵的值,不存在的話就用設置的default(默認爲None)>>> d = dict(a=1, b=2)
>>> d.get('a')
1
>>> d.get('c')
>>> d.get('d', 2)
2
合併>>> d1 = {'a':1, 'b':2}
>>> d2 = {'c':3, 'd':4}
>>> nd = {**d1, **d2}
>>> nd
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
相似的,列表也能夠這樣合併>>> l1 = [1, 2]
>>> l2 = [3, 4]
>>> l3 = [*l1, *l2]
>>> l3
[1, 2, 3, 4]
鍵值對反轉>>> kv = {'a': 1, 'b':2 , 'c': 3}
>>> vk = zip(kv.values(), kv.keys())
>>> dict(vk)
{1: 'a', 2: 'b', 3: 'c'}
>>> min(vk)
(1, 'a')
>>> sorted(vk)
[(1, 'a'), (2, 'b'), (3, 'c')]
鍵值排序>>> rows = [{k1: v1, k2: v2 ...}, ...]
>>> from operator import itemgetter
# 根據k1排序
>>> sorted(rows, key=itemgetter(k1))
# 相似的,對於class的對象能夠用attrgetter進行排序
集合運算>>> a = {'a': 1, 'b': 2, 'c': 3}
>>> b = {'x': 1, 'b': 2, 'c': 4}
>>> a.keys() & b.keys()
{'b', 'c'}
>>> a.keys() - b.keys()
{'a'}
>>> a.items() & b.items()
{('b', 2)}
其餘數據結構具名元組經常使用於構建簡單的類>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(x=11, y=22)
>>> p
Point(x=11, y=22)
>>> p.x + p.y
33
>>> coord = (33, 44)
>>> q = Point(*coord)
>>> q
Point(x=33, y=44)
默認值字典經常使用於統計數目>>> from collections import defaultdict
>>> words = ('python', 'java', 'ruby', 'python', 'C', 'java', 'C++', 'C')
>>> counts = defaultdict(int)
>>> for word in words:
...    counts[word] += 1
>>> counts
defaultdict(<class 'int'>, {'python': 2, 'java': 2, 'ruby': 1, 'C': 2, 'C++': 1})
雙向隊列>>> from collections import deque
>>> q = deque(["Eric", "John", "Michael"])
>>> q.append("Terry")
>>> q
deque(['Eric', 'John', 'Michael', 'Terry'])
>>> q.popleft()
Eric'
>>> q.pop()
'Terry'
>>> q
deque(['John', 'Michael'])
計數器>>> from collections import Counter
>>> c = Counter('hello world')
>>> c
Counter({'l': 3, 'o': 2, ' ': 1, 'e': 1, 'd': 1, 'h': 1, 'r': 1, 'w': 1})
>>> c.most_common(2)
[('l', 3), ('o', 2)]
堆>>> import heapq
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = list(heapq.merge(a, b))
>>> c
[1, 2, 3, 4, 5, 6]
>>> heapq.nlargest(3, c)
[6, 5, 4]
>>> heapq.nsmallest(3, c)
[1, 2, 3]
OOP只讀屬性能夠經過在變量名前加__來使其變成私有變量,外部沒法直接訪問,但能夠經過類定義的方法來訪問。class Person(object):
    def __init__(self, name):
            self.__name = name

    def get_name(self):
            return self.__name

    def set_name(self, name):
            self.__name = name

>>> p = Person('alphardex')
>>> p.name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'name'
>>> p.get_name()
'alphardex'
>>> p.set_name('wang')
>>> p.get_name()
'wang'
@property確定有的人不習慣經過方法來訪問私有變量,那麼如何用屬性來訪問私有變量呢?這時就要用到@property了,它能夠把一個方法變成屬性調用class Person(object):
    def __init__(self, name):
            self.__name = name

    @property
    def name(self):
            return self.__name

    @name.setter
    def name(self, value):
            self.__name = value

>>> p = Person('alphardex')
>>> p.name
'alphardex'
>>> p.name = 'wang'
>>> p.name
'wang'
slots當咱們定義了一個class並用其建立了一個實例後,能夠動態地給其綁定屬性,若是要限制這一點,能夠利用__slots__class Person(object):
    __slots__ = ('name', 'age')

>>> p = Person('wang')
>>> p.name = 'wang'
>>> p.age = 21
>>> p.skill = 'Python'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'skill'
魔術方法魔術方法能夠用來定製類的功能。好比__repr__用來調試時打印類的字符串class Person(object):
    def __init__(self, name, age):
            self.name = name
            self.age = age
    def __repr__(self):
            return f'<Person {self.name} age: {self.age}>'

>>> p = Person('alphardex', 21)
>>> p
<Person alphardex age: 21>
想了解更多魔術方法請參見官方文檔元類type俗話說道生一,一輩子二,二生三,三生萬物。在Python裏能夠這麼說:type生元類,元類生類,類生實例。用一個數字變量的建立來講明這一點吧>>> age = 21
>>> age.__class__
<class 'int'>
>>> age.__class__.__class__
<class 'type'>
age能夠看做爲int類的實例,而int類又能夠看作type類的實例。也就是說,type建立了int類,實際上諸如str和bool等類也是由type建立的。>>> help(type)
Help on class type in module builtins:

class type(object)
 |  type(object_or_name, bases, dict)
 |  type(object) -> the object's type
 |  type(name, bases, dict) -> a new type

def say_hello(self, name='world'):
    print(f'Hello, {name}')

>>> Hello = type('Hello', (object,), dict(hello=say_hello))
>>> h = Hello()
>>> type(Hello)
<class 'type'>
>>> type(h)
<class '__main__.Hello'>
經過用help查看type,能夠發現它確實能動態地建立類:第一個參數是類名name,第二個參數是基類bases,第三個參數是dict,裏面包含着類的全部方法。實際上,type是Python的一個內置元類。自定義元類固然,你也能夠利用type來定義本身的元類。class JSArrayMeta(type):
    def __new__(cls, name, bases, attrs):
            attrs['push'] = lambda self, value: self.append(value)
            attrs['shift'] = lambda self: self.pop(0)
            attrs['includes'] = lambda self, value: value in self
            return type.__new__(cls, name, bases, attrs)

class JSList(list, metaclass=JSArrayMeta):
    def __init__(self, value):
            self.extend(value)

>>> l = JSList([1, 2, 3])
>>> l
[1, 2, 3]
>>> l.push('a')
>>> l
[1, 2, 3, 'a']
>>> l.shift()
1
>>> l
[2, 3, 'a']
>>> l.includes(3)
True
咱們首先定製了一個元類,叫JSArrayMetaclass(沒錯就是JS裏的數組XD)注意元類的命名規則:結尾必定要有Meta做爲識別__new__方法用來建立JSList類,它接受4個參數JSList繼承了list類,同時得到了元類的全部方法其餘加載內置模塊利用-m參數,咱們能夠直接加載Python的模塊# 搭建http服務器
$ python -m http.server
# 建立虛擬環境
$ python -m venv <name>
# 性能測試
$ python -m cProfile <file.py>
# 查看JSON
$ cat <file.json> | python -m json.tool
數據序列化import pickle
data = ... # Some Python object
# 存儲
with open(f'{file}.pickle', 'wb') as f:
    pickle.dump(data, f)
# 讀取
with open(f'{file}.pickle', 'rb') as f:
    data = pickle.load(f)
數據分析利用pandas模塊能夠對數據進行分析$ pip install pandas
>>> import pandas as pd
>>> data = pd.read_csv(...)
# 數據查看
>>> data.columns              # 查看數據結構
>>> data.describe()           # 簡要數據分析
>>> data.sort_values(by=...)  # 對數據排序
# 數據選取
>>> data.head()               # 查看前五條數據
>>> data.iloc[n]              # 選擇位置爲n的數據,支持切片
>>> data[data.A > 0]          # 選擇A欄大於0的數據
>>> data[data.B.isin([...])]  # 利用in過濾數據
>>> data[~data.B.isin([...])] # 上一句的取反,至關於not in
# 缺失值處理
>>> pd.isna(data)             # 獲取缺失值的布爾標記
>>> data.dropna(how='any')    # 去除全部含有缺失值的欄
>>> data.fillna(value=5)      # 填充全部含有缺失值的欄
# 數據保存(能夠相互轉換格式,支持excel、csv和json)
>>> data.to_json(...)

 

做者:半載流殤
連接:https://zhuanlan.zhihu.com/p/35219750
來源:知乎
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

Pythonic,簡言之就是以Python這門語言獨特的方式寫出既簡潔又優美的代碼!筆者精心整理了許多實用的Python tricks,想要提升效率、寫出高質量的Python代碼的話此文必看。 html

注:請將Python更新到3.6版,方能完美運行本文的全部代碼。java

字符串

格式化字符串

在字符串前加f,就能夠在裏面用大括號嵌入變量了(能夠代替format函數)python

>>> a = 5
>>> b = 10
>>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'
'Five plus ten is 15 and not 30.'

字符串拼接

>>> text = ['I', ' Love ', 'Python!']
>>> print(''.join(text))
I Love Python!

字符串的contains

>>> 'ov' in 'love'
True

反轉元素

>>> 'Love'[::-1]
'evoL'
>>> for e in reversed([1,3,5]): print(e)
5 3 1

去除非法字符串

保存文件時,咱們必須去除一些非法字符串,此處利用any函數實現mysql

def rectify(name):
    if any(symbol in name for symbol in ['?', '<', '>', '|', '*', '"', ":"]):
        name = ''.join([c for c in name if c not in ['?', '<', '>', '|', '*', '"', ":"]])
    return name

HTML轉義

>>> import html
>>> html.unescape('&lt')
'<'
>>> html.escape('<')
'&lt;'

函數

可變參數

*args:任意數量的位置參數,可被打包成元組。
**kwargs:任意數量的關鍵詞參數,可被打包成字典。sql

打包

def foo(*args, **kwargs):
     print(f"args: {args}")
     print(f"kwargs: {kwargs}")

>>> foo(1,2,3,4, a=1,b=2,c=3)
args: (1, 2, 3, 4)
kwargs: {'a': 1, 'b': 2, 'c': 3}

解包

def foo(x, y):
    print(x, y)

alist = [1, 2]
adict = {'x': 1, 'y': 2}

>>> foo(*alist)
1, 2
>>> foo(**adict)
1, 2

裝飾器

裝飾器的主要用途:打印日誌、檢測性能、數據庫事務、URL路由
它本質上就是一個高階函數,它接收一個函數做爲參數,而後,返回一個新函數。
想理解裝飾器,就得知道如下兩點:
1. 函數皆對象
2. 閉包特性(內函數能捕捉到外函數的環境變量)數據庫

簡單的日誌函數

from datetime import datetime
import functools
def log(f):
    @functools.wraps(f)
    def wr(*args, **kwargs):
            print(f'call {f.__name__}() at {datetime.now()}')
            return f(*args, **kwargs)
    return wr

@log
def square(x):
    return x ** 2

>>> square(2)
call square() at 2018-01-24 11:01:19.547516
4

注意到爲了讓@deco自適應任何參數定義的函數,咱們將可變參數args, *kwargs做爲了wr的參數json

@functools.wraps(f)

爲了防止wr的函數屬性覆蓋掉原函數的屬性,咱們必須利用@functools.wraps(f)來把原函數的全部屬性複製到新函數裏數組

# 不加@functools.wraps(f)的狀況下
>>> square.__name__
'wr'
# 加了@functools.wraps(f)的狀況下
>>> square.__name__
'square'

若是想給裝飾器傳遞參數,那麼你必須利用閉包特性再嵌套一層函數,不過這並不經常使用。安全

函數性能檢測

def perf(f):
    @functools.wraps(f)
    def wr(*args, **kwargs):
            start = time.time()
            r = f(*args, **kwargs)
            end = time.time()
            print(f'call {f.__name__}() in {end - start}')
            return r
    return wr

@perf
def test(x):
    time.sleep(2)
    return x

>>> test(5)
call test() in 2.0007083415985107
5

數據庫的cursor

def link_mysql(fun):
    def wr(*args, **kwargs):
        with pymysql.connect(host=host, port=port, user=user, passwd=passwd, db=dbname, charset=charset) as cur:
            fun(cur, *args, **kwargs)
    return wr

@link_mysql
def insert_data(cur, ...):
    # execute your sql here.

上下文管理器

應用

文件操做(超經常使用)、進程互斥鎖和支持上下文的其餘對象
目的是爲了代替try語句和簡化語法
以文件操做爲例:利用它,文件會自動打開和關閉ruby

with open('/path/to/file', 'r') as f:
    handle_f

上下文語句支持嵌套(nested)
例如將a文件的源數據寫入b文件裏:

with open('a.txt') as i, open('b.txt') as o:
    o.write(i.read())

實質

經過上下文管理協議__enter__和__exit__來實現
Python有個庫contextlib利用生成器簡化了這種實現,如下是大致框架

from contextlib import contextmanager

@contextmanager
def make_context() :
    # enter
    try:
        yield <value>
    except Exception as e:
        # handle_err
    finally:
        # exit

with make_context() as <value>:
    # handle_value

如下是with語句操做文件的實質
因爲自定義,函數名用my_open,但功能和open幾乎同樣

@contextmanager
def my_open(filename, mode):
    f = open(filename, mode)
    try:
        yield f
    except Exception as e:
        raise e
    finally:
        f.close()

with my_open('/path/to/file', 'r') as f:
    handle_f

偏函數

partial()用於把一個函數的某些參數給固定住(也就是設置默認值),並返回一個新的函數。

def int2(x, base=2):
    return int(x, base)

至關於:

import functools
int2 = functools.partial(int, base=2)

數據結構

元組

元組是一個immutable對象,有如下重要性:
- 性能優化
- 線程安全
- 能夠做爲dict的key(hashable)
- 拆包特性

元組拆包

a, b = b, a
兩個數字交換的原理就是它。
如下是利用它來獲取文件名及其擴展名

>>> import os
>>> filename, ext = os.path.splitext('patch.exe')
>>> filename
'patch'
>>> ext
'exe'

更多的解包方式(_表明捨棄,*表明可變長元組)

>>> t = (1, 2, 3, 4)
>>> first, *middle, last = t
>>> middle
[2, 3]
>>> _, *rest = t
>>> rest
[2, 3, 4]

列表

切片

若是想要獲取列表的多個元素,就得用到切片

list[start:stop:step]

你甚至能夠給切片命名,加強複用性和可讀性:

s = slice(start,stop,step)
list[s]

切片的原理是序列協議

class Seq:
    def __getitem__(self, index):
            return index

>>> s = Seq()
>>> s[1:5:2]
slice(1, 5, 2)

以上實現的是不可變序列協議,若是可變的話還要添加__setitem__()
若是在運行時添加協議的話也行,這叫猴子補丁

>>> def set_item(self, key, value):
        self[key] = value
>>> classname.__setitem__ = set_item

列表推導式

這是Python最強大的幾個特徵之一。
格式也很簡單,其中if條件能夠省略,for循環能夠有多個

[i for i in iterable if condition]

10-20全部偶數的平方:

[i*i for i in range(10, 21) if i % 2 == 0 ]

一行實現快排

def qsort(arr):
    return arr if len(arr) <= 1 else qsort([x for x in arr[1:] if x<arr[0]]) + [arr[0]] + qsort([x for x in arr[1:] if x>=arr[0]])

索引迭代

enumerate()能夠把一個list變成索引-元素對。

for i, value in enumerate(['A', 'B', 'C']):
    print(i, value) 
0 A 1 B 2 C

zip

zip()能夠將可迭代的對象做爲參數,將對象中對應的元素打包成一個個元組,並返回一個迭代器,經常使用於同時遍歷兩個可迭代對象。

>>> li1 = ['Python' ,'JavaScript', 'Java']
>>> li2 = [1, 2, 3]
>>> nl = zip(li1, li2)
<zip object at memory>
>>> list(nl)
[('Python', 1), ('JavaScript', 2), ('Java', 3)]

配合dict能夠生成字典

>>> l1 = ['A', 'B', 'C']
>>> l2 = [1, 2, 3]
>>> dict(zip(l1, l2))
{'A': 1, 'B': 2, 'C': 3}

append和extend

>>> x = [1, 2, 3]
>>> x.extend([4, 5])
>>> x
[1, 2, 3, 4, 5]
>>> x.append([6, 7])
>>> x
[1, 2, 3, 4, 5, [6, 7]]

集合運算

首先將要比較的兩個list轉換爲set,再轉回list就好了

>>> l1 = [1, 2, 3, 4]
>>> l2 = [2, 3, 5, 7]
>>> list(set(l1) & set(l2))
[2, 3]
>>> list(set(l1) | set(l2))
[1, 2, 3, 4, 5, 7]
>>> list(set(l1) ^ set(l2))
[1, 4, 5, 7]

字典

本質是鍵值對哈希表

get

用來獲取某個鍵的值,不存在的話就用設置的default(默認爲None)

>>> d = dict(a=1, b=2)
>>> d.get('a')
1
>>> d.get('c')
>>> d.get('d', 2)
2

合併

>>> d1 = {'a':1, 'b':2}
>>> d2 = {'c':3, 'd':4}
>>> nd = {**d1, **d2}
>>> nd
{'a': 1, 'b': 2, 'c': 3, 'd': 4}

相似的,列表也能夠這樣合併

>>> l1 = [1, 2]
>>> l2 = [3, 4]
>>> l3 = [*l1, *l2]
>>> l3
[1, 2, 3, 4]

鍵值對反轉

>>> kv = {'a': 1, 'b':2 , 'c': 3}
>>> vk = zip(kv.values(), kv.keys())
>>> dict(vk)
{1: 'a', 2: 'b', 3: 'c'}
>>> min(vk)
(1, 'a')
>>> sorted(vk)
[(1, 'a'), (2, 'b'), (3, 'c')]

鍵值排序

>>> rows = [{k1: v1, k2: v2 ...}, ...]
>>> from operator import itemgetter
# 根據k1排序
>>> sorted(rows, key=itemgetter(k1))
# 相似的,對於class的對象能夠用attrgetter進行排序

集合運算

>>> a = {'a': 1, 'b': 2, 'c': 3}
>>> b = {'x': 1, 'b': 2, 'c': 4}
>>> a.keys() & b.keys()
{'b', 'c'}
>>> a.keys() - b.keys()
{'a'}
>>> a.items() & b.items()
{('b', 2)}

其餘數據結構

具名元組

經常使用於構建簡單的類

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(x=11, y=22)
>>> p
Point(x=11, y=22)
>>> p.x + p.y
33
>>> coord = (33, 44)
>>> q = Point(*coord)
>>> q
Point(x=33, y=44)

默認值字典

經常使用於統計數目

>>> from collections import defaultdict
>>> words = ('python', 'java', 'ruby', 'python', 'C', 'java', 'C++', 'C')
>>> counts = defaultdict(int)
>>> for word in words:
...    counts[word] += 1
>>> counts
defaultdict(<class 'int'>, {'python': 2, 'java': 2, 'ruby': 1, 'C': 2, 'C++': 1})

雙向隊列

>>> from collections import deque
>>> q = deque(["Eric", "John", "Michael"])
>>> q.append("Terry")
>>> q
deque(['Eric', 'John', 'Michael', 'Terry'])
>>> q.popleft()
Eric'
>>> q.pop()
'Terry'
>>> q
deque(['John', 'Michael'])

計數器

>>> from collections import Counter
>>> c = Counter('hello world')
>>> c
Counter({'l': 3, 'o': 2, ' ': 1, 'e': 1, 'd': 1, 'h': 1, 'r': 1, 'w': 1})
>>> c.most_common(2)
[('l', 3), ('o', 2)]

>>> import heapq
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = list(heapq.merge(a, b))
>>> c
[1, 2, 3, 4, 5, 6]
>>> heapq.nlargest(3, c)
[6, 5, 4]
>>> heapq.nsmallest(3, c)
[1, 2, 3]

OOP

只讀屬性

能夠經過在變量名前加__來使其變成私有變量,外部沒法直接訪問,但能夠經過類定義的方法來訪問。

class Person(object):
    def __init__(self, name):
            self.__name = name

    def get_name(self):
            return self.__name

    def set_name(self, name):
            self.__name = name

>>> p = Person('alphardex')
>>> p.name
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'name'
>>> p.get_name()
'alphardex'
>>> p.set_name('wang')
>>> p.get_name()
'wang'

@property

確定有的人不習慣經過方法來訪問私有變量,那麼如何用屬性來訪問私有變量呢?這時就要用到@property了,它能夠把一個方法變成屬性調用

class Person(object):
    def __init__(self, name):
            self.__name = name

    @property
    def name(self):
            return self.__name

    @name.setter
    def name(self, value):
            self.__name = value

>>> p = Person('alphardex')
>>> p.name
'alphardex'
>>> p.name = 'wang'
>>> p.name
'wang'

slots

當咱們定義了一個class並用其建立了一個實例後,能夠動態地給其綁定屬性,若是要限制這一點,能夠利用__slots__

class Person(object):
    __slots__ = ('name', 'age')

>>> p = Person('wang')
>>> p.name = 'wang'
>>> p.age = 21
>>> p.skill = 'Python'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'skill'

魔術方法

魔術方法能夠用來定製類的功能。
好比__repr__用來調試時打印類的字符串

class Person(object):
    def __init__(self, name, age):
            self.name = name
            self.age = age
    def __repr__(self):
            return f'<Person {self.name} age: {self.age}>'

>>> p = Person('alphardex', 21)
>>> p
<Person alphardex age: 21>

想了解更多魔術方法請參見官方文檔

元類

type

俗話說道生一,一輩子二,二生三,三生萬物。
在Python裏能夠這麼說:type生元類,元類生類,類生實例。
用一個數字變量的建立來講明這一點吧

>>> age = 21
>>> age.__class__
<class 'int'>
>>> age.__class__.__class__
<class 'type'>

age能夠看做爲int類的實例,而int類又能夠看作type類的實例。
也就是說,type建立了int類,實際上諸如str和bool等類也是由type建立的。

>>> help(type)
Help on class type in module builtins:

class type(object)
 |  type(object_or_name, bases, dict)
 |  type(object) -> the object's type
 |  type(name, bases, dict) -> a new type

def say_hello(self, name='world'):
    print(f'Hello, {name}')

>>> Hello = type('Hello', (object,), dict(hello=say_hello))
>>> h = Hello()
>>> type(Hello)
<class 'type'>
>>> type(h)
<class '__main__.Hello'>

經過用help查看type,能夠發現它確實能動態地建立類:第一個參數是類名name,第二個參數是基類bases,第三個參數是dict,裏面包含着類的全部方法。
實際上,type是Python的一個內置元類。

自定義元類

固然,你也能夠利用type來定義本身的元類。

class JSArrayMeta(type):
    def __new__(cls, name, bases, attrs):
            attrs['push'] = lambda self, value: self.append(value)
            attrs['shift'] = lambda self: self.pop(0)
            attrs['includes'] = lambda self, value: value in self
            return type.__new__(cls, name, bases, attrs)

class JSList(list, metaclass=JSArrayMeta):
    def __init__(self, value):
            self.extend(value)

>>> l = JSList([1, 2, 3])
>>> l
[1, 2, 3]
>>> l.push('a')
>>> l
[1, 2, 3, 'a']
>>> l.shift()
1
>>> l
[2, 3, 'a']
>>> l.includes(3)
True

 

  • 咱們首先定製了一個元類,叫JSArrayMetaclass(沒錯就是JS裏的數組XD)
  • 注意元類的命名規則:結尾必定要有Meta做爲識別
  • __new__方法用來建立JSList類,它接受4個參數
  • JSList繼承了list類,同時得到了元類的全部方法

其餘

加載內置模塊

利用-m參數,咱們能夠直接加載Python的模塊

# 搭建http服務器
$ python -m http.server
# 建立虛擬環境
$ python -m venv <name>
# 性能測試
$ python -m cProfile <file.py>
# 查看JSON
$ cat <file.json> | python -m json.tool

數據序列化

import pickle
data = ... # Some Python object
# 存儲
with open(f'{file}.pickle', 'wb') as f:
    pickle.dump(data, f)
# 讀取
with open(f'{file}.pickle', 'rb') as f:
    data = pickle.load(f)

數據分析

利用pandas模塊能夠對數據進行分析

$ pip install pandas
>>> import pandas as pd
>>> data = pd.read_csv(...)
# 數據查看
>>> data.columns              # 查看數據結構
>>> data.describe()           # 簡要數據分析
>>> data.sort_values(by=...)  # 對數據排序
# 數據選取
>>> data.head()               # 查看前五條數據
>>> data.iloc[n]              # 選擇位置爲n的數據,支持切片
>>> data[data.A > 0]          # 選擇A欄大於0的數據
>>> data[data.B.isin([...])]  # 利用in過濾數據
>>> data[~data.B.isin([...])] # 上一句的取反,至關於not in
# 缺失值處理
>>> pd.isna(data)             # 獲取缺失值的布爾標記
>>> data.dropna(how='any')    # 去除全部含有缺失值的欄
>>> data.fillna(value=5)      # 填充全部含有缺失值的欄
# 數據保存(能夠相互轉換格式,支持excel、csv和json)
>>> data.to_json(...)
相關文章
相關標籤/搜索