主頁 >  其他 > 爆肝六萬字整理的python基礎,快速入門python的首先

爆肝六萬字整理的python基礎,快速入門python的首先

2021-09-02 07:19:24 其他

文章目錄

  • 1 環境安裝
  • 2 Python的第一程式Hello World
  • 3 變數定義和型別
    • 3.1 什么是變數,
    • 3.2 變數的型別
    • 3.3 變數的命名規則
    • 3.4 常用的資料型別轉換
  • 4 注釋
    • 4.1 單行注釋
    • 4.2 多行注釋
    • 4.3 編碼
  • 5 輸入輸出
    • 5.1 輸入
    • 5.2 輸出
    • 5.2.1 格式化輸出
  • 6 運算子
  • 7 判斷陳述句
    • 7.1 if陳述句
    • 7.2 if-else陳述句
    • 7.3 elif
    • 7.4 if嵌套
  • 8 回圈、break和continue
    • 8.1 while回圈
    • 8.2 while回圈嵌套
    • 8.3 for回圈
    • 8.5 break
    • 8.6 continue
  • 9 字串、串列、元組、字典
    • 9.1 字串
  • 9.2 字串常見操作
      • 9.2.1 find
      • 9.2.2 index
      • 9.2.3 count
      • 9.2.4 replace
      • 9.2.5 split
      • 9.2.6 capitalize
      • 9.2.7 title
      • 9.2.8 startswith
      • 9.2.9 endswith
      • 9.2.10 lower
      • 9.2.11 upper
      • 9.2.12 ljust
      • 9.2.13 rjust
      • 9.2.14 center
      • 9.2.15 lstrip
      • 9.2.16 rstrip
      • 9.2.17 strip
      • 9.2.18 rfind
      • 9.2.19 rindex
      • 9.2.20 partition
      • 9.2.21 rpartition
      • 9.2.22 splitlines
      • 9.2.23 isalpha
      • 9.2.24 isdigit
      • 9.2.25 isalnum
      • 9.2.26 isspace
      • 9.2.27 join
    • 9.3 串列List
      • 9.3.1 for回圈遍歷list
      • 9.3.2 while回圈遍歷list
    • 9.4 串列的常用操作
      • 9.4.1 添加元素("增"append, extend, insert)
      • 9.4.2修改元素("改")
      • 9.4.3 查找元素("查"in, not in, index, count)
      • 9.4.4 洗掉元素("刪"del, pop, remove)
      • 9.4.5 排序(sort, reverse)
      • 9.4.6 串列的嵌套
    • 9.5 元組
      • 9.5.1 訪問元組
      • 9.5.2 修改元組
      • 9.5.3 元組的內置函式count, index
    • 9.6 字典
      • 9.6.1 根據鍵訪問值
    • 9.7 字典的常用操作
      • 9.7.1 修改元素
      • 9.7.2 添加元素
      • 9.7.3 洗掉元素
      • 9.7.4 字典的長度
      • 9.7.5 找出字典中的所有key
      • 9.7.6 找出字典所有的value
      • 9.7.7 找出字典的(鍵,值)
      • 9.7.8 判斷key是否存在
      • 9.7.9 遍歷字典的幾種方式
  • 10 函式
    • 10.1 定義函式
    • 10.2 呼叫函式
    • 10.3 函式的注釋
    • 10.4 函式的引數
      • 10.4.1 引數的定義
      • 10.4.2 引數的分類
      • 10.4.3 引數的傳遞
    • 10.5 函式的回傳值
    • 10.6 區域變數與全域變數
    • 10.7 遞回函式
    • 10.8 匿名函式
      • 10.8.1 定義
      • 10.8.2 應用場合
  • 11 檔案操作
    • 11.1 打開與關閉
      • 11.1.1 打開檔案
      • 11.1.2 關閉檔案
    • 11.2 檔案的讀寫
      • 11.2.1 寫資料(write)
      • 11.2.2 讀資料(read)
      • 11.2.3 讀資料(readlines)
      • 11.2.4 讀資料(readline)
    • 11.3 檔案的常用操作
      • 11.3.1 獲取當前讀寫的位置
      • 11.3.2 定位到某個位置
      • 11.3.3 檔案重命名
      • 11.3.4 洗掉檔案
    • 11.4 檔案夾的相關操作
      • 11.4.1 創建檔案夾
      • 11.4.2 獲取當前目錄
      • 11.4.3 改變默認目錄
      • 11.4.4 獲取目錄串列
      • 11.4.5 洗掉檔案夾
      • 11.4.6 檢測檔案夾是否存在
      • 11.4.7 創建多級檔案夾
  • 12 面向物件編程
    • 12.1 類和物件
      • 12.1.1 類
      • 12.2.2 物件
      • 12.2.3 類和物件的關系
      • 12.2.4 定義類
      • 12.2.5 創建物件
      • 12.2.6 `__init__()`方法
      • 12.2.7 魔法方法
      • 12.2.8 self
    • 12.2 屬性
      • 12.2.1 類屬性
      • 12.2.2 實體屬性(物件屬性)
      • 12.2.3 私有屬性
    • 12.3 繼承
      • 12.3.1 私有屬性和方法的繼承
      • 12.3.2 多繼承
      • 12.3.3 重寫父類方法
      • 12.3.4 呼叫父類的方法
    • 12.4 多型
    • 12.5 靜態方法和類方法
      • 12.5.1 類方法
      • 12.5.2 靜態方法
  • 13 例外
    • 13.1 捕獲例外
      • 13.1.1 捕獲例外 try...except...
      • 13.1.2 except捕獲多個例外
      • 13.1.3 獲取例外的資訊描述
      • 13.1.4捕獲所有例外
      • 13.1.5 else
      • 13.1.6 try...finally...
    • 13.2 例外的傳遞
      • 13.2.1. try嵌套中
      • 13.2.2 函式嵌套呼叫中
    • 13.3 拋出自定義的例外
    • 13.4 例外處理中拋出例外
  • 14 模塊
    • 14.1 模塊介紹
      • 14.1.1 Python中的模塊
      • 14.1.2 import
      • 14.1.3 from…import
      • 14.1.4 from … import *
      • 14.1.5 as
      • 14.1.6 定位模塊
    • 14.2 制作模塊
      • 14.2.1 定義自己的模塊
      • 14.2.2 呼叫自己定義的模塊
      • 14.2.3 測驗模塊
    • 14.3 模塊中的`__all__`
      • 14.3.1 沒有`__all__`
      • 14.3.2. 模塊中有`__all__`
    • 14.4 python中的包
      • 14.4.1. 引入包
      • 14.4.2 `__init__.py`檔案作用
    • 14.5 模塊發布
    • 14.6 模塊安裝、使用
      • 14.6.1 安裝的方式
      • 14.6.2 模塊的引入
      • 14.2.3 測驗模塊
    • 14.3 模塊中的`__all__`
      • 14.3.1 沒有`__all__`
      • 14.3.2. 模塊中有`__all__`
    • 14.4 python中的包
      • 14.4.1. 引入包
      • 14.4.2 `__init__.py`檔案作用
    • 14.5 模塊發布
    • 14.6 模塊安裝、使用
      • 14.6.1 安裝的方式
      • 14.6.2 模塊的引入

1 環境安裝

學習python開發,首先要學會安裝Python環境,我一般使用Anaconda+Pycharm作為開發環境,Anaconda是一個開源的Python發行版本,其包含了conda、Python等180多個科學包及其依賴項,因為包含了大量的科學包,Anaconda 的下載檔案比較大(約 531 MB),如果覺得安裝包太大可以使用Miniconda,

關于環境的安裝我已經寫了多篇文章,比如:

Ubuntu20.04的開發環境搭建:(4條訊息) Ubuntu 20.04安裝 Anaconda和Pycharm_AI浩-CSDN博客

Win10的開發環境搭建:(4條訊息) Win10 安裝Anaconda、Pycharm、Tensorflow和Pytorch_AI浩-CSDN博客

Anaconda的歷史版本下載:(4條訊息) Anaconda歷史版本_AI浩-CSDN博客,如果不想使用最新的版本,可以找到以前的版本,

2 Python的第一程式Hello World

新建個工程,將其命名為“Python基礎”,然后點擊“Create”

image-20210826100136979

然后,右擊工程,選擇“New”,然后選擇“Python File”,

image-20210826100257765

將其命名為“第一個Python程式”,然后按“Enter”鍵

image-20210826100510181

到這里我們創建Python檔案的作業就完成成了,下面試試Hello World,

將下面的代碼,復制進去:

   print('hello world')

然后右鍵選擇Run,或者使用快捷鍵“Ctrl+Shift+F10",

image-20210826100825453

運行結果:

image-20210826100952958

喜歡敲命令的朋友可以選擇命令列運行:

python 第一個Python程式.py

image-20210826101134469

3 變數定義和型別

3.1 什么是變數,

打個比方:我最近買了兩本書,一本售價89,一本售價118,我想用python計算一下兩本書一共要多少錢:

num1 = 89
num2 = 118
num3 = num1 + num2
print(num3)

運行結果:207

所謂的變數就是對計算機存盤值的表示,從上面的例子,我們可以得出:

Python 中的變數不需要宣告,每個變數在使用前都必須賦值,變數賦值以后該變數才會被創建,

在 Python 中,變數沒有型別,我們所說的"型別"是變數所指的記憶體中物件的型別,

等號(=)用來給變數賦值,

等號(=)運算子左邊是一個變數名,等號(=)運算子右邊是存盤在變數中的值,

3.2 變數的型別

如何知道一個變數的型別呢?

在python中,只要定義了一個變數,而且它有資料,那么它的型別就已經確定了,不需要咱們開發者主動的去說明它的型別,系統會自動辨別

可以使用type(變數的名字),來查看變數的型別,例如:

num1 = 89
num2 = 118
num3 = num1 + num2
print(type(num3))

運行結果:<class ‘int’>

3.3 變數的命名規則

變數的命名規則:

  1. 由字母、下劃線和數字組成,且數字不能開頭,

  2. 不能使用python的關鍵字,

? 關鍵字有:

      and     as      assert     break     class      continue    def     del
      elif    else    except     exec      finally    for         from    global
      if      in      import     is        lambda     not         or      pass
      print   raise   return     try       while      with        yield
  1. 起一個有意義的名字,盡量做到看一眼就知道是什么意思(提高代碼可 讀性) 比如: 名字 就定義為 name ,年齡用age,

  2. 駝峰命名法

第一種 小駝峰式命名法(lower camel case): 第一個單詞以小寫字母開始;第二個單詞的首字母大寫,例如:myName、aDog

第二種 大駝峰式命名法(upper camel case): 每一個單字的首字母都采用大寫字母,例如:FirstName、LastName

不過在程式員中還有一種命名法比較流行,就是用下劃線“_”來連接所有的單詞,比如send_buf

駝峰法

注:python中的識別符號是區分大小寫的

大小寫

3.4 常用的資料型別轉換

函式說明
int(x [,base ])將x轉換為一個整數
long(x [,base ])將x轉換為一個長整數
float(x )將x轉換到一個浮點數
complex(real [,imag ])創建一個復數
str(x )將物件 x 轉換為字串
repr(x )將物件 x 轉換為運算式字串
eval(str )用來計算在字串中的有效Python運算式,并回傳一個物件
tuple(s )將序列 s 轉換為一個元組
list(s )將序列 s 轉換為一個串列
chr(x )將一個整數轉換為一個字符
unichr(x )將一個整數轉換為Unicode字符
ord(x )將一個字符轉換為它的整數值
hex(x )將一個整數轉換為一個十六進制字串
oct(x )將一個整數轉換為一個八進制字串

舉例

    a = '100' # 此時a的型別是一個字串,里面存放了100這3個字符
    b = int(a) # 此時b的型別是整型,里面存放的是數字100
    print("a=%d"%b)

4 注釋

4.1 單行注釋

以#開頭,#右邊的所有東西當做說明,而不是真正要執行的程式,起輔助說明作用

    # 我是注釋,可以在里寫一些功能說明之類的哦
    print('hello world')

4.2 多行注釋

    '''我是多行注釋,可以寫很多很多行的
        哈哈哈,,,
        哈哈哈,,,
    '''

    '''
    我是多行注釋,可以寫很多很多行的
       哈哈哈,,,
       哈哈哈,,,
    '''
 print('hello world')

4.3 編碼

如果直接在程式中用到了中文,比如

    print('你好,我是AI浩')

如果直接運行輸出,程式會出現編碼的問題(這和平臺有關)

解決的辦法為:在程式的開頭寫入如下代碼,這就是中文注釋

    #coding=utf-8

修改之后的程式:

    #coding=utf-8
    print('你好,我是AI浩')

運行結果:

    你好

注意:在python的語法規范中推薦使用的方式:

# -*- coding:utf-8 -*-

5 輸入輸出

5.1 輸入

input()接受運算式輸入,并把運算式的結果賦值給等號左邊的變數

a = input("請輸入數字:")
print(a)
print(type(a))
b=input("請輸入字串:")
print(b)
print(type(b))
c= input("請輸入數學運算式:")
print(c)
print(type(c))
d= input("請輸入字串運算式:")
print(d)
print(type(d))

運行結果:

請輸入數字:123
123
<class 'str'>
請輸入字串:abc
abc
<class 'str'>
請輸入數學運算式:123+456
123+456
<class 'str'>
請輸入字串運算式:sdsf,1223
sdsf,1223
<class 'str'>

5.2 輸出

print() 將python的輸入

    # 列印提示
    print('hello world')

5.2.1 格式化輸出

如下代碼:

age = 100
print("我今年%d歲"%age)
age += 1
print("我今年%d歲"%age)
age += 1
print("我今年%d歲"%age)

運行結果:

我今年100歲
我今年101歲
我今年102歲

在程式中,看到了%這樣的運算子,這就是Python中格式化輸出,

    age = 18
    name = "lifeifei"
    print("我的姓名是%s,年齡是%d"%(name,age))

常用的格式符號

格式符號轉換
%c字符
%s通過str() 字串轉換來格式化
%i有符號十進制整數
%d有符號十進制整數
%u無符號十進制整數
%o八進制整數
%x十六進制整數(小寫字母)
%X十六進制整數(大寫字母)
%e索引符號(小寫’e’)
%E索引符號(大寫“E”)
%f浮點實數
%g%f和%e 的簡寫
%G%f和%E的簡寫

換行輸出

在輸出的時候,如果有\n那么,此時\n后的內容會在另外一行顯示

    print("1234567890-------") # 會在一行顯示
    print("1234567890\n-------") # 一行顯示1234567890,另外一行顯示-------

運行結果:

1234567890-------
1234567890
-------

6 運算子

python支持以下幾種運算子

  • 算術運算子

下面以a=10 ,b=20為例進行計算

運算子描述實體
+兩個物件相加 a + b 輸出結果 30
-得到負數或是一個數減去另一個數 a - b 輸出結果 -10
*兩個數相乘或是回傳一個被重復若干次的字串 a * b 輸出結果 200
/x除以y b / a 輸出結果 2
//取整除回傳商的整數部分 9//2 輸出結果 4 , 9.0//2.0 輸出結果 4.0
%取余回傳除法的余數 b % a 輸出結果 0
**回傳x的y次冪 a**b 為10的20次方, 輸出結果 100000000000000000000
>>> 9/2.0
4.5
>>> 9//2.0
4.0
  • 賦值運算子
