1. 程式人生 > 實用技巧 >Python學習筆記2

Python學習筆記2

函式

定義函式

def 函式名(引數):
    程式碼1
    程式碼2
    ......

呼叫函式

函式名(引數)
  1. 引數可有可無
  2. 函式必須先定義後使用

函式的說明文件

定義函式的說明文件

def 函式名(引數):
    """說明文件的位置"""
    程式碼
    ......

檢視函式的說明文件

help(函式名)
def num(a, b):
    """
    求和
    :param a: 引數1
    :param b: 引數2
    :return: 返回值
    """
    res = a + b
    return res


help(num)

輸出:
num(a, b)
    求和
    :param a: 引數1
    :param b: 引數2
    :return: 返回值


修改全域性變數

a = 100


def test():
    a = 200


test()
print(a)  # 100
a = 100


def test2():
    global a
    a = 200


test2()
print(a)  # 200

返回值

def test1():
    return 1, 2


print(test1())  # (1, 2)
  1. 返回多個數據的時候,預設是元組型別
  2. return 後面可以連線列表、元組或字典,以返回多個值

函式的引數

一、位置引數

def user_info(name, age, gender):
    print(f"您的名字是{name}, 年齡是{age}, 性別是{gender}")


user_info("Tom", 20, "男")

二、關鍵字引數

函式呼叫通過“鍵=值”形式加以指定。清晰、容易,清除了引數的順序需求

def user_info(name, age, gender):
    print(f"您的名字是{name}, 年齡是{age}, 性別是{gender}")


user_info("Tom", age=20, gender="男")
user_info("Jerry", gender="男", age=16)

注意:函式呼叫時,如果有位置引數時,位置引數必須在關鍵字引數的前面,但關鍵字之間不存在先後順序

三、預設引數

也叫預設引數,用於定義函式,為引數提供預設值,呼叫函式時可不傳該預設引數的值(注意:所有位置引數必須出現在預設引數前,包括函式定義和呼叫)

def user_info(name, age, gender="男"):
    print(f"您的名字是{name}, 年齡是{age}, 性別是{gender}")


user_info("TOM", 20)
user_info("Rose", 18, "女")

四、不定長引數

也叫可變引數。用於不確定呼叫的時候會傳遞多少個引數(不傳參也可以)的場景。

包裹位置傳遞

def user_info(*args):
    print(args)


user_info("TOM")  # ('TOM',)
user_info("TOM", 18)  # ('TOM', 18)

傳進的所有引數都會被args變數收集,它會根據傳進引數的位置合併為一個元組(tuple),args是元組型別

包裹關鍵字傳遞

def user_info(**kwargs):
    print(kwargs)


user_info(name="TOM", age=18, gender="男")
# {'name': 'TOM', 'age': 18, 'gender': '男'}

合併為一個字典

拆包與交換變數

元組拆包

def return_num():
    return 100, 200


num1, num2 = return_num()
print(num1)  # 100
print(num2)  # 200

字典拆包

dict1 = {"name": "TOM", "age": 18}
a, b = dict1
print(a)  # name
print(b)  # age
print(dict1[a])  # TOM
print(dict1[b])  # 18

交換變數

方法一:定義中間變數

方法二:

a, b = 1, 2
a, b = b, a
print(a)  # 2
print(b)  # 1

引用

在Python中,值是靠引用來傳遞的

id() 獲取地址

可變型別:列表、字典、集合

不可變型別:整形、浮點型、字串、元組

(資料能否直接修改,能直接修改就是可變、否則是不可變)

引用當做實參

def test1(c):
    print(c)
    print(id(c))
    c += c
    print(c)
    print(id(c))

a = 100
test1(100)
100
140728557835008
200
140728557838208

b = [1, 2]
test1()
[1, 2]
2156910280832
[1, 2, 1, 2]
2156910280832

lambda

lambda 引數列表: 表示式
  1. lambda表示式的引數可有可無,函式的引數在lambda表示式中完全使用
  2. lambda表示式能接收任何數量的引數但只能返回一個表示式的值
計算a+b
fn1 = lambda a, b: a + b
print(fn1(1, 2))  # 3

引數形式

無引數
fn1 = lambda: 100
print(fn1())

一個引數
fn1 = lambda a: a
print(fn1("hello world"))

預設引數
fn1 = lambda a, b, c=100: a + b +c
print(fn1(10, 20))

