1. 程式人生 > >Python3_高階特性學習_2

Python3_高階特性學習_2

相關連結

from __future__ import print_function

# 8 Global和Return
# Return 返回結果,變數,函式,類...
# 返回多個值可以用 元組(常用),列表,字典
def profile():
    name = 'benji'
    age = 30
    return name, age  # 等價於(name,age) 元組的括號可以省略
p_data = profile()
print(p_data[0], p_data[1])
# global 變數意味著我們可以在函式以外的區域都能訪問這個變數
# 儘量不要使用盡量不要使用盡量不要使用


# 9 Mutation和Immutation
# python中的所有東西都是一個object,所以每個變數都包含物件例項。
# 啟動物件時,會為其分配一個唯一的object id,可以通過id(object)獲得。 is 運算子判斷object的id是否相等
# 物件的型別在執行時定義,一旦設定永遠不會改變,但可以重新定義,可以通過type(object)獲得
# 但物件的狀態(值)有的是可以改變的,這就是可變物件,反之,為不可變物件
# 對某種資料型別可變性的具體定義,應該看變數的具體使用情況,而不是通過id方法獲取的記憶體地址。
#   記憶體地址體現的是底層實現, 使用的結果才是我們應該關心的
asfd = '...asd'
print('\nid(asfd)', id(asfd), "\nid('...asd')", id('...asd'))
'''
>>> asd = '...asd'
>>> id(asd)
11405856
>>> id('...asd')
11406144
'''
# 可變物件: list,dict,set,byte array
# 不可變物件:int,float,complex,string,tuple,frozen set [注意:set的不可變版本],bytes
a = 'asd'
print("a='asd'\na is 'asd' ", a is 'asd',
      '\nid(a)', id(a), "\nid('asd')", id('asd'))
b = [1]
print("b=[1]\nb is [1] ", b is [1], '\nid(b)', id(b), "\nid([1])", id([1]))
# 不可變物件的不可變性是指物件本身不可變,其組成元素可能可變
# 例如 元組(12,[1,2,3])沒有改變自身元素的方法,但其組成元素[1,2,3]是可變的
# 按值傳遞: 入參是不可變物件,經過函式運算後,入參的值不發生改變
# 按引用傳遞: 入參是可變物件,經過函式運算後,原入參的值發生改變


# 10 __slots__ 魔法方法
# 在Python中,每個類都有例項屬性。Python是動態語言,根據類建立的例項可以任意繫結屬性
# 預設情況下Python用一個字典來儲存一個物件的例項屬性,這允許我們在執行時去設定任意的新屬性,
# __slots__來告訴Python不要使用字典,而只給一個固定集合的屬性分配空間
# name是類屬性,score是例項屬性。同名時例項屬性會覆蓋掉類屬性
class Student(object):
    # 使用__slots__後將不能再使用例項屬性:AttributeError: 'Student' object has no attribute 'score'
    # 只給一個固定集合的屬性分配空間,使用的記憶體可降低40%-50%
    # ipython_memory_usage: 記憶體使用檢測工具
    # __slots__ = ['name']
    def __init__(self, name):
        self.name = name
s = Student('Bob')
s.score = 90
print(s.name, ' has score ', s.score)


# 11 虛擬環境 virtualenv
# Virtualenv 是一個工具,它能夠幫我們建立一個獨立(隔離)的Python環境
# Virtualenv會建立在當前路徑建立一個資料夾,裡面包括Python執行檔案,pip類庫,我們可以用來安裝其他類包
'''
#安裝
pip install virtualenv
#建立隔離的virtualenv環境
virtualenv myproject
#使用系統全域性模組
virtualenv --system-site-packages mycoolproject
#python 2.7
virtualenv -p /usr/bin/python2.7 my_project
#啟用
source bin/activate
#退出
deactivate
'''


# 12 Collections 容器
# Python附帶一個模組,它包含許多容器資料型別,名字叫作collections
# defaultdict: 不需要檢查key是否存在,是否重複
from collections import defaultdict
colours = (('Yasoob', 'Yellow'), ('Ali', 'Blue'),
           ('Yasoob', 'Red'), ('Ahmed', 'Silver'))