運算子描述實體
=賦值運算子把=號右邊的結果給左邊的變數 num=1+2*3 結果num的值為7
>>> a, b = 1, 2
>>> a
1
>>> b
2
  • 復合賦值運算子
運算子描述實體
+=加法賦值運算子c += a 等效于 c = c + a
-=減法賦值運算子c -= a 等效于 c = c - a
*=乘法賦值運算子c *= a 等效于 c = c * a
/=除法賦值運算子c /= a 等效于 c = c / a
%=取模賦值運算子c %= a 等效于 c = c % a
**=冪賦值運算子c **= a 等效于 c = c ** a
//=取整除賦值運算子c //= a 等效于 c = c // a
  • 比較(即關系)運算子

python中的比較運算子如下表

運算子描述示例
==檢查兩個運算元的值是否相等,如果是則條件變為真,如a=3,b=3則(a == b) 為 true.
!=檢查兩個運算元的值是否相等,如果值不相等,則條件變為真,如a=1,b=3則(a != b) 為 true.
<>檢查兩個運算元的值是否相等,如果值不相等,則條件變為真,如a=1,b=3則(a <> b) 為 true,這個類似于 != 運算子
>檢查左運算元的值是否大于右運算元的值,如果是,則條件成立,如a=7,b=3則(a > b) 為 true.
<檢查左運算元的值是否小于右運算元的值,如果是,則條件成立,如a=7,b=3則(a < b) 為 false.
>=檢查左運算元的值是否大于或等于右運算元的值,如果是,則條件成立,如a=3,b=3則(a >= b) 為 true.
<=檢查左運算元的值是否小于或等于右運算元的值,如果是,則條件成立,如a=3,b=3則(a <= b) 為 true.
  • 邏輯運算子
運算子邏輯運算式描述實體
andx and y布爾"與" - 如果 x 為 False,x and y 回傳 False,否則它回傳 y 的計算值,(a and b) 回傳 20,
orx or y布爾"或" - 如果 x 是 True,它回傳 True,否則它回傳 y 的計算值,(a or b) 回傳 10,
notnot x布爾"非" - 如果 x 為 True,回傳 False ,如果 x 為 False,它回傳 True,not(a and b) 回傳 False

7 判斷陳述句

7.1 if陳述句

  • if陳述句是用來進行判斷的,其使用格式如下:
    if 要判斷的條件:
        條件成立時,要做的事情

例1:

age = 30
print("------if判斷開始------")
if age >= 18:
    print ("我已經成年了,我可以約妹子了!!!")
print ("------if判斷結束------")

運行結果:

------if判斷開始------
我已經成年了,我可以約妹子了!!!
------if判斷結束------

例2:

age = 16
print("------if判斷開始------")
if age >= 18:
    print ("我已經成年了,我可以約妹子了!!!")
print ("------if判斷結束------")

運行結果:

    ------if判斷開始------
    ------if判斷結束------

**總結:**以上2個例子僅僅是age變數的值不一樣,結果卻不同;能夠看得出if判斷陳述句的作用:就是當滿足一定條件時才會執行那塊代碼,否則就不執行那塊代碼

7.2 if-else陳述句

    if 條件:
        滿足條件時要做的事情1
        滿足條件時要做的事情2
        滿足條件時要做的事情3
        ......
    else:
        不滿足條件時要做的事情1
        不滿足條件時要做的事情2
        不滿足條件時要做的事情3
        ......

例:

age = 30
print("------if判斷開始------")
if age >= 18:
    print ("我已經成年了,我可以約妹子了!!!")
else:
    print("還沒有成年,不能約妹子!!!")
print ("------if判斷結束------")

結果1:年齡大于18

------if判斷開始------
我已經成年了,我可以約妹子了!!!
------if判斷結束------

結果2:年齡小于18

------if判斷開始------
還沒有成年,不能約妹子!!!
------if判斷結束------

7.3 elif

elif的使用格式如下:

    if xxx1:
        事情1
    elif xxx2:
        事情2
    elif xxx3:
        事情3

說明:

  • 當xxx1滿足時,執行事情1,然后整個if結束
  • 當xxx1不滿足時,那么判斷xxx2,如果xxx2滿足,則執行事情2,然后整個if結束
  • 當xxx1不滿足時,xxx2也不滿足,如果xxx3滿足,則執行事情3,然后整個if結束

例:

score = 66
if 90 <= score <= 100:
    print('本次考試,等級為A')
elif 80 <= score < 90:
    print('本次考試,等級為B')
elif 70 <= score < 80:
    print('本次考試,等級為C')
elif 60 <= score < 70:
    print('本次考試,等級為D')
elif 0 <= score < 60:
    print('本次考試,等級為E')

可以和else一起使用

   if 性別為男性:
       輸出男性的特征
       ...
   elif 性別為女性:
       輸出女性的特征
       ...
   else:
       第三種性別的特征
       ...

說明:

  • 當 “性別為男性” 滿足時,執行 “輸出男性的特征”的相關代碼

  • 當 “性別為男性” 不滿足時,如果 “性別為女性”滿足,則執行 “輸出女性的特征”的相關代碼

  • 當 “性別為男性” 不滿足,“性別為女性”也不滿足,那么久默認執行else后面的代碼,即 “第三種性別的特征”相關代碼

  • elif必須和if一起使用,否則出錯

7.4 if嵌套

if嵌套的格式

    if 條件1:

        滿足條件1 做的事情1
        滿足條件1 做的事情2
        ......

        if 條件2:
            滿足條件2 做的事情1
            滿足條件2 做的事情2
            ......
  • 說明
    • 外層的if判斷,也可以是if-else
    • 內層的if判斷,也可以是if-else
    • 根據實際開發的情況,進行選擇

if嵌套的應用舉例:

age = 16
girl = False
if age >= 18:
    print("我已經成年了,我可以約妹子了!!!")
    if girl:
        print("有女朋友,去約會!!")
    else:
        print("沒有女朋友,約個屁啊!!")
else:
    print("還沒有成年,不能約妹子!!!")
    if girl:
        print("還沒有成年,這是早戀啊!!")
    else:
        print("聽話的好孩子!!!")

結果1:age= 30;girl= True

我已經成年了,我可以約妹子了!!!
有女朋友,去約會!!

結果2:age= 30;girl= False

我已經成年了,我可以約妹子了!!!
沒有女朋友,約個屁啊!!

結果3:age= 16;girl= False

還沒有成年,不能約妹子!!!
聽話的好孩子!!!

結果4:age= 16;girl= True

還沒有成年,不能約妹子!!!
還沒有成年,這是早戀啊!!

8 回圈、break和continue

8.1 while回圈

    while 條件:
        條件滿足時,做的事情1
        條件滿足時,做的事情2
        條件滿足時,做的事情3
        ...(省略)...

例:

i = 0
while i < 5:
    print("當前是第%d次執行回圈" % (i + 1))
    print("i=%d" % i)
    i += 1

結果:

    當前是第1次執行回圈
    i=0
    當前是第2次執行回圈
    i=1
    當前是第3次執行回圈
    i=2
    當前是第4次執行回圈
    i=3
    當前是第5次執行回圈
    i=4

案例1. 計算1~100的累積和(包含1和100)

參考代碼如下:

# encoding=utf-8
i = 1
sum = 0
while i <= 100:
    sum = sum + i
    i += 1
print("1~100的累積和為:%d" % sum)

運行結果:1~100的累積和為:5050

案例2. 計算1~100之間偶數的累積和(包含1和100)

# encoding=utf-8
i = 1
sum = 0
while i <= 100:
    if i % 2 == 0:
        sum = sum + i
    i += 1

print("1~100的偶數累積和為:%d" % sum)

運行結果:1~100的偶數累積和為:2550

8.2 while回圈嵌套

類似if的嵌套,while嵌套就是:while里面還有while

格式如下

    while 條件1:

        條件1滿足時,做的事情1
        條件1滿足時,做的事情2   
        ......
        while 條件2:
            條件2滿足時,做的事情1
            條件2滿足時,做的事情2
            條件2滿足時,做的事情3
            ...(省略)...

案例1 要求:列印如下圖形:

    *
    * *
    * * *
    * * * *
    * * * * *

參考代碼:

    i = 1
    while i<=5:
        j = 1
        while j<=i:
            print("* ",end='')
            j+=1
        print("\n")
        i+=1

案例2 :九九乘法表

    i = 1
    while i<=9:
        j=1
        while j<=i:
            print("%d*%d=%-2d "%(j,i,i*j),end='')
            j+=1
        print('\n')
        i+=1

運行結果:

1*1=1  

1*2=2  2*2=4  

1*3=3  2*3=6  3*3=9  

1*4=4  2*4=8  3*4=12 4*4=16 

1*5=5  2*5=10 3*5=15 4*5=20 5*5=25 

1*6=6  2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 

1*7=7  2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 

1*8=8  2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 

1*9=9  2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81 

8.3 for回圈

像while回圈一樣,for可以完成回圈的功能,

在Python中 for回圈可以遍歷任何序列的專案,如一個串列或者一個字串等,

格式如下:

    for 臨時變數 in 串列或者字串等:
        回圈滿足條件時執行的代碼
    else:
        回圈不滿足條件時執行的代碼

例1:

name = 'AIHao'
for x in name:
    print(x)

運行結果如下:

A
I
H
a
o

案例2:

name = ''
for x in name:
    print(x)
else:
    print("沒有資料")

運行結果如下:

沒有資料

8.5 break

1) for回圈

  name = 'AIHao'
  for x in name:
      print('----')
      if x == 'a': 
          break
      print(x)

運行結果:

----
A
----
I
----
H
----

2)while回圈

  i = 0
  while i<10:
      i = i+1
      print('----')
      if i==5:
          break
      print(i)

運行結果:

----
1
----
2
----
3
----
4
----

**總結:**break的作用:用來結束整個回圈

8.6 continue

1) for回圈

  name = 'AIHao'
  for x in name:
      print('----')
      if x == 'a': 
          continue
      print(x)

運行結果:

----
A
----
I
----
H
----
----
o

2) while回圈

  i = 0
  while i<10:
      i = i+1
      print('----')
      if i==5:
          continue
      print(i)

運行結果:

----
1
----
2
----
3
----
4
----
----
6
----
7
----
8
----
9
----
10

**總結:**continue的作用:用來結束本次回圈,緊接著執行下一次的回圈

注:

  • break/continue只能用在回圈中,除此以外不能單獨使用
  • break/continue在嵌套回圈中,只對最近的一層回圈起作用

9 字串、串列、元組、字典

9.1 字串

1)使用單引號或雙引號定義的資料就是字串,例:

a='hello'
或者
a="hello"

2)字串的輸出使用print()

name = 'AI浩'
position = '演算法工程師'
address = '北京石景山'
print('--------------------------------------------------')
print("姓名:%s" % name)
print("職位:%s" % position)
print("公司地址:%s" % address)
print('--------------------------------------------------')

運行結果:

--------------------------------------------------
姓名:AI浩
職位:演算法工程師
公司地址:北京石景山
--------------------------------------------------

3)字串輸入

userName = input('請輸入用戶名:')
print("用戶名為:%s" % userName)
password = input('請輸入密碼:')
print("密碼為:%s" % password)

結果:(根據輸入的不同結果也不同)

請輸入用戶名:dfsdfsd
用戶名為:dfsdfsd
請輸入密碼:qqq
密碼為:qqq

4)下標和切片

下標的使用

name = 'abcdef'
print(name[0])
print(name[1])
print(name[2])

運行結果:

a
b
c

切片:

切片是指對操作的物件截取其中一部分的操作,字串、串列、元組都支持切片操作,

切片的語法:[起始:結束:步長]

注意:選取的區間屬于左閉右開型,即從"起始"位開始,到"結束"位的前一位結束(不包含結束位本身),

name = 'abcdef'
print(name[0:3])  # 取 下標0~2 的字符

運行結果:

abc

9.2 字串常見操作

如有字串mystr = 'hello world AIHao and CSDN',以下是常見的操作

9.2.1 find

檢測 str 是否包含在 mystr中,如果是回傳開始的索引值,否則回傳-1,語法:

mystr.find(str, start=0, end=len(mystr))

例:

mystr = 'hello world AIHao and CSDN'
print(mystr.find("AIHao", 0, len(mystr)))

運行結果:

12

9.2.2 index

跟find()方法一樣,只不過如果str不在 mystr中會報一個例外,語法:

mystr.index(str, start=0, end=len(mystr)) 

例:

mystr = 'hello world AIHao and CSDN'
print(mystr.index("Hao", 0, len(mystr)))

運行結果:

14

9.2.3 count

回傳 str在start和end之間 在 mystr里面出現的次數,語法:

mystr.count(str, start=0, end=len(mystr))

例:

mystr = 'hello world AIHao and CSDN'
print(mystr.count("a", 0, len(mystr)))

運行結果:2

9.2.4 replace

把 mystr 中的 str1 替換成 str2,如果 count 指定,則替換不超過 count 次,語法:

mystr.replace(str1, str2,  mystr.count(str1))

例:

mystr = 'hello world AIHao and CSDN'
newStr=mystr.replace("a","ee",mystr.count("a"))
print(newStr)

運行結果:

hello world AIHeeo eend CSDN

9.2.5 split

以 str 為分隔符切片 mystr,如果 maxsplit有指定值,則僅分隔 maxsplit 個子字串,語法:

mystr.split(str=" ", 2)    

例:

mystr = 'hello world AIHao and CSDN'
newStr=mystr.split(" ",2)
print(newStr)

運行結果:

['hello', 'world', 'AIHao and CSDN']
mystr = 'hello world AIHao and CSDN'
newStr=mystr.split(" ")
print(newStr)

運行結果:

['hello', 'world', 'AIHao', 'and', 'CSDN']

9.2.6 capitalize

把字串的第一個字符大寫,其他的變成小寫,語法:

mystr.capitalize()

例:

mystr = 'hello world AIHao and CSDN'
print(mystr.capitalize())

運行結果:

Hello world aihao and csdn

9.2.7 title

把字串的每個單詞首字母大寫,其他的改成小寫,例:

mystr = 'hello world AIHao and CSDN'
print(mystr.title())

運行結果:

Hello World Aihao And Csdn

9.2.8 startswith

檢查字串是否是以 obj 開頭, 是則回傳 True,否則回傳 False

mystr.startswith(obj)

例:

mystr = 'hello world AIHao and CSDN'
ss='hello'
print(mystr.startswith(ss))

運行結果:True

9.2.9 endswith

檢查字串是否以obj結束,如果是回傳True,否則回傳 False,用法同上

mystr.endswith(obj)

9.2.10 lower

轉換 mystr 中所有大寫字符為小寫

mystr.lower()        

例:

mystr = 'hello world AIHao and CSDN'
print(mystr.lower())

運行結果:

hello world aihao and csdn

9.2.11 upper

轉換 mystr 中的小寫字母為大寫,用法同上,

mystr.upper()    

9.2.12 ljust

回傳一個原字串左對齊,并使用空格填充至長度 width 的新字串

mystr.ljust(width) 

例:

mystr = "hello world AIHao and CSDN"
print(mystr.ljust(50))

運行結果:

hello world AIHao and CSDN    

9.2.13 rjust

回傳一個原字串右對齊,并使用空格填充至長度 width 的新字串

mystr.rjust(width)    

例:

mystr = "hello world AIHao and CSDN"
print(mystr.rjust(30))