可變引數  *agrs
fn1 = lambda *args: args
print(fn1(1, 2, 3))   # 返回值為元組

可變引數   **kwargs
fn1 = lambda **kwargs: kwargs
print(fn1(name="Tom", age=20))  # {'name': 'Tom', 'age': 20}

應用

判斷

fn1 = lambda a, b: a if a > b else b
print(fn1(100, 99))

列表資料按字典key的值排序

students = [
    {"name": "TOM", "age": 20},
    {"name": "ROSE", "age": 19},
    {"name": "JACK", "age": 22},
]

# 按age值升序排列
students.sort(key=lambda x: x["age"])
print(students)
# 按age值降序排列
students.sort(key=lambda x: x["age"], reverse=True)
print(students)

高階函式

abs() 取絕對值

round() 四捨五入

def sum_num(a, b, f):
    return f(a) + f(b)


res = sum_num(-1, 2, abs)
print(res)  # 3

res = sum_num(1.4, 2.5, round)
print(res)  # 4

內建高階函式

map()

map(func, lst), 將傳入的函式變數func作用到lst變數的每個元素中,並將結果組成新的列表(Python2) / 迭代器(Python3)返回。

計算list1序列中各個數字的2次方

list1 = [1, 2, 3, 4, 5]


def func(x):
    return x ** 2


res = map(func, list1)  # res是迭代器

print(res)  # <map object at 0x000002839775C070>
print(list(res))  # [1, 4, 9, 16, 25]

reduce()

reduce(func, lst), 其中func必須有兩個引數。每次func計算的結果繼續和序列的下一個元素做累計計算。

計算list1序列中各個數字的累加和

import functools

list1 = [1, 2, 3, 4, 5]


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


res = functools.reduce(func, list1)
print(res)  # 15

filter()

filter(func, lst) 函式用於過濾序列,過濾掉不符合條件的元素,返回一個filter物件。如果要轉換為列表,可以使用list() 來轉換

list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


def func(x):
    return x % 2 == 0


res = filter(func, list1)
print(res)  # <filter object at 0x000002A29F1C6B80>
print(list(res))  # [2, 4, 6, 8, 10]

檔案操作

開啟

open(name, mode) # 開啟一個已存在的檔案,或建立一個新的檔案

name: 目標檔名的字串(可以包含檔案所在的具體路徑)

mode: 訪問模式(只讀、寫入、追加...)

f = open("text.txt", "w")

f.write("abc")

f.close()

訪問模式

r :只讀;如果檔案不存在,報錯;檔案指標在開頭(預設訪問模式)

rb:以二進位制格式開啟

r+:可讀可寫

rb:二進位制,讀寫

w : 只寫;如果檔案不存在,新建;檔案指標在開頭

wb :

w+ :

wb+ :

a 追加;如果檔案不存在,新建;檔案指標在結尾

ab:

a+:

ab+:

read()

檔案物件.read(num)  num表示讀取的長度,省略則讀取全部

readlines()

整行讀取,返回是列表,其中每一行的資料為一個元素

readline()

一次讀取一行內容

seek() 移動檔案指標

檔案物件.seek(偏移量, 起始位置)

起始位置

0:檔案開頭

1:當前位置

2:檔案結尾

檔案備份

old_name = input("請輸入您要備份的檔名:")
index = old_name.rfind(".")

if index > 0:
    postfix = old_name[index:]

new_name = old_name[:index] + "[備份]" + postfix
print(new_name)

old_f = open(old_name, "rb")
new_f = open(new_name, "wb")
while True:
    con = old_f.read(1024)
    if len(con) == 0:
        break
    new_f.write(con)

old_f.close()
new_f.close()

檔案和資料夾操作

import os
重新命名檔案/資料夾
os.rename("text.txt", "text2.txt")
刪除檔案
os.remove("text[備份].txt")
建立資料夾
os.mkdir("aa")
刪除資料夾
os.rmdir("aa")
獲取當前目錄
print(os.getcwd())  # D:\pycharm\hello
改變預設目錄
os.chdir("aa")
print(os.getcwd())  # D:\pycharm\hello\aa
獲取某個資料夾下的所有檔案,返回一個列表,無參則返回當前目錄下的所有資料夾
print(os.listdir("aa"))

例項:批量修改檔名

import os

flag = 1
file_list = os.listdir()
print(file_list)

