機器學習筆記-Python簡介

一些基本概念

Python語言簡潔明瞭,但對於不少從其他編程語言轉過來的人來說,相信有不少兄弟是奔着機器學習來的,經常被Python裏的模塊衝突,語法錯誤搞到瘋魔,這裏就對Python中的一些基本概念做一些基本的闡述,希望能對大家有所幫助(PS:本文不是Python教程,只是對於一些比較常用而又容易忽略的知識點做一些補充)。

解釋器

Linux/Unix系統上,一般默認的python版本爲2.x,我們可以將python3.x安裝在/usr/local/python3目錄中,安裝完成後,我們可以將路徑/usr/local/python/bin添加到Linux/Unix操作系統的環境變量中。
Python解釋器不止一種,有CPython、IPython、JPython、PyPy等,顧名思義,CPython使用C語言開發的,官方標準實現,是目前使用最廣泛的;IPython是在CPython基礎上在交互式方面得到增強的解釋器;JPython是轉爲Java平臺設計的解釋器,他把Python代碼編譯成Java字節碼執行,PyPy是Python語言(2.7.13和3.5.3)的一種快速、兼容的替代實現,以速度快著稱。

頭部註釋

在python2的py文件寫中文,則必須添加一行聲明文件編碼的註釋,否則python2會默認使用ascii編碼,具體請參考PEP-0263。用戶可以通過使用 #coding=<編碼名稱>#-*-編碼:<編碼名稱>-*- 來聲明編碼。

關於 #!/usr/bin/env python#!/usr/bin/python ,在Windows系統下,可以直接通過擴展名來判斷文件類型,所以只要是.py的後綴的可以直接關聯到python去執行,而Linux系統,則是根據文件開頭(首行)的標記來判斷文件類型,通過文件指定的程序來運行,如 #!/usr/bin/python 是告訴操作系統調用/usr/bin下的python解釋器來執行這個腳本, #!/usr/bin/env python 則是爲了防止沒有python裝在默認的/usr/bin路徑裏,當系統看到這一行時,會先到env設置裏查找python的安裝路徑,在調用對應的解釋器來執行,所以推薦這種寫法。

每回需要手動添加頭部註釋是很麻煩的一件事兒,可不可以通過快捷鍵直接插入呢?我本人使用的VSCode來擼代碼,這裏給出VSCode的設置方法:選擇File->Preferences->User Snippets選擇python.json添加如下:

"HEADER": {
    "prefix": "header",
    "body": [
      "#!/usr/bin/env python",
      "# -*- encoding: utf-8 -*-",
      "'''",
      "@文件    :$TM_FILENAME",
      "@說明    :",
      "@時間    :$CURRENT_YEAR/$CURRENT_MONTH/$CURRENT_DATE $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",
      "@作者    :姜戈",
      "@版本    :1.0",
      "'''",
      "",
      "$0"
    ],
  }