運行結果:

    hello world AIHao and CSDN

9.2.14 center

回傳一個原字串居中,并使用空格填充至長度 width 的新字串,用法同上,

mystr.center(width)   

9.2.15 lstrip

洗掉 mystr 左邊的空白字符

mystr.lstrip()

9.2.16 rstrip

洗掉 mystr 字串末尾的空白字符

mystr.rstrip()    

9.2.17 strip

洗掉mystr字串兩端的空白字符

>>> a = "\n\t itcast \t\n"
>>> a.strip()
'itcast'

9.2.18 rfind

類似于 find()函式,不過是從右邊開始查找.

mystr.rfind(str, start=0,end=len(mystr) )

9.2.19 rindex

類似于 index(),不過是從右邊開始.

mystr.rindex( str, start=0,end=len(mystr))

9.2.20 partition

把mystr以str分割成三部分,str前,str和str后

mystr.partition(str)

9.2.21 rpartition

類似于 partition()函式,不過是從右邊開始.

mystr.rpartition(str)

9.2.22 splitlines

按照行分隔,回傳一個包含各行作為元素的串列

mystr.splitlines()  

9.2.23 isalpha

如果 mystr 所有字符都是字母 則回傳 True,否則回傳 False

mystr.isalpha()  

9.2.24 isdigit

如果 mystr 只包含數字則回傳 True 否則回傳 False.

mystr.isdigit() 

9.2.25 isalnum

如果 mystr 所有字符都是字母或數字則回傳 True,否則回傳 False

mystr.isalnum()  

9.2.26 isspace

如果 mystr 中只包含空格,則回傳 True,否則回傳 False.

mystr.isspace()   

9.2.27 join

mystr 中每個字符后面插入str,構造出一個新的字串

mystr.join(str)

9.3 串列List

串列list用[,…]表示,格式如下:

  namesList = ['xiaoWang','xiaoZhang','xiaoHua']

9.3.1 for回圈遍歷list

1)例:

namesList = ['xiaoWang', 'xiaoZhang', 'xiaoHua']
for name in namesList:
    print(name)

結果:

    xiaoWang
    xiaoZhang
    xiaoHua

串列推導式

1)普通方式

a = [x for x in range(4)]
print(a)
b = [x for x in range(3, 4)]
print(b)
c = [x for x in range(3, 19)]
print(c)
d = [x for x in range(3, 19, 2)]
print(d)

運行結果:

[0, 1, 2, 3]
[3]
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
[3, 5, 7, 9, 11, 13, 15, 17]

2)在回圈的程序中加入if判斷

a = [x for x in range(3, 15) if x % 2 == 0]
print(a)
b = [x for x in range(3, 15) if x % 2 != 0]
print(b)
b = [x for x in range(3, 15)]
print(b)

運行結果:

[4, 6, 8, 10, 12, 14]
[3, 5, 7, 9, 11, 13]
[3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]

3)多個for回圈

a = [(x, y) for x in range(3, 5) for y in range(3)]
print(a)
b = [(x, y, z) for x in range(3, 5) for y in range(3) for z in range(4, 6)]
print(b)

運行結果:

[(3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2)]
[(3, 0, 4), (3, 0, 5), (3, 1, 4), (3, 1, 5), (3, 2, 4), (3, 2, 5), (4, 0, 4), (4, 0, 5), (4, 1, 4), (4, 1, 5), (4, 2, 4), (4, 2, 5)]

9.3.2 while回圈遍歷list

namesList = ['xiaoWang', 'xiaoZhang', 'xiaoHua']
length = len(namesList)
i = 0
while i < length:
    print(namesList[i])
    i += 1

運行結果:

xiaoWang
xiaoZhang
xiaoHua

9.4 串列的常用操作

串列中存放的資料是可以進行修改的,比如"增"、“刪”、“改”"

9.4.1 添加元素("增"append, extend, insert)

append:通過append可以向串列添加元素

例:

    #定義變數A,默認有3個元素
    A = ['xiaoWang','xiaoZhang','xiaoHua']
    print("-----添加之前,串列A的資料-----")
    for tempName in A:
        print(tempName)
    #提示、并添加元素
    temp = input('請輸入姓名:')
    A.append(temp)
    print("-----添加之后,串列A的資料-----")
    for tempName in A:
        print(tempName)

結果:

-----添加之前,串列A的資料-----
xiaoWang
xiaoZhang
xiaoHua
請輸入姓名:xiaohei
-----添加之后,串列A的資料-----
xiaoWang
xiaoZhang
xiaoHua
xiaohei

extend:通過extend可以將另一個集合中的元素逐一添加到串列中

a = [1, 2]
b = [3, 4]
a.append(b)
print(a)
a.extend(b)
print(a)

結果:

[1, 2, [3, 4]]
[1, 2, [3, 4], 3, 4]

insert :insert(index, object) 在指定位置index前插入元素object

a = [0, 1, 2]
a.insert(1, 3)
print(a)

結果:

[0, 3, 1, 2]

9.4.2修改元素(“改”)

修改元素的時候,要通過下標來確定要修改的是哪個元素,然后才能進行修改,例:

    #定義變數A,默認有3個元素
    A = ['xiaoWang','xiaoZhang','xiaoHua']

    print("-----修改之前,串列A的資料-----")
    for tempName in A:
        print(tempName)
    #修改元素
    A[1] = 'xiaoLu'
    print("-----修改之后,串列A的資料-----")
    for tempName in A:
        print(tempName)

結果:

    -----修改之前,串列A的資料-----
    xiaoWang
    xiaoZhang
    xiaoHua
    -----修改之后,串列A的資料-----
    xiaoWang
    xiaoLu
    xiaoHua

9.4.3 查找元素("查"in, not in, index, count)

所謂的查找,就是看看指定的元素是否存在

in, not in

python中查找的常用方法為:

  • in(存在),如果存在那么結果為true,否則為false
  • not in(不存在),如果不存在那么結果為true,否則false

demo

    #待查找的串列
    nameList = ['xiaoWang','xiaoZhang','xiaoHua']
    #獲取用戶要查找的名字
    findName = input('請輸入要查找的姓名:')
    #查找是否存在
    if findName in nameList:
        print('在字典中找到了相同的名字')
    else:
        print('沒有找到')

說明:

in的方法只要會用了,那么not in也是同樣的用法,只不過not in判斷的是不存在

index, count

index和count與字串中的用法相同

a = ['a', 'b', 'c', 'a', 'b']
print(a.index('a', 1, 4))
print(a.count('b'))
print(a.count('d'))
print(a.index('a', 1, 3)) # 注意是左閉右開區間

運行結果:

Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 5, in <module>
    print(a.index('a', 1, 3)) # 注意是左閉右開區間
ValueError: 'a' is not in list
3
2
0

9.4.4 洗掉元素("刪"del, pop, remove)

類比現實生活中,如果某位同學調班了,那么就應該把這個條走后的學生的姓名洗掉掉;在開發中經常會用到洗掉這種功能,

串列元素的常用洗掉方法有:

  • del:根據下標進行洗掉
  • pop:洗掉最后一個元素
  • remove:根據元素的值進行洗掉

demo:(del)

    movieName = ['加勒比海盜','駭客帝國','第一滴血','指環王','霍位元人','速度與激情']
    print('------洗掉之前------')
    for tempName in movieName:
        print(tempName)
    del movieName[2]
    print('------洗掉之后------')
    for tempName in movieName:
        print(tempName)

結果:

    ------洗掉之前------
    加勒比海盜
    駭客帝國
    第一滴血
    指環王
    霍位元人
    速度與激情
    ------洗掉之后------
    加勒比海盜
    駭客帝國
    指環王
    霍位元人
    速度與激情

例:(pop)

    movieName = ['加勒比海盜','駭客帝國','第一滴血','指環王','霍位元人','速度與激情']

    print('------洗掉之前------')
    for tempName in movieName:
        print(tempName)

    movieName.pop()

    print('------洗掉之后------')
    for tempName in movieName:
        print(tempName)

結果:

    ------洗掉之前------
    加勒比海盜
    駭客帝國
    第一滴血
    指環王
    霍位元人
    速度與激情
    ------洗掉之后------
    加勒比海盜
    駭客帝國
    第一滴血
    指環王
    霍位元人

demo:(remove)

    movieName = ['加勒比海盜','駭客帝國','第一滴血','指環王','霍位元人','速度與激情']

    print('------洗掉之前------')
    for tempName in movieName:
        print(tempName)

    movieName.remove('指環王')

    print('------洗掉之后------')
    for tempName in movieName:
        print(tempName)

結果:

    ------洗掉之前------
    加勒比海盜
    駭客帝國
    第一滴血
    指環王
    霍位元人
    速度與激情
    ------洗掉之后------
    加勒比海盜
    駭客帝國
    第一滴血
    霍位元人
    速度與激情

9.4.5 排序(sort, reverse)

sort方法是將list按特定順序重新排列,默認為由小到大,引數reverse=True可改為倒序,由大到小,

reverse方法是將list逆置,

>>> a = [1, 4, 2, 3]
>>> a
[1, 4, 2, 3]
>>> a.reverse()
>>> a
[3, 2, 4, 1]
>>> a.sort()
>>> a
[1, 2, 3, 4]
>>> a.sort(reverse=True)
>>> a
[4, 3, 2, 1]

9.4.6 串列的嵌套

類似while回圈的嵌套,串列也是支持嵌套的

一個串列中的元素又是一個串列,那么這就是串列的嵌套

    schoolNames = [['北京大學','清華大學'],
                    ['南開大學','天津大學','天津師范大學'],
                    ['山東大學','中國海洋大學']]

案例:一個學校,有3個辦公室,現在有8位老師等待工位的分配,請撰寫程式,完成隨機的分配

#encoding=utf-8
import random
# 定義一個串列用來保存3個辦公室
offices = [[],[],[]]
# 定義一個串列用來存盤8位老師的名字
names = ['A','B','C','D','E','F','G','H']
i = 0
for name in names:
    index = random.randint(0,2)    
    offices[index].append(name)
i = 1
for tempNames in offices:
    print('辦公室%d的人數為:%d'%(i,len(tempNames)))
    i+=1
    for name in tempNames:
        print("%s"%name,end='')
    print("\n")
    print("-"*20)

運行結果如下:

辦公室1的人數為:3
BFG

--------------------
辦公室2的人數為:5
ACDEH

--------------------
辦公室3的人數為:0


--------------------

9.5 元組

Python的元組與串列類似,不同之處在于元組的元素不能修改,元組使用小括號(),串列使用方括號[],例:

aTuple = ('et',77,99.9)
print(aTuple)

運行結果:(‘et’, 77, 99.9)

9.5.1 訪問元組

aTuple = ('et',77,99.9)
print(aTuple[0])
print(aTuple[1])

運行結果:

et
77

9.5.2 修改元組

aTuple = ('et',77,99.9)
aTuple[0]=111

運行結果:

Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 2, in <module>
    aTuple[0]=111
TypeError: 'tuple' object does not support item assignment

從上面的運行結果可以得出: python中不允許修改元組的資料,包括不能洗掉其中的元素,

9.5.3 元組的內置函式count, index

index和count與字串和串列中的用法相同

>>> a = ('a', 'b', 'c', 'a', 'b')
>>> a.index('a', 1, 3) # 注意是左閉右開區間
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: tuple.index(x): x not in tuple
>>> a.index('a', 1, 4)
3
>>> a.count('b')
2
>>> a.count('d')
0

9.6 字典

字典是一種可變容器模型,且可存盤任意型別物件,

字典的每個鍵值 key=>value 對用冒號 : 分割,每個對之間用逗號(,)分割,整個字典包括在花括號 {} 中 ,格式如下所示:

d = {key1 : value1, key2 : value2, key3 : value3 }

新建 Microsoft Visio 繪圖

例:

   info = {'name':'AI浩', 'id':100, 'sex':'f', 'address':'中國北京'}

9.6.1 根據鍵訪問值

    info = {'name':'AI浩', 'id':100, 'sex':'f', 'address':'中國北京'}
    print(info['name'])
    print(info['address'])

結果:

    AI浩
    中國北京

若訪問不存在的鍵,則會報錯:

info = {'name': 'AI浩', 'id': 100, 'sex': 'f', 'address': '中國北京'}
print(info['age'])

運行結果:

Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 2, in <module>
    print(info['age'])
KeyError: 'age'

在我們不確定字典中是否存在某個鍵而又想獲取其值時,可以使用get方法,還可以設定默認值:

>>> age = info.get('age')
>>> age #'age'鍵不存在,所以age為None
>>> type(age)
<type 'NoneType'>
>>> age = info.get('age', 18) # 若info中不存在'age'這個鍵,就回傳默認值18
>>> age
18

9.7 字典的常用操作

9.7.1 修改元素

字典的每個元素中的資料是可以修改的,只要通過key找到,即可修改,例:

info = {'name': 'AI浩', 'id': 100, 'sex': 'f', 'address': '中國北京'}
info['id'] = 150
print('修改之后的id為:%d' % info['id'])

結果:修改之后的id為:150

9.7.2 添加元素

使用 變數名[‘鍵’] = 資料 時,這個“鍵”在字典中,不存在,那么就會新增這個元素,例:

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
newId = input('請輸入新的ID')
info['id'] = int(newId)

print('添加之后的id為:%d' % info['id'])

結果:

請輸入新的ID123
添加之后的id為:123

9.7.3 洗掉元素

對字典進行洗掉操作,有一下幾種:

  • del
  • clear()

例1:del洗掉指定的元素

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
print('洗掉前,%s' % info['name'])
del info['name']
print('洗掉后,%s' % info['name'])

結果:

洗掉前,AI浩
Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 4, in <module>
    print('洗掉后,%s' % info['name'])
KeyError: 'name'

例2:del洗掉整個字典

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
print('洗掉前,%s' % info)
del info
print('洗掉后,%s' % info)

運行結果:

Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 4, in <module>
    print('洗掉后,%s' % info)
NameError: name 'info' is not defined
洗掉前,{'name': 'AI浩', 'sex': 'f', 'address': '中國北京'}

例3:clear清空整個字典

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
print('清空前,%s' % info)
info.clear()
print('清空后,%s' % info)

運行結果:

清空前,{'name': 'AI浩', 'sex': 'f', 'address': '中國北京'}
清空后,{}

9.7.4 字典的長度

使用len()方法,求字典的長度,例:

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
print('字典的長度:%d' % len(info))

運行結果:字典的長度:3

9.7.5 找出字典中的所有key

keys回傳一個包含字典所有KEY的視圖物件,例:

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
dicKeys=info.keys()
print(dicKeys)
print(dicKeys[0])

運行結果:

Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 4, in <module>
    print(dicKeys[0])
TypeError: 'dict_keys' object is not subscriptable
dict_keys(['name', 'sex', 'address'])

注:回傳的是個視圖物件,不是list,很多資料說list是不對的,但是可以轉為list,例:

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
dicKeys=list(info.keys())
print(dicKeys)
print(dicKeys[0])

運行結果:

['name', 'sex', 'address']
name

9.7.6 找出字典所有的value

屬性values回傳一個包含字典所有value的視圖串列,用法同上,例:

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
dicvalues=list(info.values())
print(dicvalues)
print(dicvalues[0])

運行結果:

['AI浩', 'f', '中國北京']
AI浩

9.7.7 找出字典的(鍵,值)

屬性items,回傳一個包含所有(鍵,值)元祖的串列

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
dicItems=info.items()
print(dicItems)