for i in file_list:
    if flag == 1:  # 新增Python_字首
        new_name = "Python_" + i
        
    elif flag == 2:  # 刪除Python_字首
        num = len("Python_")
        new_name = i[num:]
        
    os.rename(i, new_name)

面向物件

定義類

class 類名():
    程式碼
    ......

注意:類名要滿足識別符號命名規則,同時遵循大駝峰命名習慣

class Washer():
    def wash(self):
        print("洗衣服")
        print(self)


haier1 = Washer()
haier1.wash()
洗衣服
<__main__.Washer object at 0x000002DCD8DAA430>

haier2 = Washer()
haier2.wash()
洗衣服
<__main__.Washer object at 0x000002DCDA8A55B0>

新增和獲取物件屬性

類外面新增和獲取物件屬性

物件名.屬性名 = 值

haier1.width = 500
haier1.height = 800

print(haier1.width)  # 500

類裡面獲取物件屬性

class Washer():
    def wash(self):
        print("洗衣服")

    def print_info(self):
        print(self.width)


haier1 = Washer()

haier1.width = 500
haier1.print_info()

魔法方法

在Python中,_xx_() 的函式叫做魔法方法,指的是具有特殊功能的函式

_init_() 初始化物件

class Washer():
    def __init__(self):
        self.width = 500
        self.height = 800

    def wash(self):
        print("洗衣服")

    def print_info(self):
        print(f"洗衣機的寬度是{self.width},高度是{self.height}")


haier1 = Washer()

haier1.width = 501
haier1.print_info()  # 洗衣機的寬度是501,高度是800

帶引數
class Washer():
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def wash(self):
        print("洗衣服")

    def print_info(self):
        print(f"洗衣機的寬度是{self.width},高度是{self.height}")


haier1 = Washer(500, 800)

haier1.print_info()

注意:

_init_() 方法,在建立一個物件時預設被呼叫,不需要手動呼叫

_inti_(self)中的self引數,不需要開發者傳遞,Python直譯器會自動把當前的物件引用傳遞過去

_str_()

當使用print輸出物件的時候,預設列印物件的記憶體地址。如果類定義了_str_方法,那麼就會列印從這個方法中return的資料

class Washer():
    def __str__(self):
        return "這是洗衣機的說明書"


haier1 = Washer()
print(haier1)  # 這是洗衣機的說明書

_del_()

當刪除物件時,Python直譯器也會預設呼叫_del_()方法

    def __del__(self):
        print(f"{self}物件已被刪除")

繼承

class A(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)


class B(A):
    pass


res = B()
res.info_print()  # 1

在Python中,所有類預設繼承object類,object類是頂級類或基類;其他子類叫做派生類。

單繼承

多繼承

class A(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)


class B(object):
    def __init__(self):
        self.num = 2

    def info_print(self):
        print(self.num)


class C(A, B):
    pass


res = C()
print(res.num)  # 1
res.info_print()  # 1

當一個類有多個父類的時候,預設使用第一個父類的同名屬性和方法

子類重寫父類同名屬性和方法

class A(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)


class B(object):
    def __init__(self):
        self.num = 2

    def info_print(self):
        print(self.num)


class C(A, B):
    def __init__(self):
        self.num = 3

    def info_print(self):
        print(self.num)


res = C()
print(res.num)  # 3
res.info_print()  # 3

_mro_ 檢視繼承關係

print(C.__mro__)  # (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

子類呼叫父類同名方法和屬性

class A(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)


class B(object):
    def __init__(self):
        self.num = 2

    def info_print(self):
        print(self.num)


class C(A, B):
    def __init__(self):
        self.num = 3

    def info_print(self):
# 如果先呼叫了父類,父類屬性會覆蓋子類屬性,故在呼叫屬性前,先呼叫自己子類的初始化
        self.__init__()  
        print(self.num)

    def info_print_a(self):
        A.__init__(self)  # 同理
        A.info_print(self)

    def info_print_b(self):
        B.__init__(self)
        B.info_print(self)


res = C()
print(res.num)  # 3
res.info_print()  # 3
res.info_print_a()  # 1
res.info_print()  # 3

super()

super() 函式是用於呼叫父類(超類)的一個方法。

super 是用來解決多重繼承問題的,直接用類名呼叫父類方法在使用單繼承的時候沒問題,但是如果使用多繼承,會涉及到查詢順序(MRO)、重複呼叫(鑽石繼承)等種種問題。