favourite_colours = defaultdict(list)
for name, colour in colours:
    favourite_colours[name].append(colour)
print(favourite_colours)
# 字典中對一個鍵進行巢狀賦值
import collections
def tree(): return collections.defaultdict(tree)
some_dict = tree()
some_dict['colours']['favourite'] = "yellow"

# Counter: 計數器 對某項資料進行計數
from collections import Counter
colours = (('Yasoob', 'Yellow'), ('Ali', 'Blue'),
           ('Yasoob', 'Red'), ('Ahmed', 'Silver'))
favs = Counter(col1 for col1, item in colours)
print(favs)
# rb:以二進位制開啟檔案的只讀模式
with open('readme.md', 'rb') as f:
    line_count = Counter(f)
print(line_count)

# deque:雙端佇列 可以從頭/尾兩端新增或刪除元素,用法類似list
from collections import deque
d = deque()
d.append('1')
d.append('2')
d.append('3')
print('d, len(d), d[0], d[-1]: ', d, len(d), d[0], d[-1])
print('d.popleft(),d.pop(),d:', d.popleft(), d.pop(), d)
# 一旦設定長度後,資料會從對佇列另一端被擠出去(pop); 也可以從任一端拓展佇列的資料
d = deque(maxlen=2)
d.append('1')
d.append('2')
d.append('3')
print('d', d)
d = deque(range(5))
d.extendleft([-2, -1, 0])
d.extend([10, 11, 12])
print('d', d)

# namedtuple 命名元組, 可以字典訪問的元組,當然仍然是不可變的
# 有兩個必須引數:元組名稱和欄位名稱, 這讓命名元組變得自文件了
# 而且,namedtuple的每個例項沒有物件字典, 但_asdict()可以轉換為字典
from collections import namedtuple
Animal = namedtuple('Animal', 'name age type')
perry = Animal(name='perry', age=31, type='cat')
print('perry, perry.age', perry, perry.age)
# AttributeError: can't set attribute
# perry.age=42
print(perry._asdict())

# enum.Enum(Python 3.4+)
# Enums(列舉型別)基本上是一種組織各種東西的方式
from enum import Enum
class Species(Enum):
    cat = 1
    dog = 2
    horse = 3
    owl = 4
    platypus = 5
    aardvark = 6
    kitten = 7
    puppy = 8
    dragon = 9
print('Species.cat, Species.dragon, type(Species.cat)',
      Species.cat, Species.dragon, type(Species.cat))
perry = Animal(name='perry', age=31, type=Species.cat)
print('perry.type', perry.type)
perry.type


# 13 列舉 enumerate 
# 遍歷資料並自動計數
# 返回一個迭代器物件, 詳見 學習一: 3 生成器(Generators)
mylist = ['apple', 'banana', 'grapes', 'pear']
# 定製從哪個數字開始列舉 2 apple 3 banana 4 grapes 5 pear
for c, val in enumerate(mylist, 2):
    print(c, val)
# 建立包含索引的元組列表
counterlist = list(enumerate(mylist, 1))
print(counterlist)


# 14 物件自省 introspection
# 自省 在計算機程式設計領域裡,是指在執行時來判斷一個物件的型別的能力
# Python中所有一切都是一個物件, 並且包含許多內建函式和模組
# dir 返回一個列表,列出了一個物件所擁有的屬性和方法
mylist = [1, 23, 4]
print('dir(mylist)', dir(mylist))
# type 返回一個物件的型別
# id 返回任意不同種類物件的唯一ID
print('type({})', type({}))
print('id(mylist)', id(mylist))
# inspect模組 提供了許多有用的函式,來獲取活躍物件的資訊
import inspect
print(inspect.getmembers(mylist))