運行結果:

dict_items([('name', 'AI浩'), ('sex', 'f'), ('address', '中國北京')])

9.7.8 判斷key是否存在

“key in dict"如果鍵在字典dict里回傳true,否則回傳false,例:

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
ss='name' in info
print(ss)

運行結果:True

9.7.9 遍歷字典的幾種方式

1) 遍歷字典的key(鍵)

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
for key in info.keys():
    print(key)

運行結果:

name
sex
address

2) 遍歷字典的value(值)

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
for key in info.values():
    print(key)

運行結果:

AI浩
f
中國北京

3) 遍歷字典的項(元素)

info = {'name': 'AI浩',  'sex': 'f', 'address': '中國北京'}
for item in info.items():
    print(item)

運行結果:

('name', 'AI浩')
('sex', 'f')
('address', '中國北京')

4) 遍歷字典的key-value(鍵值對)

info = {'name': 'AI浩', 'sex': 'f', 'address': '中國北京'}
for key, value in info.items():
    print("key=%s,value=%s" % (key, value))

運行結果:

key=name,value=AI浩
key=sex,value=f
key=address,value=中國北京

10 函式

函式是組織好的,可重復使用的,用來實作單一,或相關聯功能的代碼段,

函式能提高應用的模塊性,和代碼的重復利用率,你已經知道Python提供了許多內建函式,比如print(),但你也可以自己創建函式,這被叫做用戶自定義函式,

10.1 定義函式

語法:

def 函式名(引數串列):
    函式體

例:

# 定義一個函式,能夠完成列印資訊的功能
def printInfo():
    print ('------------------------------------')
    print ('         人生苦短,我用Python')
    print ('------------------------------------')

定義函式的規則:

  • 函式代碼塊以 def 關鍵詞開頭,后接函式識別符號名稱和圓括號 ()
  • 任何傳入引數和自變數必須放在圓括號中間,圓括號之間可以用于定義引數,
  • 函式的第一行陳述句可以選擇性地使用檔案字串—用于存放函式說明,
  • 函式內容以冒號 : 起始,并且縮進,
  • return [運算式] 結束函式,選擇性地回傳一個值給呼叫方,不帶運算式的 return 相當于回傳 None,

10.2 呼叫函式

定義了函式之后,就相當于有了一個具有某些功能的代碼,想要讓這些代碼能夠執行,需要呼叫它

呼叫函式很簡單的,通過 函式名() 即可完成呼叫,例:

    # 定義完函式后,函式是不會自動執行的,需要呼叫它才可以
    printInfo()

10.3 函式的注釋