class A(object):
    def __init__(self):
        self.num = 1

    def info_print(self):
        print(self.num)


class B(A):
    def __init__(self):
        self.num = 2

    def info_print(self):
        print(self.num)
        # 有參寫法
        # super(B, self).__init__()
        # super(B, self).info_print()
		
        # 無參寫法
        super().__init__()
        super().info_print()


class C(B):
    def __init__(self):
        self.num = 3

    def info_print(self):
        self.__init__()
        print(self.num)

    # 同時呼叫A和B
    def info_print_ab(self):
        # super(C, self).__init__()
        # super(C, self).info_print()

        super().__init__()
        super().info_print()


res = C()

res.info_print_ab()  # 2 1

私有許可權

設定某個例項屬性或例項方法不繼承給子類

class A(object):
    def __init__(self):
        self.num = 1
        self.__money = 200

    def __info_print(self):
        print("私有")


class B(A):
    pass


res = B()

print(res.money)  # AttributeError: 'B' object has no attribute 'money'
res.info_print()  # AttributeError: 'B' object has no attribute 'info_print'

獲取和修改私有屬性值

一般定義 get_xx()、set_xx()

class A(object):
    def __init__(self):
        self.num = 1
        self.__money = 200

    def get_money(self):
        return self.__money

    def set_money(self, val):
        self.__money = val

    def __info_print(self):
        print("私有")


class B(A):
    pass


res = B()

print(res.get_money())  # 200
res.set_money(500)
print(res.get_money())  # 500

多型

class Dog(object):
    def work(self):
        print("指哪打哪")


class ArmyDog(Dog):
    def work(self):
        print("追擊敵人")


class DrugDog(Dog):
    def work(self):
        print("追查毒品")


class Person(object):
    def work_with_dog(self, dog):
        dog.work()


ad = ArmyDog()
dd = DrugDog()

daqiu = Person()
daqiu.work_with_dog(ad)  # 追擊敵人
daqiu.work_with_dog(dd)  # 追查毒品

類屬性和例項屬性

類屬性就是類物件所擁有的屬性,它被該類的所有例項物件所共有

類屬性可以使用類物件例項物件訪問

class Dog(object):
    tooth = 10


wangcai = Dog()
xiaohei = Dog()

print(Dog.tooth)  # 10
print(wangcai.tooth)  # 10
print(xiaohei.tooth)  # 10

類屬性的優點

記錄的某項資料始終保持一致時,則定義類屬性

例項屬性要求每個物件為其單獨開闢一份記憶體空間來記錄資料,而類屬性為全類所共有,僅佔用一份記憶體,更加節省記憶體空間

修改類屬性

類屬性只能通過類物件修改,不能通過例項物件修改,如果通過例項物件修改類屬性,表示的是建立了一個例項屬性

class Dog(object):
    tooth = 10


wangcai = Dog()
xiaohei = Dog()

# 修改類屬性
Dog.tooth = 12
print(Dog.tooth)  # 12
print(wangcai.tooth)  # 12
print(xiaohei.tooth)  # 12

# 不能通過物件修改屬性,如果這樣操作,實則是建立了一個例項屬性
wangcai.tooth = 20
print(Dog.tooth)  # 12
print(wangcai.tooth)  # 20
print(xiaohei.tooth)  # 12

類方法和靜態方法

類方法

需要用裝飾器@classmethod來標識其為類方法,對於類方法,第一個引數必須是類物件,一般以cls作為第一個引數

使用場景

當方法中需要使用類物件(如訪問私有類屬性等)時,定義類方法

類方法一般和類屬性配合使用

class Dog(object):
    __tooth = 10

    @classmethod
    def get_tooth(cls):
        return cls.__tooth


wangcai = Dog()
print(wangcai.get_tooth())  # 10

靜態方法

需要通過裝飾器@staticmethod來進行修飾,靜態方法既不需要傳遞類物件也不需要傳遞例項物件(形參沒有self/cls)

靜態方法也能夠通過例項物件和類物件去訪問

使用場景

當方法中既不需要使用例項物件(如例項物件,例項屬性),也不需要使用類物件(如類屬性、類方法、建立例項等)時,定義靜態方法

取消不需要的引數傳遞,有利於減少不必要的記憶體佔用和效能消耗

class Dog(object):
    __tooth = 10

    @staticmethod
    def info_print():
        print("建立狗例項")