# 15 推導式 comprehensions:list dict set
# 是可以從一個數據序列構建另一個新的資料序列的結構體
# 列表推導式 list  variable = [out_exp for out_exp in input_list if out_exp == 2]
squard = [x**2 for x in range(10) if x > -1]
print(squard)
# 字典推導式 dict variable = { key: value for key, value in some_dict.items() if key > 2}
d = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
reverse_d = {vk: val for val, vk in d.items() if vk > 10}
print(reverse_d)
# 集合推導式 set variable = {out_exp for out_exp in input_list if out_exp ==2}
squard = {x**2 for x in [1, 2, 33, 1] if x < 10}
print(squard)


# 16 異常 Exception
try:
    file = open('readme.md', 'rb')
    #i = 1/0
# only catch IOError
except IOError as e:
    print('IOError occured. {}'.format(e.args[-1]))
# catch all exception and raise them
except Exception as e:
    print('Exception. {}'.format(e.args[-1]))
    #raise e
else:
    print('without error, else block will be run.')
finally:
    print('without raise, finally block will be run.')


# 17 lambda 匿名函式/行函式
#  lambda 引數:操作(引數)
a = [(1, 2), (4, 1), (9, 10), (13, -3)]
a.sort(key=lambda x: x[1])
print(a)
# zip in Python 3 returns an iterator
data = list(zip([2, 1], [4, 3]))
print(data[:])


# 18 python 行式命令
'''
python -m/-c
python -c command [arg] ...,啟動 Python 直譯器 這種方法可以在 命令列 執行 Python 語句,類似於 shell 中的 -c 選項。一般將 命令 用單引號包裹起來。
python -m module [arg] ... 將 Python 模組也可以當作指令碼使用 命令呼叫它們,這類似在命令列中鍵入完整的路徑名執行 模組 原始檔一樣。
# ??? 共享檔案
python -m http.server
# 指令碼效能分析
python -m cProfile PythonAdvanced.2.py
# csv轉換為json
python -c "import csv,json;print(json.dumps(list(csv.reader(open('download.csv')))))"
'''
# 列表碾平
import itertools
a_list = [[1, 2], [3, 4], [5, 6]]
print(list(itertools.chain.from_iterable(a_list)))
# 一行式構造器 避免初始化時的重複賦值語句
class A(object):
    def __init__(self, a, b, c, d, e, f):
        self.__dict__.update(
            {k: v for k, v in locals().items() if k != 'self'})
a = A('aaa', 'b123', 'c12', 'd11', 'e22', 'f321')
print(a.__dict__)


# 19 For - Else
# else從句會在迴圈正常結束時執行
# 類似的還有 while .. else ..
for n in range(2, 20):
    for i in range(2, n):
        if n % i == 0:
            print(n, 'equals', i, '*', n/i)
            break
    else:
        print(n, 'is a prime')


# 20 使用C拓展
# C語言的執行速度是python的50倍且C有很多傳統類庫
# ctypes: python類庫,直接呼叫C類庫,使用簡單,但是不能操作python物件
# SWIG: 適合多語言,但是使用複雜,需要為SWIG入口編寫介面檔案
# Python/C API: 可以將c原始碼編譯為拓展模組,作為類包引用,可以操作python物件,適合c/c++
# 詳見add_c資料夾


# 21 open 開啟一個檔案,返回一個控制代碼.
# with: open函數出現異常時不會關閉檔案控制代碼,with可以保證無論是否出現異常,檔案都能關閉
# mode: r 只讀; r+ 讀寫; w 覆蓋寫入; a 追加寫入
#       rb 二進位制模式只讀; rt(預設為文字) 文字模式只讀
with open('pythondatastructure.png', 'rb') as f:
    picdata = f.read()
# io 模組可以設定編碼型別
import io
with open('pythondatastructure.png', 'rb') as inf:
    picdata = inf.read()
if picdata.startswith(b'\xff\xd8'):
    text = u'this is a JPG file (%d bytes long)\n'
else:
    text = u'this is a no JPG file (%d bytes long)\n'
with io.open('open_summary.txt', 'w', encoding='utf-8') as outf:
    outf.write(text % len(picdata))


# 22 相容 python2 + python3
# 匯入__future__ 模組
# must set at the beginning
# from __future__ import print_function
print('this is from __future__')
# 模組重新命名
# import foo as foo_alias
try:
    import urllib.request as urllib_request