在新建**.py文件後,輸入header按tab鍵即可快速生成頭部文件,當然你也可以修改自定義快捷鍵。除了頭部註釋以外,我們還會用到單行註釋(一個#號),多行註釋(3個單引號或雙引號),下面我們以Engineer類爲例,給大家展示註釋的用法:

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件    :helloworld.py
@說明    :
@時間    :2020/12/30 13:48:21
@作者    :姜戈
@版本    :1.0
'''


class Engineer:
    '''
    這是我的多行註釋:
    工程師類,當其寫在類下或者方法下時,會被當作文檔註釋  。
    '''
    id = ''  # 單行註釋:標識
    name = ''  # 單行註釋:姓名
    age = 24  # 單行註釋:年齡

    def __init__(self, id, name, age):
        '''
        構造函數
        '''
        self.id = id
        self.name = name
        self.age = age

    def work(self):
        print(self.name + "正在工作。")

    def __str__(self):
        '''
        等同於java和.net中的tostring()方法
        '''
        return 'id:{},name:{},age:{}'.format(self.id, self.name, self.age)


if __name__ == '__main__':
    '''
    這段代碼是定式,如果被聲明,則當前文件被直接運行時,該代碼塊會被直接運行;當.py文件是以模塊的形式導入是,該代碼塊則不會執行。
    '''
    xiaowang = Engineer(1, '小王', 25)
    xiaowang.work()

模塊和包

模塊

有時候,爲了提高代碼的可維護性,我們會對編寫的函數進行分類,放到不同的Python文件裏,這樣的Python文件我們稱之爲模塊(Moudle),當模塊編寫完成後,就可以被其他地方引用,我們在編程的時候也會經常引用其他模塊,包括Python的內置模塊和第三方模塊。

使用模塊還有一個好處就是避免了變量名的衝突,相同名字的函數和變量存在不同的模塊中(不過還是要儘量避免命名與內置函數衝突),就像這個世界上有很多重名的人一樣,模塊命名總有可能衝突,爲解決這個問題,Python又引入按目錄來組織模塊的方法,稱之爲包(Package)。

舉個例子:

/factory
    ├─/hr
    │    ├─ __init__.py
    │    └─ work.py
    ├─/engineer
    │    ├─ __init__.py
    │    └─ work.py

文件work.py就是一個名字叫做work的模塊,但是,hr和enginner都有work的模塊,但由於其目錄不同,所以在引用時並不會發生衝突,比如我們想讓hr去工作,通過 factory.hr. work 來引入,想讓 enginner 去工作,就通過 factory.enginner.work 來引入。這裏需要注意的是,我們在每一層目錄下都有一個 _init_.py的文件,它可以爲空,但是是必須的,否則,Python就會把這個目錄當成一個普通目錄,而不是一個包。

下面我們通過os包中的getcwd方法來獲取:

import os

def show():
    print(os.getcwd())

if __name__ == '__main__':
    show()

如上面的代碼所示,當我們需要使用os中的getcwd方法時,先通過import將其導入進來,就可以直接調用了。每個模塊都包含一些對象的定義和一些語句,當模塊第一次被加載時這些語句會被執行(多次import只會執行一次),當引入一個模塊時,Python會按照以下路徑來查找模塊:

  • 當前目錄
  • 環境變量PYTHONPATH所制定的目錄
  • Python包的安裝目錄

一般來說,正常函數和變量名是公開的,可以被直接引用,類似 __xxx__這樣的變量就屬於特殊變量,會有一些特殊用途,比如_author_,_name_,__version__就屬於特殊變量,而類似_xxx和__xxx這種變量就是非公開的,不應該被直接引用,當然這種不應該只是習慣上的,並不是不能,Python並沒有強制性的做Public和Private的限制。

當然,每個模塊中除了你自己自定義的變量之外,還會有一些默認的attribute,我們通過dir()可以查看到結果:

['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'sys']

第三方模塊

除了自己編寫的模塊,大多數時候,我們還需要引入第三方模塊,如常用的numpy,那麼該如何引入呢? 與nuget和maven類似,我們在使用模塊之前,我們先要使用命令“pip install numpy”將numpy安裝到本地,通常安裝在對應解釋器的 .../site-packages 目錄下。如果仍不清楚,可以使用 pip show numpy 來查看 numpy 安裝目錄,如果仍不清楚,可以通過巧用 pip uninstall numpy來查看其安裝目錄,只需要在確認時輸入n即可。

模塊的引入

一個模塊的導入方式可以有多種,這裏我們依舊以numpy 爲例:

  1. 直接引入:import numpy
  2. 直接引入並指定別名:import numpy as np
  3. 直接引入所有:from numpy import *
  4. 直接引入模塊中的指定內容:from numpy import random
  5. 直接引入模塊中的指定內容並指定別名:from numpy import random as rn

其中,我們使用第三種方式來引入包時,就不需要在調用時,指定numpy作爲前綴,但這種方式並不推薦,因爲這種引用方式很有可能導致其和你自定義或其他模塊的變量衝突。

常用工具

pip

Python從2.7.9版本後,引入了pip工具,用於安裝第三方包,這裏我們依舊以numpy爲例:

  • 安裝指定的Package:pip install numpy
  • 安裝指定版本的Package:pip install numpy=1.19.2
  • 安裝最小版本的Package:pip install numpy>=1.19.2
  • 升級指定的Package:pip install --upgrade numpy

pydoc

有時候引入了包之後,我們想快速瞭解包中有哪些功能,這個時候我們可以通過pydoc來生成文檔來快速查看api說明,在終端輸入命令

python -m pydoc -w -p 9527

然後再瀏覽器中直接輸入:http://localhost:9527/ 就可以直接快速瀏覽相關文檔啦。

import os
print("PYTHONPATH:", os.environ.get('PYTHONPATH'))
print("PATH:", os.environ.get('PATH'))

格式化輸出

格式化輸出也是程序當中經常用到的功能,尤其是在記錄日誌的時候,我們工作中主要用到的是字符傳的格式化輸出和日期格式化輸出。

字符串格式化

佔位符

其實很簡單,如上文的Enginner中的work方法,我們需要打印出張三的工作內容,可以使用佔位符直接輸出:

print('%s is working,his age is %d'%(name,age))

佔位符會自動進行替換,%s是針對所有的數據類型,%d則僅僅針對數字類型,當然也有其他諸如%g、%e的佔位符,有興趣的可以自行了解,下面是一部分示例代碼:

print('%d' % (0b10))  # 轉換爲帶符號十進制整數
print('%o' % (0x10))  # 轉換爲帶符號八進制整數
print('%x' % (18))  # 轉換爲帶符號十六進制整數
pi = 3.1415926
print('%f' % pi)  # 轉化爲十進制浮點數
print('%.3f' % pi)  # 轉化爲十進制浮點數,保留小數點後三位
print('%08.3f' % pi)  # 轉化爲十進制浮點數,保留小數點後三位並指定寬度爲8,不夠的左邊補0
print('%.03f' % 3.1)  # 轉化爲十進制浮點數,小數點後補0

format 格式化

# 按順序的輸出
print('{} is working,his age is {}'.format(self.name, self.age))
# 按索引輸出
print('{1} is working,his age is {0}'.format(self.age,self.name))

f-String格式化

name='張三'
age=24
print(f'{name} is working,his age is {age}')
# 輸出的簡單運算,如age的乘2
print(F'{name} is working,his age is {age*2}')
print(F"{pi:.2f}")  # 保留小數點後2位
print(F"{pi:0>20}")  # 指定寬度不夠的左側以0補齊
print(F"{pi:0<20}")  # 指定寬度不夠的右側以0補齊

日期格式化

時間轉換是工作中經常遇見的問題,Python格式化日期的函數爲datetime.datetime.strftime(),由字符串轉換日期的函數爲datetime.datetime.strptime(),下面將簡單介紹一下日期的格式化輸出:

from datetime import datetime

now = datetime.now()
print(now)  # 輸出格式爲:2021-01-05 14:10:27.149326
print('年:{},月:{},日:{},小時:{},分鐘:{},秒:{}'.format(now.year, now.month, now.day,
                                               now.hour, now.minute,
                                               now.second))
print(now.strftime('%a'))  # 輸出星期幾英文簡稱,全稱請用大寫 A Tue
print(now.strftime('%b'))  # 輸出月份英文簡稱,全稱請用大寫 B Jan
print(now.strftime('%c'))  # 以本地時間輸出 Tue Jan  5 14:16:29 2021
print(now.strftime('%p'))  # 顯示上午還是下午以AM/PM顯示
print(now.strftime('%j'))  # 顯示一年中的第幾天 005
print(now.strftime('%w'))  # 顯示一週中的第幾天 2
print(now.strftime('%W'))  # 顯示一年中的第幾周 01
print(now.strftime('%Y'))  # 顯示年月日中的年 2021
print(now.strftime('%m'))  # 顯示年月日中的月 01
print(now.strftime('%d'))  # 顯示年月日中的日 05
print(now.strftime('%H'))  # 顯示年月日中的小時(24小時制) 14
print(now.strftime('%I'))  # 顯示年月日中的小時(12小時制) 02
print(now.strftime('%M'))  # 顯示分鐘數 39
print(now.strftime('%S'))  # 顯示秒數

# 組合使用
print(now.strftime('%Y-%m-%d %H:%M:%S'))  # 2021-01-05 14:44:57

日期的反向格式化直接使用strptime()函數即可:

now = '2021/01/05 14:44:57'
print(datetime.strptime(now, '%Y/%m/%d %H:%M:%S').day)

瞭解了這些格式化輸出,已經基本上可以滿足正常的工作使用否,最後稍稍的介紹一下日期的加減法,工作中也會經常用到:

import datetime
from dateutil.relativedelta import relativedelta

now = datetime.datetime.now()
# 添加日
addday = datetime.timedelta(days=1)
print(now + addday)
# 添加分鐘
addmin = datetime.timedelta(minutes=5)
print(now + addmin)
# 加減年
addyear = relativedelta(years=1)
print(now + addyear)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章