在函式定義下面使用'''進行注釋,使用help函式可以查看函式的注釋,

def test(a1, a2):
    '''
    用來完成對2個數求和"
    :param a1:第一個引數
    :param a2:第二個引數
    :return:無
    '''
    print("%d" % (a1 + a2))


print(help(test))

運行結果:

test(a1, a2)
    用來完成對2個數求和"
    :param a1:第一個引數
    :param a2:第二個引數
    :return:無

None

10.4 函式的引數

10.4.1 引數的定義

? 引數分形參、實參

形參:函式定義時括號內的引數

實參:函式呼叫時括號內的引數

形參相當于變數,實參相當于變數的值,

def add2num(a, b):
    c = a + b
    print(c)
    
add2num(11, 22)  # 呼叫帶有引數的函式時,需要在小括號中,傳遞資料

a,b為形參;11,12為實參

形參:

只在被呼叫時,才分配記憶體單元,呼叫結束,立刻釋放所分配的記憶體,

只在函式內部有效,

實參:

可以是:常量、變數、運算式、函式,

進行函式呼叫時,實參必須是確定的值,

10.4.2 引數的分類

Python的函數除了正常定義的必選引數外,還可以使用默認引數、可變引數和關鍵字引數,使得函式定義出來的介面,不但能處理復雜的引數,還可以簡化呼叫者的代碼,

1)位置引數

位置形參:函式定義時,從左往右寫的引數,比如上面的 a, b

位置實參:函式呼叫時,從左往右寫的引數, 比如上面的 11,12

位置形參定義多少個,呼叫時位置實參必須寫上多少個,多一個少一個都不行,

2)關鍵引數:

正常情況下,給函式傳引數,要按順序,如果不想按順序,就用關鍵引數,

指定引數名的引數,就叫做關鍵引數,

函式呼叫時:func(a=1, b=2), 這種指定了引數名的引數,就是關鍵引數,

呼叫函式時,關鍵引數可以和位置引數一起用,但是關鍵引數必須在位置引數的后面,不然會報錯,

例:

def add2num(a, b):
    c = a + b
    print(c)

#正確的呼叫方式
add2num(11, b=22)  # 呼叫帶有引數的函式時,需要在小括號中,傳遞資料
add2num(a=11, b=22)
add2num(b=11, a=22)
# 錯誤的呼叫方式,
#add2num(22, a=22)
#add2num(b=11,22)

3)默認引數

函式定義時,默認引數必須在位置形參的后面,

函式呼叫時,指定引數名的引數,叫關鍵引數,

而在函式定義時,給引數名指定值的時候,這個引數叫做默認引數,

關鍵引數,和默認引數兩個引數寫法一樣,區別在于:

關鍵引數是在函式呼叫時,指定實參的引數名,也可以說指定值的引數名,

默認引數是在函式定義時,指定引數名的值,

定義時,有默認引數的話,呼叫時,這個實參可以不寫,如果實參不寫的話,這個形參的引數值是他的默認值,

例:

def add2num(a, b=100):
    c = a + b
    print(c)


add2num(11, b=22)  # 呼叫帶有引數的函式時,需要在小括號中,傳遞資料
add2num(11)

運行結果:

33
111

4 ) 動態引數:*args **kwargs

*args

針對函式定義時的*:

def func(a, b, *args):

pass

*args會接收函式呼叫時,傳入的多余的位置實參,

*args 是一個元組

例子:

func(1, 2, 3, 4, 5, 6) 函式呼叫,因為函式定義時,*args前面有形參a, 形參b, *args就接收呼叫時多余的位置實參

a為1, b為2, *args 為: (3, 4, 5, 6),是一個元組,

針對函式呼叫時的 *:

func(1, 2, *[1, 2, 3, 4]) == func(1, 2, 1, 2, 3, 4)

函式呼叫時有*, 就應該立馬將*后面的串列,元組,字串之類的迭代器,打散成位置引數來看,

注意,如果 *后面是一個字典的話,那么打散成的位置引數就是字典的key

*可以看做是for回圈,

形參中 *args 只能接收多余的位置實參,成為一個元組,不能接收關鍵實參,

例:

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum
nums = [1, 2, 3]
# 呼叫方式1
print(calc(nums[0], nums[1], nums[2]))
#呼叫方式2
print(calc(*nums))

運行結果:

14
14

**kwargs:

針對函式定義時,站在形參的角度看 **:

接收多余的關鍵實參,成為一個字典dict,

字典的key是關鍵實參的變數名,字典的value是關鍵實參的值,

將字典交給**后面的變數名,這里是kwargs

站在實參的角度看 ** :

d = {‘x’:1, ‘y’:2, ‘z’:333}

func(**d) # 等價于func(x=1,y=2,z=333)

函式呼叫時,后面可以接一個字典,然后會把字典打散成關鍵引數的形式,也就是key=value的形式,

例:

def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

#呼叫方式1
print(person('Michael', 30))
#呼叫方式2
print(person('Bob', 35, city='Beijing'))
#呼叫方式3
print(person('Adam', 45, gender='M', job='Engineer'))

運行結果:

name: Michael age: 30 other: {}
None
name: Bob age: 35 other: {'city': 'Beijing'}
None
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
None

5)混合引數時,引數順序

函式定義時:

從左往右:位置形參 > *args > 默認引數 > **kwargs

位置形參 > 默認引數 > *args > **kwargs 也可以,

因為函式呼叫時給的實參滿足了位置形參、默認引數之后,會把多余的位置實參給args,這樣并不會報錯,

但是 **kwargs 必須在 *args后面

默認形參必須在位置形參后面

? 函式呼叫時:

從左到右:位置實參 > *args > 關鍵引數 > **kwargs

因為 * args 在函式呼叫時,會被打散成位置實參,而關鍵引數必須在位置實參的后面,否則會報錯,SyntaxError: positional argument follows keyword argument

*args 必須在 **kwargs后面, 否則會報語法錯誤:SyntaxError: iterable argument unpacking follows keyword argument unpacking

總結

Python的函式具有非常靈活的引數形態,既可以實作簡單的呼叫,又可以傳入非常復雜的引數,

默認引數一定要用不可變物件,如果是可變物件,程式運行時會有邏輯錯誤!

要注意定義可變引數和關鍵字引數的語法:

*args是可變引數,args接收的是一個tuple;

**kw是關鍵字引數,kw接收的是一個dict,

以及呼叫函式時如何傳入可變引數和關鍵字引數的語法:

可變引數既可以直接傳入:func(1, 2, 3),又可以先組裝list或tuple,再通過*args傳入:func(*(1, 2, 3))

關鍵字引數既可以直接傳入:func(a=1, b=2),又可以先組裝dict,再通過**kw傳入:func(**{'a': 1, 'b': 2})

使用*args**kw是Python的習慣寫法,當然也可以用其他引數名,但最好使用習慣用法,

命名的關鍵字引數是為了限制呼叫者可以傳入的引數名,同時可以提供默認值,

定義命名的關鍵字引數在沒有可變引數的情況下不要忘了寫分隔符*,否則定義的將是位置引數,

10.4.3 引數的傳遞

Python引數傳遞采用的肯定是“傳物件參考”的方式,這種方式相當于傳值和傳參考的一種綜合,如果函式收到的是一個可變物件(比如字典或者串列)的參考,就能修改物件的原始值--相當于通過“傳參考”來傳遞物件,如果函式收到的是一個不可變物件(比如數字、字符或者元組)的參考,就不能直接修改原始物件--相當于通過“傳值’來傳遞物件,

例:

attrList = [0, 1, 2, 3, 4, 5]
print("改變前————————————————————————————————")
print(attrList)
def func(i, attrList):
    attrList[i] = attrList[i] * 10


print("改變后————————————————————————————————")
for i in range(3):
    func(i, attrList)
print(attrList)

運行結果:

改變前————————————————————————————————
[0, 1, 2, 3, 4, 5]
改變后————————————————————————————————
[0, 10, 20, 3, 4, 5]

可以看到,List發生了改變,如果傳入不可變的元素呢?

a = 10
print("改變前————————————————————————————————")
print(a)


def func(c):
    print(id(c))
    c += 2
    print(id(c))
    print("func函式的c值:", c)

print(id(a))
func(a)
print("改變后————————————————————————————————")
print(a)
print(id(a))

運行結果:

改變前————————————————————————————————
10
140724141828160
140724141828160
140724141828224
func函式的c值: 12
改變后————————————————————————————————
10
140724141828160

將a變數作為引數傳遞給了func函式,傳遞了a的一個參考,把a的地址傳遞過去了,所以在函式內獲取的變數c的地址跟變數a的地址是一樣的,但是在函式內,對c進行賦值運算,c的值從10變成了12,實際上10和12所占的記憶體空間都還是存在的,賦值運算后,c指向12所在的記憶體,而a仍然指向10所在的記憶體,所以后面列印a,其值還是10.

10.5 函式的回傳值

想要在函式中把結果回傳給呼叫者,需要在函式中使用return,例:

def add2num(a, b):
    c = a + b
    return c


print(add2num(1, 2))

可以回傳多個回傳值,例:

def divid(a, b):
    shang = a // b
    yushu = a % b
    return shang, yushu


sh, yu = divid(5, 2)

10.6 區域變數與全域變數

  • 區域變數就是定義在一個函式體內部的變數

  • 全域變數是定義在外面的變數

    例:

    a = 1
    def f():
        b = 2
    

    其中a就是全域變數,而b是區域變數,區域變數只在函式體內部有效,出了函式體,外面是訪問不到的,而全域變數則對下面的代碼都有效,

    全域變數可以直接在函式體內容部使用的,你可以直接訪問,但是注意的是,如果對于不可變型別的資料,如果在函式里面進行了賦值操作,則對外面的全域變數不產生影響,因為相當于新建了一個區域變數,只是名字和全域一樣,而對于可變型別,如果使用賦值陳述句,同樣對外部不產生影響,但是使用方法的話就會對外部產生影響,

    g_b = 3
    g_l1 = [1, 2]
    g_l2 = [1, 2, 3]
    
    
    def t1():
        g_b = 2
        g_l1 = []
        g_l2.append(7)
    
    
    t1()
    print(g_b, g_l1, g_l2)
    

    運行結果:3 [1, 2] [1, 2, 3, 7]

    global關鍵字
    上面說到,如果使用的是賦值陳述句,在函式內部相當于新建了一個變數,并且重新給了指向,但是有時候我們想把這個變數就是外部的那個全域變數,在賦值操作的時候,就是對全域變數給了重新的指向,這個時候可以通過global關鍵字表示我在函式里面的這個變數是使用的全域那個,使用方法如下:

g_b = 3


def t1():
    global g_b
    g_b = 2


t1()
print(g_b)

運行結果:2

這個時候你會發現全域變數g_b也重新指向了,這是因為global g_b表示指定了函式中的g_b就是外面的那個,

10.7 遞回函式

如果一個函式在內部呼叫自身本身,這個函式就是遞回函式,例:

def fact(n):
    if n == 1:
        return 1
    return n * fact(n - 1)


print(fact(5))

運行結果:120

可以根據函式定義看到計算程序如下:

===> fact(5)
===> 5 * fact(4)
===> 5 * (4 * fact(3))
===> 5 * (4 * (3 * fact(2)))
===> 5 * (4 * (3 * (2 * fact(1))))
===> 5 * (4 * (3 * (2 * 1)))
===> 5 * (4 * (3 * 2))
===> 5 * (4 * 6)
===> 5 * 24
===> 120

遞回函式的優點是定義簡單,邏輯清晰,理論上,所有的遞回函式都可以寫成回圈的方式,但回圈的邏輯不如遞回清晰,

使用遞回函式需要注意防止堆疊溢位,在計算機中,函式呼叫是通過堆疊(stack)這種資料結構實作的,每當進入一個函式呼叫,堆疊就會加一層堆疊幀,每當函式回傳,堆疊就會減一層堆疊幀,由于堆疊的大小不是無限的,所以,遞回呼叫的次數過多,會導致堆疊溢位,可以試試fact(1000),

解決遞回呼叫堆疊溢位的方法是通過尾遞回優化,事實上尾遞回和回圈的效果是一樣的,所以,把回圈看成是一種特殊的尾遞回函式也是可以的,

尾遞回是指,在函式回傳的時候,呼叫自身本身,并且,return陳述句不能包含運算式,這樣,編譯器或者解釋器就可以把尾遞回做優化,使遞回本身無論呼叫多少次,都只占用一個堆疊幀,不會出現堆疊溢位的情況,

上面的fact(n)函式由于return n * fact(n - 1)引入了乘法運算式,所以就不是尾遞回了,要改成尾遞回方式,需要多一點代碼,主要是要把每一步的乘積傳入到遞回函式中,例:

def fact(n):
    return fact_iter(n, 1)

def fact_iter(num, product):
    if num == 1:
        return product
    return fact_iter(num - 1, num * product)

可以看到,return fact_iter(num - 1, num * product)僅回傳遞回函式本身,num - 1和num * product在函式呼叫前就會被計算,不影響函式呼叫,

fact(5)對應的fact_iter(5, 1)的呼叫如下:

===> fact_iter(5, 1)
===> fact_iter(4, 5)
===> fact_iter(3, 20)
===> fact_iter(2, 60)
===> fact_iter(1, 120)
===> 120

尾遞回呼叫時,如果做了優化,堆疊不會增長,因此,無論多少次呼叫也不會導致堆疊溢位,

遺憾的是,大多數編程語言沒有針對尾遞回做優化,Python解釋器也沒有做優化,所以,即使把上面的fact(n)函式改成尾遞回方式,也會導致堆疊溢位,

小結

使用遞回函式的優點是邏輯簡單清晰,缺點是過深的呼叫會導致堆疊溢位,

針對尾遞回優化的語言可以通過尾遞回防止堆疊溢位,尾遞回事實上和回圈是等價的,沒有回圈陳述句的編程語言只能通過尾遞回實作回圈,

Python標準的解釋器沒有針對尾遞回做優化,任何遞回函式都存在堆疊溢位的問題,

10.8 匿名函式

10.8.1 定義

用lambda關鍵詞能創建小型匿名函式,這種函式得名于省略了用def宣告函式的標準步驟,

lambda函式的語法只包含一個陳述句,如下:

    lambda [arg1 [,arg2,.....argn]]:expression

如下實體:

sum = lambda a1, a2: a1 * a2

# 呼叫sum函式
print("Value of total : ", sum(10, 20))
print("Value of total : ", sum(20, 20))

以上實體輸出結果:

Value of total :  200
Value of total :  400

Lambda函式能接收任何數量的引數但只能回傳一個運算式的值

匿名函式不能直接呼叫print,因為lambda需要一個運算式

10.8.2 應用場合

例1:自己定義函式作為引數傳遞

def fun(a, b, opt):
    print("a =", a)
    print("b =", b)
    print("result =", opt(a, b))


fun(1, 2, lambda x, y: x + y)

運行結果:

a = 1
b = 2
result = 3

例2:作為內置函式的引數

想一想,下面的資料如何指定按age或name排序?

stus = [
    {"name":"zhangsan", "age":18}, 
    {"name":"lisi", "age":19}, 
    {"name":"wangwu", "age":17}
]

按name排序:

stus.sort(key=lambda x: x['name'])
print(stus)

運行結果:

[{'name': 'lisi', 'age': 19}, {'name': 'wangwu', 'age': 17}, {'name': 'zhangsan', 'age': 18}]

按age排序:

stus.sort(key=lambda x: x['age'])
print(stus)

運行結果:

[{'name': 'wangwu', 'age': 17}, {'name': 'zhangsan', 'age': 18}, {'name': 'lisi', 'age': 19}]

11 檔案操作

11.1 打開與關閉

11.1.1 打開檔案

在python,使用open函式,可以打開一個已經存在的檔案,或者創建一個新檔案

open(檔案名,訪問模式)

示例如下:

    f = open('test.txt', 'w')

說明:

訪問模式說明
r以只讀方式打開檔案,檔案的指標將會放在檔案的開頭,這是默認模式,
w打開一個檔案只用于寫入,如果該檔案已存在則將其覆寫,如果該檔案不存在,創建新檔案,
a打開一個檔案用于追加,如果該檔案已存在,檔案指標將會放在檔案的結尾,也就是說,新的內容將會被寫入到已有內容之后,如果該檔案不存在,創建新檔案進行寫入,
rb以二進制格式打開一個檔案用于只讀,檔案指標將會放在檔案的開頭,這是默認模式,
wb以二進制格式打開一個檔案只用于寫入,如果該檔案已存在則將其覆寫,如果該檔案不存在,創建新檔案,
ab以二進制格式打開一個檔案用于追加,如果該檔案已存在,檔案指標將會放在檔案的結尾,也就是說,新的內容將會被寫入到已有內容之后,如果該檔案不存在,創建新檔案進行寫入,
r+打開一個檔案用于讀寫,檔案指標將會放在檔案的開頭,
w+打開一個檔案用于讀寫,如果該檔案已存在則將其覆寫,如果該檔案不存在,創建新檔案,
a+打開一個檔案用于讀寫,如果該檔案已存在,檔案指標將會放在檔案的結尾,檔案打開時會是追加模式,如果該檔案不存在,創建新檔案用于讀寫,
rb+以二進制格式打開一個檔案用于讀寫,檔案指標將會放在檔案的開頭,
wb+以二進制格式打開一個檔案用于讀寫,如果該檔案已存在則將其覆寫,如果該檔案不存在,創建新檔案,
ab+以二進制格式打開一個檔案用于追加,如果該檔案已存在,檔案指標將會放在檔案的結尾,如果該檔案不存在,創建新檔案用于讀寫,

11.1.2 關閉檔案

close( )

示例如下:

    # 新建一個檔案,檔案名為:test.txt
    f = open('test.txt', 'w')

    # 關閉這個檔案
    f.close()

11.2 檔案的讀寫

11.2.1 寫資料(write)

使用write()可以完成向檔案寫入資料,例:

f = open('test.txt', 'w')
f.write('hello 大家好, 我是AI浩')
f.close()

運行現象:

image-20210831144255382

注意:

  • 如果檔案不存在那么創建,如果存在那么就先清空,然后寫入資料

11.2.2 讀資料(read)

使用read(num)可以從檔案中讀取資料,num表示要從檔案中讀取的資料的長度(單位是位元組),如果沒有傳入num,那么就表示讀取檔案中所有的資料,例:

f = open('test.txt', 'r')
content = f.read(5)
print(content)
print("-"*30)
content = f.read()
print(content)
f.close()

運行結果:

hello
------------------------------
 大家好, 我是AI浩

注意:

  • 如果open是打開一個檔案,那么可以不用謝打開的模式,即只寫 open('test.txt')
  • 如果使用讀了多次,那么后面讀取的資料是從上次讀完后的位置開始的

11.2.3 讀資料(readlines)

就像read沒有引數時一樣,readlines可以按照行的方式把整個檔案中的內容進行一次性讀取,并且回傳的是一個串列,其中每一行的資料為一個元素

#coding=utf-8

f = open('test.txt', 'r')
content = f.readlines()
print(type(content))
i=1
for temp in content:
    print("%d:%s"%(i, temp))
    i+=1
f.close()

運行結果:

<class 'list'>
1:hello 大家好, 我是AI浩

11.2.4 讀資料(readline)

#coding=utf-8

f = open('test.txt', 'r')
content = f.readline()
print("1:%s"%content)
content = f.readline()
print("2:%s"%content)

f.close()

運行結果:

1:hello 大家好, 我是AI浩

2:asfsifhiudh

11.3 檔案的常用操作

11.3.1 獲取當前讀寫的位置

在讀寫檔案的程序中,如果想知道當前的位置,可以使用tell()來獲取,例:

# 打開一個已經存在的檔案
f = open("test.txt", "r")
str = f.read(3)
print("讀取的資料是 : ", str)
# 查找當前位置
position = f.tell()
print("當前檔案位置 : ", position)
str = f.read(3)
print("讀取的資料是 : ", str)
# 查找當前位置
position = f.tell()
print("當前檔案位置 : ", position)
f.close()

運行結果:

讀取的資料是 :  hel
當前檔案位置 :  3
讀取的資料是 :  lo 
當前檔案位置 :  6

11.3.2 定位到某個位置

如果在讀寫檔案的程序中,需要從另外一個位置進行操作的話,可以使用seek()

seek(offset, from)有2個引數

  • offset:偏移量
  • from:方向
    • 0:表示檔案開頭
    • 1:表示當前位置
    • 2:表示檔案末尾

例1:把位置設定為:從檔案開頭,偏移5個位元組

# 打開一個已經存在的檔案
f = open("test.txt", "r")
str = f.read(30)
print("讀取的資料是 : ", str)

# 查找當前位置
position = f.tell()
print("當前檔案位置 : ", position)
# 重新設定位置
f.seek(5, 0)
# 查找當前位置
position = f.tell()
print("當前檔案位置 : ", position)
f.close()

例2:把位置設定為:離檔案末尾,3位元組處

# 打開一個已經存在的檔案
f = open("test.txt", "rb")
print("讀取的資料是 : ", str)
position = f.tell()
print("當前檔案位置 : ", position)

# 重新設定位置
f.seek(-3, 2)

# 讀取到的資料為:檔案最后3個位元組資料
str = f.read()
print("讀取的資料是 : ", str)

f.close()

運行結果:

讀取的資料是 :  <class 'str'>
當前檔案位置 :  0
讀取的資料是 :  b'ddf'

11.3.3 檔案重命名

os模塊中的rename()可以完成對檔案的重命名操作

rename(需要修改的檔案名, 新的檔案名)

import os

os.rename("test.txt", "test-1.txt")

11.3.4 洗掉檔案

os模塊中的remove()可以完成對檔案的洗掉操作

remove(待洗掉的檔案名)

    import os
    os.remove("test.txt")

11.4 檔案夾的相關操作

實際開發中,有時需要用程式的方式對檔案夾進行一定的操作,比如創建、洗掉等

就像對檔案操作需要os模塊一樣,如果要操作檔案夾,同樣需要os模塊

11.4.1 創建檔案夾

    import os

    os.mkdir("aa")

11.4.2 獲取當前目錄

    import os

    os.getcwd()

11.4.3 改變默認目錄

    import os

    os.chdir("../")

11.4.4 獲取目錄串列

    import os

    os.listdir("./")

11.4.5 洗掉檔案夾

    import os

    os.rmdir("張三")

11.4.6 檢測檔案夾是否存在

import os
if not os.path.exists(path):
      os.makedirs(path)

11.4.7 創建多級檔案夾

import os
os.makedirs(opDir)

12 面向物件編程

面向物件編程——Object Oriented Programming,簡稱OOP,是一種程式設計思想,OOP把物件作為程式的基本單元,一個物件包含了資料和操作資料的函式,

面向程序的程式設計把計算機程式視為一系列的命令集合,即一組函式的順序執行,為了簡化程式設計,面向程序把函式繼續切分為子函式,即把大塊函式通過切割成小塊函式來降低系統的復雜度,

而面向物件的程式設計把計算機程式視為一組物件的集合,而每個物件都可以接收其他物件發過來的訊息,并處理這些訊息,計算機程式的執行就是一系列訊息在各個物件之間傳遞,

在Python中,所有資料型別都可以視為物件,當然也可以自定義物件,自定義的物件資料型別就是面向物件中的類(Class)的概念,

12.1 類和物件

面向物件最重要的概念就是類(Class)和實體(Instance),必須牢記類是抽象的模板,比如Student類,而實體是根據類創建出來的一個個具體的“物件”,每個物件都擁有相同的方法,但各自的資料可能不同,

12.1.1 類

人以類聚 物以群分,
具有相似內部狀態和運動規律的物體的集合(或統稱為抽象), 
具有相同屬性和行為事物的統稱

類是抽象的,在使用的時候通常會找到這個類的一個具體的存在,使用這個具體的存在,一個類可以找到多個物件

12.2.2 物件

某一個具體事物的存在 ,在現實世界中可以是看得見摸得著的,
可以是直接使用的

12.2.3 類和物件的關系

類是創建實體的模板,而實體則是一個一個具體的物件,各個實體擁有的資料都互相獨立,互不影響;

12.2.4 定義類

定義一個類,格式如下:

class 類名:
    方法串列

例:定義一個Car類

# 定義類
class Car:
    # 方法
    def getCarInfo(self):
        print('車輪子個數:%d, 顏色%s'%(self.wheelNum, self.color))

    def move(self):
        print("車正在移動...")

說明:

  • 定義類時有2種:新式類和經典類,上面的Car為經典類,如果是Car(object)則為新式類
  • 類名 的命名規則按照"大駝峰"

12.2.5 創建物件

通過上一節,定義了一個Car類;就好比有車一個張圖紙,那么接下來就應該把圖紙交給生成工人們去生成了

python中,可以根據已經定義的類去創建出一個個物件

創建物件的格式為:

物件名 = 類名()

創建物件demo:

# 定義類
class Car:
    # 移動
    def move(self):
        print('車在奔跑...')

    # 鳴笛
    def toot(self):
        print("車在鳴笛...嘟嘟..")


# 創建一個物件,并用變數BMW來保存它的參考
BMW = Car()
BMW.color = '黑色'
BMW.wheelNum = 4 #輪子數量
BMW.move()
BMW.toot()
print(BMW.color)
print(BMW.wheelNum)

運行結果:

車在奔跑...
車在鳴笛...嘟嘟..
黑色
4

12.2.6 __init__()方法

1)使用方式

def 類名:
    #初始化函式,用來完成一些默認的設定
    def __init__():
        pass

2)__init__()方法的呼叫

# 定義汽車類
class Car:

    def __init__(self):
        self.wheelNum = 4
        self.color = '藍色'

    def move(self):
        print('車在跑,目標:夏威夷')

# 創建物件
BMW = Car()

print('車的顏色為:%s'%BMW.color)
print('車輪胎數量為:%d'%BMW.wheelNum)

運行結果:

車的顏色為:藍色
車輪胎數量為:4

12.2.7 魔法方法

1)列印id()

如果把BMW使用print進行輸出的話,會看到如下的資訊,例:

# 定義汽車類
class Car:

    def __init__(self):
        self.wheelNum = 4
        self.color = '藍色'

    def move(self):
        print('車在跑,目標:夏威夷')

# 創建物件
BMW = Car()

print(BMW)

運行結果:

<__main__.Car object at 0x0000014F596F8400>

即看到的是創建出來的BMW物件在記憶體中的地址

2) 定義__str__()方法

class Car:
    def __init__(self, newWheelNum, newColor):
        self.wheelNum = newWheelNum
        self.color = newColor
    def __str__(self):
        msg = "嘿,,,我的顏色是" + self.color + "我有" + str(self.wheelNum) + "個輪胎..."
        return msg

    def move(self):
        print('車在跑,目標:夏威夷')


BMW = Car(4, "白色")
print(BMW)

運行結果:

嘿,,,我的顏色是白色我有4個輪胎...

3)定義__del__()方法

創建物件后,python解釋器默認呼叫__init__()方法;

當洗掉一個物件時,python解釋器也會默認呼叫一個方法,這個方法為__del__()方法

import time


class Animal(object):
    # 初始化方法
    # 創建完物件后會自動被呼叫
    def __init__(self, name):
        print('__init__方法被呼叫')
        self.__name = name

    # 析構方法
    # 當物件被洗掉時,會自動被呼叫
    def __del__(self):
        print("__del__方法被呼叫")
        print("%s物件馬上被干掉了..." % self.__name)


# 創建物件
dog = Animal("哈皮狗")
# 洗掉物件
del dog
cat = Animal("波斯貓")
cat2 = cat
cat3 = cat
print("---馬上 洗掉cat物件")
del cat
print("---馬上 洗掉cat2物件")
del cat2
print("---馬上 洗掉cat3物件")
del cat3
print("程式2秒鐘后結束")
time.sleep(2)

運行結果:

__init__方法被呼叫
__del__方法被呼叫
哈皮狗物件馬上被干掉了...
__init__方法被呼叫
---馬上 洗掉cat物件
---馬上 洗掉cat2物件
---馬上 洗掉cat3物件
__del__方法被呼叫
波斯貓物件馬上被干掉了...
程式2秒鐘后結束
  • 當有1個變數保存了物件的參考時,此物件的參考計數就會加1
  • 當使用del洗掉變數指向的物件時,如果物件的參考計數不會1,比如3,那么此時只會讓這個參考計數減1,即變為2,當再次呼叫del時,變為1,如果再呼叫1次del,此時會真的把物件進行洗掉

總結

  • 在python中方法名如果是__xxxx__()的,那么就有特殊的功能,因此叫做“魔法”方法
  • 當使用print輸出物件的時候,只要自己定義了__str__(self)方法,那么就會列印從在這個方法中return的資料

常用的魔法方法串列

魔法方法含義
基本的魔法方法
_new_(cls[, …])1. new 是在一個物件實體化的時候所呼叫的第一個方法 2. 它的第一個引數是這個類,其他的引數是用來直接傳遞給 init 方法 3. new 決定是否要使用該 init 方法,因為 new 可以呼叫其他類的構造方法或者直接回傳別的實體物件來作為本類的實體,如果 new 沒有回傳實體物件,則 init 不會被呼叫 4. new 主要是用于繼承一個不可變的型別比如一個 tuple 或者 string
_init_(self[, …])構造器,當一個實體被創建的時候呼叫的初始化方法
_del_(self)析構器,當一個實體被銷毀的時候呼叫的方法
_call_(self[, args…])允許一個類的實體像函式一樣被呼叫:x(a, b) 呼叫 x.call(a, b)
_len_(self)定義當被 len() 呼叫時的行為
_repr_(self)定義當被 repr() 呼叫時的行為
_str_(self)定義當被 str() 呼叫時的行為
_bytes_(self)定義當被 bytes() 呼叫時的行為
_hash_(self)定義當被 hash() 呼叫時的行為
_bool_(self)定義當被 bool() 呼叫時的行為,應該回傳 True 或 False
_format_(self, format_spec)定義當被 format() 呼叫時的行為
有關屬性
_getattr_(self, name)定義當用戶試圖獲取一個不存在的屬性時的行為
_getattribute_(self, name)定義當該類的屬性被訪問時的行為
_setattr_(self, name, value)定義當一個屬性被設定時的行為
_delattr_(self, name)定義當一個屬性被洗掉時的行為
_dir_(self)定義當 dir() 被呼叫時的行為
_get_(self, instance, owner)定義當描述符的值被取得時的行為
_set_(self, instance, value)定義當描述符的值被改變時的行為
_delete_(self, instance)定義當描述符的值被洗掉時的行為
比較運算子
_lt_(self, other)定義小于號的行為:x < y 呼叫 x.lt(y)
_le_(self, other)定義小于等于號的行為:x <= y 呼叫 x.le(y)
_eq_(self, other)定義等于號的行為:x == y 呼叫 x.eq(y)
_ne_(self, other)定義不等號的行為:x != y 呼叫 x.ne(y)
_gt_(self, other)定義大于號的行為:x > y 呼叫 x.gt(y)
_ge_(self, other)定義大于等于號的行為:x >= y 呼叫 x.ge(y)
算數運算子
_add_(self, other)定義加法的行為:+
_sub_(self, other)定義減法的行為:-
_mul_(self, other)定義乘法的行為:*
_truediv_(self, other)定義真除法的行為:/
_floordiv_(self, other)定義整數除法的行為://
_mod_(self, other)定義取模演算法的行為:%
_divmod_(self, other)定義當被 divmod() 呼叫時的行為
_pow_(self, other[, modulo])定義當被 power() 呼叫或 ** 運算時的行為
_lshift_(self, other)定義按位左移位的行為:<<
_rshift_(self, other)定義按位右移位的行為:>>
_and_(self, other)定義按位與操作的行為:&
_xor_(self, other)定義按位異或操作的行為:^
_or_(self, other)定義按位或操作的行為:|
反運算
_radd_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rsub_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rmul_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rtruediv_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rfloordiv_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rmod_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rdivmod_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rpow_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rlshift_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rrshift_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_rxor_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
_ror_(self, other)(與上方相同,當左運算元不支持相應的操作時被呼叫)
增量賦值運算
_iadd_(self, other)定義賦值加法的行為:+=
_isub_(self, other)定義賦值減法的行為:-=
_imul_(self, other)定義賦值乘法的行為:*=
_itruediv_(self, other)定義賦值真除法的行為:/=
_ifloordiv_(self, other)定義賦值整數除法的行為://=
_imod_(self, other)定義賦值取模演算法的行為:%=
_ipow_(self, other[, modulo])定義賦值冪運算的行為:**=
_ilshift_(self, other)定義賦值按位左移位的行為:<<=
_irshift_(self, other)定義賦值按位右移位的行為:>>=
_iand_(self, other)定義賦值按位與操作的行為:&=
_ixor_(self, other)定義賦值按位異或操作的行為:^=
_ior_(self, other)定義賦值按位或操作的行為:|=
一元運算子
_neg_(self)定義正號的行為:+x
_pos_(self)定義負號的行為:-x
_abs_(self)定義當被 abs() 呼叫時的行為
_invert_(self)定義按位求反的行為:~x
型別轉換
_complex_(self)定義當被 complex() 呼叫時的行為(需要回傳恰當的值)
_int_(self)定義當被 int() 呼叫時的行為(需要回傳恰當的值)
_float_(self)定義當被 float() 呼叫時的行為(需要回傳恰當的值)
_round_(self[, n])定義當被 round() 呼叫時的行為(需要回傳恰當的值)
_index_(self)1. 當物件是被應用在切片運算式中時,實作整形強制轉換 2. 如果你定義了一個可能在切片時用到的定制的數值型,你應該定義 index 3. 如果 index 被定義,則 int 也需要被定義,且回傳相同的值
背景關系管理(with 陳述句)
_enter_(self)1. 定義當使用 with 陳述句時的初始化行為 2. enter 的回傳值被 with 陳述句的目標或者 as 后的名字系結
_exit_(self, exc_type, exc_value, traceback)1. 定義當一個代碼塊被執行或者終止后背景關系管理器應該做什么 2. 一般被用來處理例外,清除作業或者做一些代碼塊執行完畢之后的日常作業
容器型別
_len_(self)定義當被 len() 呼叫時的行為(回傳容器中元素的個數)
_getitem_(self, key)定義獲取容器中指定元素的行為,相當于 self[key]
_setitem_(self, key, value)定義設定容器中指定元素的行為,相當于 self[key] = value
_delitem_(self, key)定義洗掉容器中指定元素的行為,相當于 del self[key]
_iter_(self)定義當迭代容器中的元素的行為
_reversed_(self)定義當被 reversed() 呼叫時的行為
_contains_(self, item)定義當使用成員測驗運算子(in 或 not in)時的行為

12.2.8 self

self可以理解為自己,類似C#中的this,例:

# 定義一個類
class Animal:

    # 方法
    def __init__(self, name):
        self.name = name

    def printName(self):
        print('名字為:%s' % self.name)


# 定義一個函式
def myPrint(animal):
    animal.printName()


dog1 = Animal('淘淘')
myPrint(dog1)
dog2 = Animal('貝貝')
myPrint(dog2)

運行結果:

名字為:淘淘
名字為:貝貝

總結

所謂的self,可以理解為自己

可以把self當做C++中類里面的this指標一樣理解,就是物件自身的意思

某個物件呼叫其方法時,python解釋器會把這個物件作為第一個引數傳遞給self,所以開發者只需要傳遞后面的引數即可

12.2 屬性

屬性分為類屬性和實體屬性,

類屬性就是屬于類所有,可以直接用類名.屬性名直接呼叫,類的屬性在記憶體中只有一份,實體屬性就是在__init__()方法中初始化的屬性;
實體屬性屬于類的物件所有,可以用物件名.屬性名的形式進行呼叫,但是不能用類名.屬性名進行呼叫 ,因為實體屬性只有在實體創建時,才會初始化創建,

12.2.1 類屬性

類屬性就是類物件所擁有的屬性,它被所有類物件實體物件所共有,在記憶體中只存在一個副本,這個和C#中類的靜態成員變數有點類似,對于公有的類屬性,在類外可以通過類物件實體物件訪問,例:

class People(object):
    name = 'Tom'  #公有的類屬性
    __age = 12     #私有的類屬性

p = People()

print(p.name)           #正確
print(People.name)      #正確
print(p.__age)            #錯誤,不能在類外通過實體物件訪問私有的類屬性
print(People.__age)        #錯誤,不能在類外通過類物件訪問私有的類屬性

類屬性的訪問:

import time


class Test(object):
    name = 'scolia'


a = Test()
print(Test.name)  # 通過類進行訪問
print(a.name)  # 通過實體進行訪問

運行結果:

scolia
scolia

可以訪問的,但是,試圖修改這個屬性的話:

class Test(object):
    name = 'scolia'


a = Test()
Test.name = 'scolia good'  # 通過類進行修改
print(Test.name)
print(a.name)

運行結果:

scolia good
scolia good

我們發現兩者都修改成功了,再嘗試通過實體來修改屬性的話:

class Test(object):
    name = 'scolia'

a = Test()
a.name = 'scolia good'  # 通過實體進行修改
print(Test.name)
print(a.name)

運行結果:

scolia
scolia good

我們發現類的屬性沒有修改,而實體的屬性則修改成功了,這究竟是為什么?

其實這里的情況非常類似于區域作用域和全域作用域,

我在函式內訪問變數時,會先在函式內部查詢有沒有這個變數,如果沒有,就到外層中找,這里的情況是我在實體中訪問一個屬性,但是我實體中沒有,我就試圖去創建我的類中尋找有沒有這個屬性,找到了,就有,沒找到,就拋出例外,而當我試圖用實體去修改一個在類中不可變的屬性的時候,我實際上并沒有修改,而是在我的實體中創建了這個屬性,而當我再次訪問這個屬性的時候,我實體中有,就不用去類中尋找了,如果用一張圖來表示的話:

下載

12.2.2 實體屬性(物件屬性)

實體屬性是在_init_(self)方法定義的屬性,屬于物件的本身,只能通過物件.屬性來訪問,不能用過類.屬性來訪問,例:

class People(object):
    address = '山東' #類屬性
    def __init__(self):
        self.name = 'xiaowang' #實體屬性
        self.age = 20 #實體屬性

p = People()
p.age =12 #實體屬性
print(p.address) #正確
print(p.name)    #正確
print(p.age)     #正確

print(People.address) #正確
print(People.name)    #錯誤
print(People.age)     #錯誤

12.2.3 私有屬性

如果有一個物件,當需要對其進行修改屬性時,有2種方法

  • 物件名.屬性名 = 資料 ---->直接修改
  • 物件名.方法名() ---->間接修改

為了更好的保存屬性安全,即不能隨意修改,一般的處理方式為

  • 將屬性定義為私有屬性
  • 添加一個可以呼叫的方法,供呼叫
class People(object):

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

    def getName(self):
        return self.__name

    def setName(self, newName):
        if len(newName) >= 5:
            self.__name = newName
        else:
            print("error:名字長度需要大于或者等于5")

xiaoming = People("AI浩")
print(xiaoming.__name)
Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 16, in <module>
    print(xiaoming.__name)
AttributeError: 'People' object has no attribute '__name'

直接呼叫私有屬性會報錯,我需要定義個方法,呼叫方法

class People(object):

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

    def getName(self):
        return self.__name

    def setName(self, newName):
        if len(newName) >= 5:
            self.__name = newName
        else:
            print("error:名字長度需要大于或者等于5")


xiaoming = People("張三")

xiaoming.setName("wanger")
print(xiaoming.getName())

xiaoming.setName("lisi")
print(xiaoming.getName())

運行結果:

wanger
error:名字長度需要大于或者等于5
wanger

總結

  • 如果需要在類外修改類屬性,必須通過類物件去參考然后進行修改,如果通過實體物件去參考,會產生一個同名的實體屬性,這種方式修改的是實體屬性,不會影響到類屬性,并且之后如果通過實體物件去參考該名稱的屬性,實體屬性會強制屏蔽掉類屬性,即參考的是實體屬性,除非洗掉了該實體屬性
  • Python中沒有像C++中public和private這些關鍵字來區別公有屬性和私有屬性
  • 它是以屬性命名方式來區分,如果在屬性名前面加了2個下劃線’__’,則表明該屬性是私有屬性,否則為公有屬性(方法也是一樣,方法名前面加了2個下劃線的話表示該方法是私有的,否則為公有的),

12.3 繼承

在程式中,繼承描述的是事物之間的所屬關系,例如貓和狗都屬于動物,程式中便可以描述為貓和狗繼承自動物;同理,波斯貓和巴厘貓都繼承自貓,而沙皮狗和斑點狗都繼承足夠,如下如所示:

繼承

# 定義一個父類,如下:
class Cat(object):

    def __init__(self, name, color="白色"):
        self.name = name
        self.color = color

    def run(self):
        print("%s--在跑" % self.name)


# 定義一個子類,繼承Cat類如下:
class Bosi(Cat):

    def setNewName(self, newName):
        self.name = newName

    def eat(self):
        print("%s--在吃" % self.name)


bs = Bosi("印度貓")
print('bs的名字為:%s' % bs.name)
print('bs的顏色為:%s' % bs.color)
bs.eat()
bs.setNewName('波斯')
bs.run()

運行結果:

bs的名字為:印度貓
bs的顏色為:白色
印度貓--在吃
波斯--在跑

結論:

  • 雖然子類沒有定義__init__方法,但是父類有,所以在子類繼承父類的時候這個方法就被繼承了,所以只要創建Bosi的物件,就默認執行了那個繼承過來的__init__方法

  • 子類在繼承的時候,在定義類時,小括號()中為父類的名字

  • 父類的屬性、方法,會被繼承給子類

12.3.1 私有屬性和方法的繼承

class Animal(object):

    def __init__(self, name='動物', color='白色'):
        self.__name = name
        self.color = color

    def __test(self):
        print(self.__name)
        print(self.color)

    def test(self):
        print(self.__name)
        print(self.color)


class Dog(Animal):
    def dogTest1(self):
        # print(self.__name) #不能訪問到父類的私有屬性
        print(self.color)

    def dogTest2(self):
        # self.__test() #不能訪問父類中的私有方法
        self.test()


A = Animal()
# print(A.__name) #程式出現例外,不能訪問私有屬性
print(A.color)
# A.__test() #程式出現例外,不能訪問私有方法
A.test()

print("------分割線-----")

D = Dog(name="小花狗", color="黃色")
D.dogTest1()
D.dogTest2()

運行結果:


白色
動物
白色
------分割線-----
黃色
小花狗
黃色

結論:

私有的屬性,不能通過物件直接訪問,但是可以通過方法訪問
私有的方法,不能通過物件直接訪問
私有的屬性、方法,不會被子類繼承,也不能被訪問
一般情況下,私有的屬性、方法都是不對外公布的,往往用來做內部的事情,起到安全的作用

12.3.2 多繼承

Python中多繼承的格式如下:

# 定義一個父類
class A:
    def printA(self):
        print('----A----')

# 定義一個父類
class B:
    def printB(self):
        print('----B----')

# 定義一個子類,繼承自A、B
class C(A,B):
    def printC(self):
        print('----C----')

obj_C = C()
obj_C.printA()
obj_C.printB()

運行結果:

----A----
----B----

結論:

python中是可以多繼承的
父類中的方法、屬性,子類會繼承

如果父類A和父類B中,有一個同名的方法,那么通過子類去呼叫的時候,呼叫哪個?

# coding=utf-8
class base(object):
    def test(self):
        print('----base test----')


class A(base):
    def test(self):
        print('----A test----')


# 定義一個父類
class B(base):
    def test(self):
        print('----B test----')


# 定義一個子類,繼承自A、B
class C(A, B):
    pass


obj_C = C()
obj_C.test()

print("搜索順序:",C.__mro__)  # 可以查看C類的物件搜索方法時的先后順序

運行結果:

----A test----
搜索順序: (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.base'>, <class 'object'>)

12.3.3 重寫父類方法

所謂重寫,就是子類中,有一個和父類相同名字的方法,在子類中的方法會覆寫掉父類中同名的方法

class Cat(object):
    def sayHello(self):
        print("halou-----1")


class Bosi(Cat):

    def sayHello(self):
        print("halou-----2")


bosi = Bosi()
bosi.sayHello()

運行結果:

halou-----2

12.3.4 呼叫父類的方法

呼叫父類的__init__方法

#coding=utf-8
class Cat(object):
    def __init__(self,name):
        self.name = name
        self.color = 'yellow'


class Bosi(Cat):

    def __init__(self,name):
        # 呼叫父類的__init__方法1(python2)
        #Cat.__init__(self,name)
        # 呼叫父類的__init__方法2
        #super(Bosi,self).__init__(name)
        # 呼叫父類的__init__方法3
        super().__init__(name)

    def getName(self):
        return self.name

bosi = Bosi('xiaohua')
print(bosi.name)
print(bosi.color)

運行結果:

xiaohua
yellow

呼叫父類的普通方法

# 父類
class Dog:
  def bark(self):
    print("汪汪叫")
# 子類 繼承
class XiaoTianQuan(Dog):
  def fly(self):
    print("我會飛")
  # 可以重寫父類中的同名方法
  def bark(self):
    # super().父類方法名 呼叫父類中的方法 (第一種方式)(推薦)
    super().bark()
    # 父類名.方法(self) 呼叫父類中的方法 (第二種方式,python2.x)(不推薦,父類名修改后,此處也得改)
    Dog.bark(self)
    # 注意:如果使用子類名呼叫方法,可能會出現遞回呼叫 -- 死回圈!
    # XiaoTianQuan.bark(self) # 會產生死回圈
    # 針對子類特有的需求,進行擴展
    print("神一樣的叫喚...")
xtq = XiaoTianQuan()
xtq.bark()

運行結果:

汪汪叫
汪汪叫
神一樣的叫喚...

12.4 多型

多型的概念是應用于Java和C#這一類強型別語言中,而Python崇尚“鴨子型別”,

所謂多型:定義時的型別和運行時的型別不一樣,此時就成為多型,例:Python “鴨子型別”

class F1(object):
    def show(self):
        print ('F1.show')

class S1(F1):

    def show(self):
        print ('S1.show')

class S2(F1):

    def show(self):
        print ('S2.show')

def Func(obj):
    print (obj.show())

s1_obj = S1()
Func(s1_obj)
s2_obj = S2()
Func(s2_obj)

運行結果:

S1.show
None
S2.show
None

12.5 靜態方法和類方法

12.5.1 類方法

是類物件所擁有的方法,需要用修飾器@classmethod來標識其為類方法,對于類方法,第一個引數必須是類物件,一般以cls作為第一個引數(當然可以用其他名稱的變數作為其第一個引數,但是大部分人都習慣以’cls’作為第一個引數的名字,就最好用’cls’了),能夠通過實體物件和類物件去訪問,

class People(object):
    country = 'china'

    # 類方法,用classmethod來進行修飾
    @classmethod
    def getCountry(cls):
        return cls.country

p = People()
print(p.getCountry())  # 可以用過實體物件參考
print(People.getCountry())  # 可以通過類物件參考

類方法還有一個用途就是可以對類屬性進行修改:

class People(object):
    country = 'china'

    # 類方法,用classmethod來進行修飾
    @classmethod
    def getCountry(cls):
        return cls.country

    @classmethod
    def setCountry(cls, country):
        cls.country = country


p = People()
print(p.getCountry())  # 可以用過實體物件參考
print(People.getCountry())  # 可以通過類物件參考
p.setCountry('japan')
print(p.getCountry())
print(People.getCountry())

運行結果:

china
china
japan
japan

結果顯示在用類方法對類屬性修改之后,通過類物件和實體物件訪問都發生了改變

12.5.2 靜態方法

需要通過修飾器@staticmethod來進行修飾,靜態方法不需要多定義引數

class People(object):
    country = 'china'

    @staticmethod
    #靜態方法
    def getCountry():
        return People.country


print People.getCountry()

總結

從類方法和實體方法以及靜態方法的定義形式就可以看出來,類方法的第一個引數是類物件cls,那么通過cls參考的必定是類物件的屬性和方法;而實體方法的第一個引數是實體物件self,那么通過self參考的可能是類屬性、也有可能是實體屬性(這個需要具體分析),不過在存在相同名稱的類屬性和實體屬性的情況下,實體屬性優先級更高,靜態方法中不需要額外定義引數,因此在靜態方法中參考類屬性的話,必須通過類物件來參考

13 例外

當Python檢測到一個錯誤時,解釋器就無法繼續執行了,反而出現了一些錯誤的提示,這就是所謂的"例外",

13.1 捕獲例外

13.1.1 捕獲例外 try…except…

看如下示例:

try:
    print('-----test--1---')
    open('123.txt','r')
    print('-----test--2---')
except IOError:
    pass

運行結果:

-----test--1---

說明:

  • 此程式看不到任何錯誤,因為用except 捕獲到了IOError例外,并添加了處理的方法
  • pass 表示實作了相應的實作,但什么也不做;如果把pass改為print陳述句,那么就會輸出其他資訊

小總結:

img

  • 把可能出現問題的代碼,放在try中
  • 把處理例外的代碼,放在except中

13.1.2 except捕獲多個例外

看如下示例:

try:
    print (num)
except IOError:
    print('產生錯誤了')

運行結果如下:

Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 2, in <module>
    print(num)
NameError: name 'num' is not defined

想一想:

上例程式,已經使用except來捕獲例外了,為什么還會看到錯誤的資訊提示?

答:

except捕獲的錯誤型別是IOError,而此時程式產生的例外為 NameError ,所以except沒有生效

修改后的代碼為:

try:
    print (num)
except NameError:
    print('產生錯誤了')

運行結果如下:

產生錯誤了

實際開發中,捕獲多個例外的方式,如下:

#coding=utf-8
try:
    print('-----test--1---')
    open('123.txt','r') # 如果123.txt檔案不存在,那么會產生 IOError 例外
    print('-----test--2---')
    print(num)# 如果num變數沒有定義,那么會產生 NameError 例外

except (IOError,NameError):
    #如果想通過一次except捕獲到多個例外可以用一個元組的方式
    # errorMsg里會保存捕獲到的錯誤資訊
    print(errorMsg)

運行結果:

-----test--1---
Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 4, in <module>
    open('123.txt','r') # 如果123.txt檔案不存在,那么會產生 IOError 例外
FileNotFoundError: [Errno 2] No such file or directory: '123.txt'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 12, in <module>
    print(errorMsg)
NameError: name 'errorMsg' is not defined

注意:

  • 當捕獲多個例外時,可以把要捕獲的例外的名字,放到except 后,并使用元組的方式僅進行存盤

13.1.3 獲取例外的資訊描述

img

img

13.1.4捕獲所有例外

img

img

13.1.5 else

咱們應該對else并不陌生,在if中,它的作用是當條件不滿足時執行的實行;同樣在try…except…中也是如此,即如果沒有捕獲到例外,那么就執行else中的事情

try:
    num = 100
    print (num)
except NameError as errorMsg:
    print('產生錯誤了:%s'%errorMsg)
else:
    print('沒有捕獲到例外,真高興')

運行結果如下:

100
沒有捕獲到例外,真高興

13.1.6 try…finally…

try…finally…陳述句用來表達這樣的情況:

在程式中,如果一個段代碼必須要執行,即無論例外是否產生都要執行,那么此時就需要使用finally, 比如檔案關閉,釋放鎖,把資料庫連接返還給連接池等

demo:

import time
try:
    f = open('test.txt')
    try:
        while True:
            content = f.readline()
            if len(content) == 0:
                break
            time.sleep(2)
            print(content)
    except:
        #如果在讀取檔案的程序中,產生了例外,那么就會捕獲到
        #比如 按下了 ctrl+c
        pass
    finally:
        f.close()
        print('關閉檔案')
except:
    print("沒有這個檔案")

說明:

test.txt檔案中每一行資料列印,但是我有意在每列印一行之前用time.sleep方法暫停2秒鐘,這樣做的原因是讓程式運行得慢一些,在程式運行的時候,按Ctrl+c中斷(取消)程式,

我們可以觀察到KeyboardInterrupt例外被觸發,程式退出,但是在程式退出之前,finally從句仍然被執行,把檔案關閉,

13.2 例外的傳遞

13.2.1. try嵌套中

import time
try:
    f = open('test.txt')
    try:
        while True:
            content = f.readline()
            if len(content) == 0:
                break
            time.sleep(2)
            print(content)
    finally:
        f.close()
        print('關閉檔案')
except:
    print("沒有這個檔案")

運行結果:

沒有這個檔案

13.2.2 函式嵌套呼叫中

def test1():
    print("----test1-1----")
    print(num)
    print("----test1-2----")


def test2():
    print("----test2-1----")
    test1()
    print("----test2-2----")


def test3():
    try:
        print("----test3-1----")
        test1()
        print("----test3-2----")
    except Exception as result:
        print("捕獲到了例外,資訊是:%s" % result)

    print("----test3-2----")


test3()
print("------華麗的分割線-----")
test2()

運行結果:

----test3-1----
----test1-1----
捕獲到了例外,資訊是:name 'num' is not defined
----test3-2----
------華麗的分割線-----
----test2-1----
----test1-1----
Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 26, in <module>
    test2()
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 9, in test2
    test1()
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 3, in test1
    print(num)
NameError: name 'num' is not defined

總結:

  • 如果try嵌套,那么如果里面的try沒有捕獲到這個例外,那么外面的try會接收到這個例外,然后進行處理,如果外邊的try依然沒有捕獲到,那么再進行傳遞,,,
  • 如果一個例外是在一個函式中產生的,例如函式A---->函式B---->函式C,而例外是在函式C中產生的,那么如果函式C中沒有對這個例外進行處理,那么這個例外會傳遞到函式B中,如果函式B有例外處理那么就會按照函式B的處理方式進行執行;如果函式B也沒有例外處理,那么這個例外會繼續傳遞,以此類推,,,如果所有的函式都沒有處理,那么此時就會進行例外的默認處理,即通常見到的那樣
  • 注意觀察上圖中,當呼叫test3函式時,在test1函式內部產生了例外,此例外被傳遞到test3函式中完成了例外處理,而當例外處理完后,并沒有回傳到函式test1中進行執行,而是在函式test3中繼續執行

13.3 拋出自定義的例外

你可以用raise陳述句來引發一個例外,例外/錯誤物件必須有一個名字,且它們應是Error或Exception類的子類

下面是一個引發例外的例子:

class ShortInputException(Exception):
    '''自定義的例外類'''
    def __init__(self, length, atleast):
        #super().__init__()
        self.length = length
        self.atleast = atleast

def main():
    try:
        s = input('請輸入 --> ')
        if len(s) < 3:
            # raise引發一個你定義的例外
            raise ShortInputException(len(s), 3)
    except ShortInputException as result:#x這個變數被系結到了錯誤的實體
        print('ShortInputException: 輸入的長度是 %d,長度至少應是 %d'% (result.length, result.atleast))
    else:
        print('沒有例外發生.')

main()

運行結果如下:

請輸入 --> 11
ShortInputException: 輸入的長度是 2,長度至少應是 3

注意

  • 以上程式中,關于代碼#super().init()的說明

    這一行代碼,可以呼叫也可以不呼叫,建議呼叫,因為__init__方法往往是用來對創建完的物件進行初始化作業,如果在子類中重寫了父類的__init__方法,即意味著父類中的很多初始化作業沒有做,這樣就不保證程式的穩定了,所以在以后的開發中,如果重寫了父類的__init__方法,最好是先呼叫父類的這個方法,然后再添加自己的功能

13.4 例外處理中拋出例外

class Test(object):
    def __init__(self, switch):
        self.switch = switch #開關
    def calc(self, a, b):
        try:
            return a/b
        except Exception as result:
            if self.switch:
                print("捕獲開啟,已經捕獲到了例外,資訊如下:")
                print(result)
            else:
                #重新拋出這個例外,此時就不會被這個例外處理給捕獲到,從而觸發默認的例外處理
                raise


a = Test(True)
a.calc(11,0)

print("----------------------華麗的分割線----------------")

a.switch = False
a.calc(11,0)

運行結果:

捕獲開啟,已經捕獲到了例外,資訊如下:
division by zero
----------------------華麗的分割線----------------
Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 21, in <module>
    a.calc(11,0)
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 6, in calc
    return a/b
ZeroDivisionError: division by zero

14 模塊

14.1 模塊介紹

14.1.1 Python中的模塊

有過C語言編程經驗的朋友都知道在C語言中如果要參考sqrt函式,必須用陳述句#include <math.h>引入math.h這個頭檔案,否則是無法正常進行呼叫的,

那么在Python中,如果要參考一些其他的函式,該怎么處理呢?

在Python中有一個概念叫做模塊(module),這個和C語言中的頭檔案以及Java中的包很類似,比如在Python中要呼叫sqrt函式,必須用import關鍵字引入math這個模塊,下面就來了解一下Python中的模塊,

說的通俗點:模塊就好比是工具包,要想使用這個工具包中的工具(就好比函式),就需要匯入這個模塊

14.1.2 import

在Python中用關鍵字import來引入某個模塊,比如要參考模塊math,就可以在檔案最開始的地方用import math來引入,

形如:

    import module1,mudule2...

當解釋器遇到import陳述句,如果模塊在當前的搜索路徑就會被匯入,

在呼叫math模塊中的函式時,必須這樣參考:

  模塊名.函式名
  • 想一想:

    為什么必須加上模塊名呼叫呢?

  • 答:

    因為可能存在這樣一種情況:在多個模塊中含有相同名稱的函式,此時如果只是通過函式名來呼叫,解釋器無法知道到底要呼叫哪個函式,所以如果像上述這樣引入模塊的時候,呼叫函式必須加上模塊名

    import math

    #這樣會報錯
    print sqrt(2)

    #這樣才能正確輸出結果
    print math.sqrt(2)

有時候我們只需要用到模塊中的某個函式,只需要引入該函式即可,此時可以用下面方法實作:

    from 模塊名 import 函式名1,函式名2....

不僅可以引入函式,還可以引入一些全域變數、類等

  • 注意:

    • 通過這種方式引入的時候,呼叫函式時只能給出函式名,不能給出模塊名,但是當兩個模塊中含有相同名稱函式的時候,后面一次引入會覆寫前一次引入,也就是說假如模塊A中有函式function( ),在模塊B中也有函式function( ),如果引入A中的function在先、B中的function在后,那么當呼叫function函式的時候,是去執行模塊B中的function函式,
    • 如果想一次性引入math中所有的東西,還可以通過from math import *來實作

14.1.3 from…import

Python的from陳述句讓你從模塊中匯入一個指定的部分到當前命名空間中

語法如下:

    from modname import name1[, name2[, ... nameN]]

例如,要匯入模塊fib的fibonacci函式,使用如下陳述句:

    from fib import fibonacci

注意

  • 不會把整個fib模塊匯入到當前的命名空間中,它只會將fib里的fibonacci單個引入

14.1.4 from … import *

把一個模塊的所有內容全都匯入到當前的命名空間也是可行的,只需使用如下宣告:

    from modname import *

注意

  • 這提供了一個簡單的方法來匯入一個模塊中的所有專案,然而這種宣告不該被過多地使用,

14.1.5 as

    In [1]: import time as tt

    In [2]: time.sleep(1)
    ---------------------------------------------------------------------------
    NameError                                 Traceback (most recent call last)
    <ipython-input-2-07a34f5b1e42> in <module>()
    ----> 1 time.sleep(1)

    NameError: name 'time' is not defined

    In [3]: 

    In [3]: 

    In [3]: tt.sleep(1)

    In [4]: 

    In [4]: 

    In [4]: from time import sleep as sp

    In [5]: sleep(1)
    ---------------------------------------------------------------------------
    NameError                                 Traceback (most recent call last)
    <ipython-input-5-82e5c2913b44> in <module>()
    ----> 1 sleep(1)

    NameError: name 'sleep' is not defined

    In [6]: 

    In [6]: 

    In [6]: sp(1)

    In [7]:

14.1.6 定位模塊

當你匯入一個模塊,Python決議器對模塊位置的搜索順序是:

  1. 當前目錄
  2. 如果不在當前目錄,Python則搜索在shell變數PYTHONPATH下的每個目錄,
  3. 如果都找不到,Python會察看默認路徑,UNIX下,默認路徑一般為/usr/local/lib/python/
  4. 模塊搜索路徑存盤在system模塊的sys.path變數中,變數里包含當前目錄,PYTHONPATH和由安裝程序決定的默認目錄,

14.2 制作模塊

14.2.1 定義自己的模塊

在Python中,每個Python檔案都可以作為一個模塊,模塊的名字就是檔案的名字,

比如有這樣一個檔案test.py,在test.py中定義了函式add

test.py

    def add(a,b):
        return a+b

14.2.2 呼叫自己定義的模塊

那么在其他檔案中就可以先import test,然后通過test.add(a,b)來呼叫了,當然也可以通過from test import add來引入

main.py

    import test

    result = test.add(11,22)
    print(result)

14.2.3 測驗模塊

在實際開中,當一個開發人員撰寫完一個模塊后,為了讓模塊能夠在專案中達到想要的效果,這個開發人員會自行在py檔案中添加一些測驗資訊,例如:

test.py
    def add(a,b):
        return a+b

    # 用來進行測驗
    ret = add(12,22)
    print('int test.py file,,,,12+22=%d'%ret)

如果此時,在其他py檔案中引入了此檔案的話,想想看,測驗的那段代碼是否也會執行呢!

main.py
    import test

    result = test.add(11,22)
    print(result)

運行現象:

int test.py file,,,,12+22=34
33

至此,可發現test.py中的測驗代碼,應該是單獨執行test.py檔案時才應該執行的,不應該是其他的檔案中參考而執行

為了解決這個問題,python在執行一個檔案時有個變數__name__

直接運行此檔案

def add(a, b):
    return a + b
# # 用來進行測驗
# ret = add(12,22)
# print('int test.py file,,,,12+22=%d'%ret)
print("in test.py file,__name__ is %s "%__name__)

運行結果:

in test.py file,__name__ is __main__ 

在其他檔案中import此檔案

in test.py file,__name__ is test 
33

總結:

  • 可以根據__name__變數的結果能夠判斷出,是直接執行的python腳本還是被引入執行的,從而能夠有選擇性的執行測驗代碼

    執行test.py:

def add(a, b):
    return a + b


if __name__ == "__main__":
    # 用來進行測驗
    ret = add(12, 22)
    print('int test.py file,,,,12+22=%d' % ret)
    print("in test.py file,__name__ is %s " % __name__)

運行結果:

D:\ProgramData\Anaconda3\python.exe C:/Users/WH/Desktop/Python基礎/test.py
int test.py file,,,,12+22=34
in test.py file,__name__ is __main__ 

執行main.py :

import test

result = test.add(11, 22)
print(result)

運行結果:

33

14.3 模塊中的__all__

14.3.1 沒有__all__

test.py

class Test(object):
    def test(self):
        print("Test類中的test函式")
def test1():
    print("test1函式")
def test2():
    print("test2函式")

main.py呼叫

from test import *

a=Test()
print(a.test())
print(test1())
print(test2())

運行結果:

Test類中的test函式
None
test1函式
None
test2函式
None

14.3.2. 模塊中有__all__

__all__=["Test","test1"]
class Test(object):
    def test(self):
        print("Test類中的test函式")
def test1():
    print("test1函式")
def test2():
    print("test2函式")

執行main.py

from test import *

a=Test()
print(a.test())
print(test1())
print(test2())

運行結果:

Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 6, in <module>
    print(test2())
NameError: name 'test2' is not defined
Test類中的test函式
None
test1函式
None

總結

如果一個檔案中有__all__變數,那么也就意味著這不在變數中的元素,不會被from xxx import *時匯入

14.4 python中的包

14.4.1. 引入包

有2個模塊功能有些聯系

img

所以將其放到同一個檔案夾下

img

使用import 檔案.模塊 的方式匯入

img

使用from 檔案夾 import 模塊 的方式匯入

img

在msg檔案夾下創建__init__.py檔案

img

__init__.py檔案中寫入

img

重新使用from 檔案夾 import 模塊 的方式匯入

img

總結:

  • 包將有聯系的模塊組織在一起,即放到同一個檔案夾下,并且在這個檔案夾創建一個名字為__init__.py 檔案,那么這個檔案夾就稱之為
  • 有效避免模塊名稱沖突問題,讓應用組織結構更加清晰

14.4.2 __init__.py檔案作用

__init__.py 控制著包的匯入行為

__init__.py為空,僅僅是把這個包匯入,不會匯入包中的模塊

__all____init__.py檔案中,定義一個__all__變數,它控制著 from 包名 import *時匯入的模塊

14.5 模塊發布

1.mymodule目錄結構體如下:

.
├── setup.py
├── suba
│   ├── aa.py
│   ├── bb.py
│   └── __init__.py
└── subb
    ├── cc.py
    ├── dd.py
    └── __init__.py

2.編輯setup.py檔案

py_modules需指明所需包含的py檔案

from distutils.core import setup

setup(name="AIhao", version="1.0", description="AIhao's module", author="AIhao", py_modules=['suba.aa', 'suba.bb', 'subb.cc', 'subb.dd'])

3.構建模塊

python setup.py build

構建后目錄結構

.
├── build
│   └── lib.linux-i686-2.7
│       ├── suba
│       │   ├── aa.py
│       │   ├── bb.py
│       │   └── __init__.py
│       └── subb
│           ├── cc.py
│           ├── dd.py
│           └── __init__.py
├── setup.py
├── suba
│   ├── aa.py
│   ├── bb.py
│   └── __init__.py
└── subb
    ├── cc.py
    ├── dd.py
    └── __init__.py

4.生成發布壓縮包

python setup.py sdist

打包后,生成最終發布壓縮包AIhao-1.0.tar.gz , 目錄結構

.
├── build
│   └── lib.linux-i686-2.7
│       ├── suba
│       │   ├── aa.py
│       │   ├── bb.py
│       │   └── __init__.py
│       └── subb
│           ├── cc.py
│           ├── dd.py
│           └── __init__.py
├── dist
│   └── AIhao-1.0.tar.gz
├── MANIFEST
├── setup.py
├── suba
│   ├── aa.py
│   ├── bb.py
│   └── __init__.py
└── subb
    ├── cc.py
    ├── dd.py
    └── __init__.py

14.6 模塊安裝、使用

14.6.1 安裝的方式

  1. 找到模塊的壓縮包
  2. 解壓
  3. 進入檔案夾
  4. 執行命令python setup.py install

注意:

  • 如果在install的時候,執行目錄安裝,可以使用python setup.py install --prefix=安裝路徑

14.6.2 模塊的引入

在程式中,使用from import 即可完成對安裝的模塊使用

from 模塊名 import 模塊名或者*

,然后通過test.add(a,b)來呼叫了,當然也可以通過from test import add來引入

main.py

    import test

    result = test.add(11,22)
    print(result)

14.2.3 測驗模塊

在實際開中,當一個開發人員撰寫完一個模塊后,為了讓模塊能夠在專案中達到想要的效果,這個開發人員會自行在py檔案中添加一些測驗資訊,例如:

test.py
    def add(a,b):
        return a+b

    # 用來進行測驗
    ret = add(12,22)
    print('int test.py file,,,,12+22=%d'%ret)

如果此時,在其他py檔案中引入了此檔案的話,想想看,測驗的那段代碼是否也會執行呢!

main.py
    import test

    result = test.add(11,22)
    print(result)

運行現象:

int test.py file,,,,12+22=34
33

至此,可發現test.py中的測驗代碼,應該是單獨執行test.py檔案時才應該執行的,不應該是其他的檔案中參考而執行

為了解決這個問題,python在執行一個檔案時有個變數__name__

直接運行此檔案

def add(a, b):
    return a + b
# # 用來進行測驗
# ret = add(12,22)
# print('int test.py file,,,,12+22=%d'%ret)
print("in test.py file,__name__ is %s "%__name__)

運行結果:

in test.py file,__name__ is __main__ 

在其他檔案中import此檔案

in test.py file,__name__ is test 
33

總結:

  • 可以根據__name__變數的結果能夠判斷出,是直接執行的python腳本還是被引入執行的,從而能夠有選擇性的執行測驗代碼

    執行test.py:

def add(a, b):
    return a + b


if __name__ == "__main__":
    # 用來進行測驗
    ret = add(12, 22)
    print('int test.py file,,,,12+22=%d' % ret)
    print("in test.py file,__name__ is %s " % __name__)

運行結果:

D:\ProgramData\Anaconda3\python.exe C:/Users/WH/Desktop/Python基礎/test.py
int test.py file,,,,12+22=34
in test.py file,__name__ is __main__ 

執行main.py :

import test

result = test.add(11, 22)
print(result)

運行結果:

33

14.3 模塊中的__all__

14.3.1 沒有__all__

test.py

class Test(object):
    def test(self):
        print("Test類中的test函式")
def test1():
    print("test1函式")
def test2():
    print("test2函式")

main.py呼叫

from test import *

a=Test()
print(a.test())
print(test1())
print(test2())

運行結果:

Test類中的test函式
None
test1函式
None
test2函式
None

14.3.2. 模塊中有__all__

__all__=["Test","test1"]
class Test(object):
    def test(self):
        print("Test類中的test函式")
def test1():
    print("test1函式")
def test2():
    print("test2函式")

執行main.py

from test import *

a=Test()
print(a.test())
print(test1())
print(test2())

運行結果:

Traceback (most recent call last):
  File "C:/Users/WH/Desktop/Python基礎/第一個Python程式.py", line 6, in <module>
    print(test2())
NameError: name 'test2' is not defined
Test類中的test函式
None
test1函式
None

總結

如果一個檔案中有__all__變數,那么也就意味著這不在變數中的元素,不會被from xxx import *時匯入

14.4 python中的包

14.4.1. 引入包

有2個模塊功能有些聯系

[外鏈圖片轉存中…(img-SLQzBFTR-1630474706485)]

所以將其放到同一個檔案夾下

[外鏈圖片轉存中…(img-PcvSAxTz-1630474706486)]

使用import 檔案.模塊 的方式匯入

[外鏈圖片轉存中…(img-w8G4goMf-1630474706486)]

使用from 檔案夾 import 模塊 的方式匯入

[外鏈圖片轉存中…(img-sruI0KU8-1630474706487)]

在msg檔案夾下創建__init__.py檔案

[外鏈圖片轉存中…(img-303ePJ8i-1630474706487)]

__init__.py檔案中寫入

[外鏈圖片轉存中…(img-a9ithVil-1630474706488)]

重新使用from 檔案夾 import 模塊 的方式匯入

[外鏈圖片轉存中…(img-6ClhSwqC-1630474706488)]

總結:

  • 包將有聯系的模塊組織在一起,即放到同一個檔案夾下,并且在這個檔案夾創建一個名字為__init__.py 檔案,那么這個檔案夾就稱之為
  • 有效避免模塊名稱沖突問題,讓應用組織結構更加清晰

14.4.2 __init__.py檔案作用

__init__.py 控制著包的匯入行為

__init__.py為空,僅僅是把這個包匯入,不會匯入包中的模塊

__all____init__.py檔案中,定義一個__all__變數,它控制著 from 包名 import *時匯入的模塊

14.5 模塊發布

1.mymodule目錄結構體如下:

.
├── setup.py
├── suba
│   ├── aa.py
│   ├── bb.py
│   └── __init__.py
└── subb
    ├── cc.py
    ├── dd.py
    └── __init__.py

2.編輯setup.py檔案

py_modules需指明所需包含的py檔案

from distutils.core import setup

setup(name="AIhao", version="1.0", description="AIhao's module", author="AIhao", py_modules=['suba.aa', 'suba.bb', 'subb.cc', 'subb.dd'])

3.構建模塊

python setup.py build

構建后目錄結構

.
├── build
│   └── lib.linux-i686-2.7
│       ├── suba
│       │   ├── aa.py
│       │   ├── bb.py
│       │   └── __init__.py
│       └── subb
│           ├── cc.py
│           ├── dd.py
│           └── __init__.py
├── setup.py
├── suba
│   ├── aa.py
│   ├── bb.py
│   └── __init__.py
└── subb
    ├── cc.py
    ├── dd.py
    └── __init__.py

4.生成發布壓縮包

python setup.py sdist

打包后,生成最終發布壓縮包AIhao-1.0.tar.gz , 目錄結構

.
├── build
│   └── lib.linux-i686-2.7
│       ├── suba
│       │   ├── aa.py
│       │   ├── bb.py
│       │   └── __init__.py
│       └── subb
│           ├── cc.py
│           ├── dd.py
│           └── __init__.py
├── dist
│   └── AIhao-1.0.tar.gz
├── MANIFEST
├── setup.py
├── suba
│   ├── aa.py
│   ├── bb.py
│   └── __init__.py
└── subb
    ├── cc.py
    ├── dd.py
    └── __init__.py

14.6 模塊安裝、使用

14.6.1 安裝的方式

  1. 找到模塊的壓縮包
  2. 解壓
  3. 進入檔案夾
  4. 執行命令python setup.py install

注意:

  • 如果在install的時候,執行目錄安裝,可以使用python setup.py install --prefix=安裝路徑

14.6.2 模塊的引入

在程式中,使用from import 即可完成對安裝的模塊使用

from 模塊名 import 模塊名或者*

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/296804.html

標籤:AI

上一篇:Yolov5-Pytorch版-Windows下訓練自己的資料集,內含voc批量轉yolo方法。(自稱宇宙超級巨詳細步驟)

下一篇:IT專業淪為新時代農民工?為什么你身邊的人都不讓你報計算機專業?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more