except ImportError:
    import urllib2 as urllib_request
# 禁用python2中的12個廢除的內建功能 作用環境python2
# from future.builtins.disabled import *


# 23 協程 Coroutines
# 協同程式和執行緒差不多,也就是一條執行序列,擁有自己獨立的棧、區域性變數和指標,
# 同時又與其他協同程式共享全域性變數和其他大部分東西。
# 與執行緒區別:一個具有多個執行緒的程式可以同時執行幾個執行緒,而協同程式卻需要彼此協作地執行
# 就是說一個具有多個協同程式的程式在任意時刻只能和執行一個協同程式
# 生成器是資料的生產者 協程則是資料的消費者. yield可獲得一個協程。協程會消費掉髮送給它的值
def grep(pattern):
    print("searching for", pattern)
    while True:
        # line 不包含任何初始值,相反要從外部傳值給它
        line = (yield)
        if pattern in line:
            print(line)
search = grep('coroutine')
# next() 啟動一個協程,send()方法向它傳值, close()方法來關閉一個協程
next(search)  # output: searching for coroutine
search.send('I Love bodybuilding')
search.send('I Love coroutine')  # output: I Love coroutine
search.close()
# search.send('I Love coroutine') # error: StopIteration

# 24 函式快取 Function caching
# 函式快取允許我們將一個函式對於給定引數的返回值快取起來
# python 3.2之後使用lru_cache
from functools import lru_cache
@lru_cache(maxsize=32)
def fib(n):
    if n < 2:
        return n
    return fib(n-2)+fib(n-1)
print([fib(x) for x in range(10)])
# 清空快取
fib.cache_clear()
# python 2 實現快取機制
from functools import wraps
def memorize(function):
    memo = {}
    @wraps(function)
    def wrapper(*args):
        # print('*args',*args)#*args 6
        # print('args',args)#args (6,)
        # print('memo',memo)#memo {(0,): 0, (1,): 1, (2,): 1, (3,): 2, (4,): 3, (5,): 5, (6,): 8}
        if args in memo:
            return memo[args]
        else:
            rv = function(*args)
            memo[args] = rv
            return rv
    return wrapper
@memorize
def fib2(n):
    if n < 2:
        return n
    return fib2(n-2)+fib2(n-1)
print('fib2(10)', fib2(10))
print('fib2(5)', fib2(5))


# 25 上下文管理器 Context managers
# 上下文管理器允許你在有需要的時候,精確地分配和釋放資源,
# 常見的, 資源的加鎖和解鎖,以及關閉已開啟的檔案with
with open('download.csv', 'r+') as f:
    picdata = f.read()
# 基於類的實現
# 上下文管理器的類必須要定義方法__enter__和__exit__
class MyFile(object):
    __slots__ = ["file_obj"]
    def __init__(self, file_name, method):
        self.file_obj = open(file_name, method)

    def __enter__(self):
        return self.file_obj

    def __exit__(self, type, value, traceback):
        print('with has handled exception')
        self.file_obj.close()
        return True
# with語句先暫存了MyFile類的__exit__方法
# 然後它呼叫MyFile類的__enter__方法
# __enter__方法開啟檔案並返回給with語句
# 開啟的檔案控制代碼被傳遞給f引數
# 我們使用.write()來寫檔案
# with語句呼叫之前暫存的__exit__方法
#    異常發生 :type,value和traceback傳遞給__exit__方法
#             __exit__返回True,異常就被處理了。返回True以外的任何東西,with將丟擲異常
# __exit__方法關閉了檔案
with MyFile('download.csv', 'r+') as f:
    f.write('this is from with key word')
with MyFile('download.csv', 'r+') as f:
    f.writenodefine('this is from with key word')    
# 基於生成器的實現 
# 裝飾器(decorators)和生成器(generators)來實現上下文管理器
# 通過contextlib模組呼叫contextmanager函式返回一個GeneratorContextManager物件封裝過的生成器
from contextlib import contextmanager
@contextmanager
def open_file(name):
    f = open(name, 'a')
    yield f
    f.close()
with open_file('download.csv') as f:
    f.write('write via contextmanager')