wangcai = Dog()
# 靜態方法既可以使用物件訪問又可以使用類訪問
wangcai.info_print()  # 建立狗例項
Dog.info_print()  # 建立狗例項

異常

try:
    可能發生錯誤的程式碼
except:
    如果出現異常執行的程式碼
try:
    f = open("test.txt", "r")
except:
    f = open("text.txt", "w")

捕獲指定異常

try:
    可能發生錯誤的程式碼
except 異常型別:
    如果捕獲到該異常型別執行的程式碼
try:
    print(num)
except NameError:
    print("有錯誤")

一般嘗試執行的程式碼的異常型別和要捕獲的異常型別不一致,則無法捕獲異常

一般try下方只放一行嘗試執行的程式碼

捕獲多個指定異常

try:
    print(1/0)
except (NameError, ZeroDivisionError):  # 元組的方式
    print("有錯誤")

捕獲異常描述資訊

try:
    print(num)
except (NameError, ZeroDivisionError) as result:
    print(result)  # name 'num' is not defined

捕獲所有異常

Exception是所有程式異常類的父類

try:
    print(num)
except Exception as result:
    print(result)  # name 'num' is not defined

異常的else

else表示的是如果沒有異常要執行的程式碼

try:
    print(1)  # 1
except Exception as result:
    print(result)
else:
    print("沒有異常")  # 沒有異常

異常的finally

finally表示的是無論是否異常都要執行的程式碼

try:
    f = open("test.txt", "r")
except Exception as result:
    f = open("text.txt", "w")
else:
    print("沒有異常")
finally:
    f.close()

異常的傳遞

import time

try:
    f = open("text2.txt", "r")
    try:
        while True:
            con = f.readline()
            if len(con) == 0:
                break
            time.sleep(2)  # 每隔兩秒
            print(con)
    except:
        print("讀取資料被終止")
    finally:
        f.close()
        print("關閉檔案")

except:
    print("開啟失敗")

自定義異常

raise 異常類物件
class ShortInputError(Exception):  # 繼承Exception類
    def __init__(self, length, min_len):
        self.length = length
        self.min_len = min_len

    # 設定丟擲異常的描述資訊
    def __str__(self):
        return f"你輸入的長度是{self.length},不能少於{self.min_len}個字元"


def main():
    try:
        con = input("請輸入密碼:")
        if len(con) < 3:
            raise ShortInputError(len(con), 3)
    except Exception as result:
        print(result)
    else:
        print("密碼輸入完成")


main()

模組

Python模組(Module),是一個Python檔案,以.py結尾,包含了Python物件定義和Python語句

匯入模組

  • import 模組名
  • from 模組名 import 功能名
  • form 模組名 import *
  • import 模組名 as 別名
  • from 模組名 import 功能名 as 別名
import 模組名
import 模組名1, 模組名2...

import math
math.sqrt(9)  # 3.0
from 模組名 import 功能1,功能2......

from math import sqrt
print(sqrt(9))
from 模組名 import *

from math import *
print(sqrt(9))

as定義別名

# 模組別名
import time as tt
tt.sleep(2)
print("hello")

# 功能別名
from time import sleep as sl
sl(2)
print("hello")

製作模組

在當前檔案中呼叫該函式
print(_name_)  # _main_

呼叫其他匯入的檔案
print(_name_)  # 匯入的檔名

模組定義順序

自己的檔名不要和已有模組名重複,否則導致模組功能無法使用

使用from 模組名 import 功能 的時候,如果功能名字重複,呼叫到的是最後定義或匯入的功能

__all__ 列表

如果一個模組檔案中有__all__變數,當使用from xxx import *匯入時,只能匯入這個列表中的元素

__all__ = ["testA"]


def testA():
    print("testA")


def testB():
    print("testB")

新建包

[new]--->[Python Package]

匯入包

法一

import 包名.模組名

包名.模組名.目標

法二

必須在_init_.py檔案中新增__all__ = [] 控制允許匯入的模組列表

from 包名 import *

模組名.目標

__dict__

class A(object):
    a = 0

    def __init__(self):
        self.b = 1


aa = A()
# 返回類內部所有屬性和方法對應的字典
print(A.__dict__)

{'__module__': '__main__', 'a': 0, '__init__': <function A.__init__ at 0x000001B38BC191F0>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}

# 返回例項屬性和值組成的字典
print(aa.__dict__)
{'b': 1}