您的位置:首頁(yè) >社會(huì ) > 正文

Python類(lèi)與面向對象

Python類(lèi)與面向對象

一、面向對象

1.1 面向對象概述

面向對象與面向過(guò)程?

面向過(guò)程編程的基本思想是:分析解決問(wèn)題的步驟,使用函數實(shí)現每步對應的功能,按照步驟的先后順序依次調用函數。面向過(guò)程只考慮如何解決當前問(wèn)題,它著(zhù)眼于問(wèn)題本身。


(資料圖片僅供參考)

面向對象編程的基本思想是:著(zhù)眼于角色以及角色之間的聯(lián)系。使用面向對象編程思想解決問(wèn)題時(shí),開(kāi)發(fā)人員首先會(huì )從問(wèn)題之中提煉出問(wèn)題涉及的角色,將不同角色各自的特征和關(guān)系進(jìn)行封裝,以角色為主體,為不同角度定義不同的屬性和方法,以描述角色各自的屬性與行為。

1.2 面向對象的基本概念

1.對象

對象是一個(gè)程序模塊,從用戶(hù)來(lái)看,對象為他們提供所希望的行為。對象既可以是具體的物理實(shí)體的事物,也可以是人為的概念,如一名員工、一家公司、一輛汽車(chē)、一個(gè)故事等。

2.類(lèi)

在面向對象的方法中,類(lèi)是具有相同屬性行為的一組對象的集合,它提供了一個(gè)抽象的描述,其內部包括屬性和方法兩個(gè)主要部分。

3.抽象

抽象是抽取特定實(shí)例的共同特征,形成概念的過(guò)程。抽象主要是為了使復雜度降低,它強調主要特征,忽略次要特征,以得到較簡(jiǎn)單的概念,從而讓人們能控制其過(guò)程或以綜合的角度來(lái)了解許多特定的事態(tài)。

4.封裝

封裝是面向對象的核心思想,將對象的屬性和行為封裝起來(lái),不需要讓外界知道具體實(shí)現細節,避免了外界直接訪(fǎng)問(wèn)對象屬性而造成耦合度過(guò)高及過(guò)度依賴(lài),同時(shí)也阻止了外界對對象內部數據的修改而可能引發(fā)的不可預知錯誤。

5.繼承

繼承不僅增強了代碼復用性,提高了開(kāi)發(fā)效率,也為程序的擴充提供了便利。在軟件開(kāi)發(fā)中,類(lèi)的繼承性使所建立的軟件具有開(kāi)放性、可擴充性,這是數據組織和分類(lèi)行之有效的方法,它降低了創(chuàng )建對象、類(lèi)的工作量。

6.多態(tài)

多態(tài)指同一屬性或行為在父類(lèi)及其各派生類(lèi)中具有不同的語(yǔ)義,面向對象的多態(tài)特性使開(kāi)發(fā)更科學(xué)、更符合人類(lèi)的思維習慣,能有效地提高軟件開(kāi)發(fā)效率,縮短開(kāi)發(fā)周期,提高軟件的可靠性。

二、類(lèi)與對象

2.1 類(lèi)與對象的關(guān)系

類(lèi)是對多個(gè)對象共同特征的抽象描述,是對象的模板;對象用于描述現實(shí)中的個(gè)體,它是類(lèi)的實(shí)例。

2.2 類(lèi)的定義與訪(fǎng)問(wèn)

類(lèi)的定義格式如下:

class 類(lèi)名:  # 使用class定義類(lèi) 類(lèi)名首字母一般為大寫(xiě)屬性名 = 屬性值  # 定義屬性def 方法名(self,形參1,形參2,...,形參N):  # 定義方法 方法中有一個(gè)指向對象的默認參數self方法體

可以看到,在方法定義的參數中,有一個(gè):self關(guān)鍵字。self關(guān)鍵字是成員方法定義的時(shí)候,必須填寫(xiě)的。

  • 它用來(lái)表示類(lèi)對象本身的意思
  • 當我們使用類(lèi)對象調用方法的時(shí)候,self會(huì )自動(dòng)被python傳入
  • 在方法內部,想要訪(fǎng)問(wèn)類(lèi)的成員變量,必須使用self
  • self關(guān)鍵字,盡管在參數列表中,但是傳參的時(shí)候可以忽略它。

2.3 對象的創(chuàng )建與使用

類(lèi)定義完成后不能直接使用,程序中的類(lèi)需要實(shí)例化為對象才能實(shí)現其意義。

對象的創(chuàng )建格式

對象名=類(lèi)名()

訪(fǎng)問(wèn)對象成員

對象名.屬性    # 訪(fǎng)問(wèn)對象屬性對象名.方法()  # 訪(fǎng)問(wèn)對象方法

2.4 訪(fǎng)問(wèn)控制

類(lèi)中定義的屬性和方法默認為公有屬性和方法,該類(lèi)的對象可以任意訪(fǎng)問(wèn)類(lèi)的公有成員。為了契合封裝原則,python支持將類(lèi)中的成員設置為私有成員,在一定程度上限制對象對類(lèi)成員的訪(fǎng)問(wèn)。

定義私有成員

python通過(guò)在類(lèi)成員名之前添加雙下畫(huà)線(xiàn)(__)來(lái)限制成員的訪(fǎng)問(wèn)權限,語(yǔ)法格式如下:

__屬性名__方法名
class PersonInfo:__weight = 55             # 私有屬性def __info(self):         # 私有方法print(f"我的體重是:{__weight}")     

私有成員的訪(fǎng)問(wèn)

對象無(wú)法直接訪(fǎng)問(wèn)類(lèi)的私有成員。下面演示如何在類(lèi)內部訪(fǎng)問(wèn)私有屬性和私有方法。

訪(fǎng)問(wèn)私有屬性。私有屬性可在公有方法中通過(guò)指代類(lèi)本身的默認參數self訪(fǎng)問(wèn),類(lèi)外部可通過(guò)公有方法間接獲取類(lèi)的私有屬性。

class PersonInfo:    __weight = 65  # 私有屬性    def get_weight(self):        print(f"體重:{self.__weight}kg")  # 體重:65kgpersonInfo = PersonInfo()personInfo.get_weight()

訪(fǎng)問(wèn)私有方法。私有方法同樣在公有方法中通過(guò)參數self訪(fǎng)問(wèn)。

class PersonInfo:    __weight = 65  # 私有屬性    def __info(self):  # 私有方法        print(f"我的體重是:{self.__weight}")    def get_weight(self):        print(f"體重:{self.__weight}kg")        self.__info()# 創(chuàng  )建PersonInfo類(lèi)的對象person,訪(fǎng)問(wèn)公有方法get_weight()personInfo = PersonInfo()  # 體重:65kgpersonInfo.get_weight()    # 我的體重是:65

三、構造方法與析構方法

類(lèi)中有兩個(gè)特殊的方法:構造方法_init_()和析構方法__del()__。這兩個(gè)方法分別在類(lèi)創(chuàng )建和銷(xiāo)毀的時(shí)候自動(dòng)調用。

3.1 構造方法

每個(gè)類(lèi)都有一個(gè)默認的_init_()方法,如果在定義類(lèi)時(shí)顯示地定義了_init()方法,則創(chuàng )建對象時(shí)python解釋器會(huì )調用顯式定義的_init_()方法;如果定義類(lèi)時(shí)沒(méi)有顯式定義_init()方法,那么Python解釋器會(huì )調用默認的_init()方法。

class Information(object):    def __init__(self, name, sex):  # 有參構造方法        self.name = name            # 添加屬性name        self.sex = sex              # 添加屬性sex    def info(self):        print(f"姓名:{self.name}")    # 姓名:齊納        print(f"性別:{self.sex}")     # 性別:男information = Information("齊納", "男")information.info()

注意:前面在類(lèi)中定義的屬性是類(lèi)屬性,可以通過(guò)對象或類(lèi)進(jìn)行訪(fǎng)問(wèn);在構造方法中定義的屬性是實(shí)例屬性,只能通過(guò)對象進(jìn)行訪(fǎng)問(wèn)。

3.2 析構方法

在創(chuàng )建對象時(shí),系統會(huì )自動(dòng)調用_init_()方法,在對象被清理時(shí),系統也會(huì )自動(dòng)調用一個(gè)_del_()方法,這個(gè)方法就是類(lèi)的析構方法。

擴展:python的垃圾回收機制。Pyhton中的垃圾回收主要采用的是引用計數。引用計數是一種內存管理技術(shù),他通過(guò)引用計數器記錄所有對象的引用數量,當對象的引用計數器數值為0時(shí),就會(huì )將該對象視為垃圾進(jìn)行回收。

import sys# getrefcount()函數是sys模塊中用于統計對象引用數量的函數,其返回結果通常比預期結果大1,這是因為getrefcount()函數也會(huì )統計臨時(shí)對象的引用class Destruction:    def __init__(self):        print("對象被創(chuàng  )建")    def __del__(self):        print("對象被銷(xiāo)毀")# 調用getrefcount()函數返回Destruction類(lèi)的對象的引用計數器的值。destruction = Destruction()print(sys.getrefcount(destruction))  # 2

3.3 其他方法

_str_()

# __str__字符串方法class Student:    def __init__(self, name, age):        self.name = name        self.age = age    def __str__(self):        return f"Student類(lèi)對象,name={self.name},age={self.age}"student = Student("趙無(wú)極", 10)# print(student)       # <__main__.Student object at 0x0000017F57579390># print(str(student))  # <__main__.Student object at 0x0000017F57579390>print(student)       # Student類(lèi)對象,name=趙無(wú)極,age=10print(str(student))  # Student類(lèi)對象,name=趙無(wú)極,age=10# 當類(lèi)對象需要被轉換為字符串之時(shí),會(huì )輸出如上結果(內存地址)# 我們可以通過(guò)__str__方法,控制類(lèi)轉換為字符串的行為。

_lt_ 小于符號比較方法

class Student:    def __init__(self, name, age):        self.name = name        self.age = age    def __lt__(self, other):        return self.age < other.agestu1 = Student("周杰倫", 41)stu2 = Student("林俊杰", 42)# 直接對2個(gè)對象進(jìn)行比較是不可以的,但是在類(lèi)中實(shí)現__lt__方法,即可同時(shí)完成:小于符號 和 大于符號 2種比較print(stu1 < stu2)  # True      print(stu1 > stu2)  # False

_le_ 小于等于比較符號方法

__le__可用于:<=、>=兩種比較運算符上。

class Student:    def __init__(self, name, age):        self.name = name        self.age = age    def __le__(self, other):        return self.age < other.agestu1 = Student("周杰倫", 41)stu2 = Student("林俊杰", 41)print(stu1 <= stu2)  # Trueprint(stu1 >= stu2)  # False

_eq_,比較運算符實(shí)現方法

不實(shí)現__eq__方法,對象之間可以比較,但是是比較內存地址,也即是:不同對象==比較一定是False結果。實(shí)現了__eq__方法,就可以按照自己的想法來(lái)決定2個(gè)對象是否相等了。

class Student:    def __init__(self, name, age):        self.name = name        self.age = age    def __eq__(self, other):        return self.age == other.agestudent1 = Student("周杰庫", 41)student2 = Student("張學(xué)友", 41)print(student2 == student1)  # True

3.4 總結

四、類(lèi)方法和靜態(tài)方法

4.1 類(lèi)方法

擴展:實(shí)例方法:直接定義、只比普通函數多一個(gè)self參數的方法是類(lèi)最基本的方法,這種方法稱(chēng)為實(shí)例方法,它只能通過(guò)類(lèi)實(shí)例化的對象調用。

類(lèi)方法與實(shí)例方法有以下不同:

  • 類(lèi)方法使用裝飾器@classmethod修飾
  • 類(lèi)方法的第一個(gè)參數是cls而非self,它代表類(lèi)本身
  • 類(lèi)方法即可由對象調用,也可直接由類(lèi)來(lái)調用
  • 類(lèi)方法可以修改類(lèi)屬性,實(shí)例方法無(wú)法修改類(lèi)屬性

定義類(lèi)方法

語(yǔ)法格式如下:

類(lèi)名.類(lèi)方法對象名.類(lèi)方法
class Test:    @classmethod    def use_class_method(cls):        print(f"我是類(lèi)方法")test = Test()Test.use_class_method()     # 類(lèi)名調用方法test.use_class_method()     # 對象名調用方法

從輸出結果可以看出,使用類(lèi)名或對象名均可調用類(lèi)方法。

4.2 修改類(lèi)屬性

在實(shí)例方法中無(wú)法修改類(lèi)屬性的值,但在類(lèi)方法中可以修改類(lèi)屬性的值。

class Apple(object):  # 定義Apple類(lèi)    count = 0  # 定義類(lèi)屬性    def add_one(self):        self.count = 1  # 對象方法    @classmethod    def add_two(cls):        cls.count = 2  # 類(lèi)方法apple = Apple()apple.add_one()print(Apple.count)     # 0print(apple.count)     # 1Apple.add_two()print(Apple.count)     # 2

從輸出結果可以看出,調用實(shí)例方法add_one()后訪(fǎng)問(wèn)count的值為0,說(shuō)明count的值沒(méi)有被修改;調用類(lèi)方法add_two()后再次訪(fǎng)問(wèn)count的值為2,說(shuō)明類(lèi)屬性count的值被修改成功。

思考:通過(guò)"self.count=1"只是創(chuàng )建了一個(gè)與類(lèi)屬性同名的實(shí)例屬性count并將其賦值為1,而非對類(lèi)屬性進(jìn)行重新賦值。

4.3 靜態(tài)方法

靜態(tài)方法與實(shí)例方法有以下不同:

  • 靜態(tài)方法沒(méi)有self參數,它需要使用@staticmethod修飾
  • 靜態(tài)方法中需要以“類(lèi)名.方法名/屬性名”的形式訪(fǎng)問(wèn)類(lèi)的成員
  • 靜態(tài)方法即可有對象調用,亦可直接由類(lèi)調用
class Example:    num = 10   # 類(lèi)屬性    @staticmethod # 定義靜態(tài)方法    def static_method():        print(f"類(lèi)屬性的值為:{Example.num}")        print("--靜態(tài)方法--")example = Example()      # 創(chuàng  )建對象example.static_method()  # 對象調用Example.static_method()  # 類(lèi)調用

總結:類(lèi)方法和靜態(tài)方法的區別

類(lèi)方法和靜態(tài)方法最主要的區別在于類(lèi)方法有一個(gè)cls參數,使用該參數可以在類(lèi)方法中訪(fǎng)問(wèn)類(lèi)的成員;靜態(tài)方法沒(méi)有任何默認參數,它無(wú)法使用默認參數訪(fǎng)問(wèn)類(lèi)的成員。因此,靜態(tài)方法更適合與類(lèi)無(wú)關(guān)的操作。

五、繼承

5.1 單繼承

單繼承指的是子類(lèi)只繼承一個(gè)父類(lèi),其語(yǔ)法格式如下:

class 子類(lèi)(父類(lèi)):
class Amphibian:    name = "兩棲動(dòng)物"    def features(self):        print("幼年用腮呼吸")        print("成年用肺兼皮膚呼吸")class Frog(Amphibian):  # Frog類(lèi)繼承自Amphibian類(lèi)    def attr(self):        print(f"青蛙是{self.name}")        print("我會(huì )呱呱叫")frog = Frog()       # 創(chuàng  )建類(lèi)的實(shí)例化對象print(frog.name)    # 訪(fǎng)問(wèn)父類(lèi)的屬性   兩棲動(dòng)物frog.features()     # 使用父類(lèi)的方法   幼年用腮呼吸      成年用肺兼皮膚呼吸frog.attr()         # 使用自身的方法   青蛙是兩棲動(dòng)物    我會(huì )呱呱叫

從輸出結果可以看出,子類(lèi)繼承父類(lèi)之后,就擁有了父類(lèi)繼承的屬性和方法,它既可以調用自己的方法,也可以調用從分類(lèi)繼承的方法。

擴展:isinstance()函數與issubclass()函數

isinstance(o,t)函數用于檢查對象的類(lèi)型,它有兩個(gè)參數,第一個(gè)參數是要判斷類(lèi)型的對象(o),第二個(gè)參數是類(lèi)型(t),如果o是t類(lèi)型的對象,則函數返回True,否則返回False

print(isinstance(frog, Frog))   # True

函數issubclass(cls,classinfo)用于檢查類(lèi)的繼承關(guān)系,它也有2個(gè)參數:第一個(gè)參數是要判斷的子類(lèi)型(cls);第二個(gè)參數是要判斷的父類(lèi)類(lèi)型(classinfo)。如果cls類(lèi)型是classinfo類(lèi)型的子類(lèi),則函數返回True,否則返回False。

print(issubclass(Frog, Amphibian))   # True

5.2 多繼承

多基礎指的是一個(gè)子類(lèi)繼承多個(gè)父類(lèi),其語(yǔ)法格式如下:

class 子類(lèi)(父類(lèi)A, 父類(lèi)B):
class English:    def eng_konw(self):        print("具備英語(yǔ)知識")class Math:    def math_koow(self):        print("具備數學(xué)知識")class Student(English, Math):    def study(self):        print("學(xué)生的任務(wù)是學(xué)習")s = Student()s.eng_konw()    # 具備英語(yǔ)知識s.math_koow()   # 具備數學(xué)知識s.study()       # 學(xué)生的任務(wù)是學(xué)習

注意事項:多個(gè)父類(lèi)中,如果有同名的成員,那么默認以繼承順序(從左到右)為優(yōu)先級。即:先繼承的保留,后繼承的被覆蓋

5.3 方法的重寫(xiě)

子類(lèi)可以繼承父類(lèi)的屬性和方法,若父類(lèi)的方法不能滿(mǎn)足子類(lèi)的要求,子類(lèi)可以重寫(xiě)父類(lèi)的方法,以實(shí)現輔助的功能。

class Felines:    def speciality(self):        print("貓科動(dòng)物特長(cháng)是爬樹(shù)")class Cat(Felines):    name = "貓"    def speciality(self):        print(f"{self.name}會(huì )抓老鼠")        print(f"{self.name}會(huì )爬樹(shù)")cat = Cat()cat.speciality()

程序運行結果:

貓會(huì )抓老鼠貓會(huì )爬樹(shù)

5.4 super()函數

如果子類(lèi)重寫(xiě)了父類(lèi)的方法,但仍希望調用父類(lèi)中的方法,可以通過(guò)super()函數調用父類(lèi)的方法。

super()函數使用方法如下:

super().方法名()
class Felines:    def speciality(self):        print("貓科動(dòng)物特長(cháng)是爬樹(shù)")class Cat(Felines):    name = "貓"    def speciality(self):        print(f"{self.name}會(huì )抓老鼠")        print(f"{self.name}會(huì )爬樹(shù)")        print("*" * 20)        super().speciality()cat = Cat()cat.speciality()

程序運行結果如下:

貓會(huì )抓老鼠貓會(huì )爬樹(shù)********************貓科動(dòng)物特長(cháng)是爬樹(shù)

從輸出結果可以看出,通過(guò)super()函數可以訪(fǎng)問(wèn)被重寫(xiě)的父類(lèi)方法。

5.5 多態(tài)

在Python中,多態(tài)值在不考慮對象類(lèi)型的情況下使用對象。Python中并不需要顯式指定對象的類(lèi)型,只要對象具有預期的方法和表達式操作符,就可以使用對象。

pass關(guān)鍵字的作用是什么?

pass是占位語(yǔ)句,用來(lái)保證函數(方法)或類(lèi)定義的完整性,表示無(wú)內容,空的意思。

class Animal(object):  # 定義父類(lèi)Animal    def move(self):        passclass Rabbit(Animal):  # 定義子類(lèi)Rabbit    def move(self):        print("兔子蹦蹦跳跳")class Snail(Animal):  # 定義子類(lèi)Snail    def move(self):        print("蝸牛緩慢爬行")def test(obj):    obj.move()rabbit = Rabbit()test(rabbit)  # 接受Rabbit對象snail = Snail()test(snail)   # 接受Snail對象

程序運行結果

兔子蹦蹦跳跳蝸牛緩慢爬行

從運行結果看出,同一個(gè)函數會(huì )根據參數的類(lèi)型去調用不同的方法,從而產(chǎn)生不同的結果。

六、類(lèi)型注解

7.1 變量的類(lèi)型注解

Pyhton在3.5版本的時(shí)候引入了類(lèi)型注解,以方便靜態(tài)類(lèi)型檢查工具,IDE等第三方工具。

類(lèi)型注解:在代碼中涉及數據交互的地方,提供數據類(lèi)型的注解(顯示的說(shuō)明)。

主要功能:

  • 幫助第三方IDE工具(如Pycharm)對代碼進(jìn)行類(lèi)型推斷,協(xié)助做代碼提示
  • 幫助開(kāi)發(fā)者自身對變量進(jìn)行類(lèi)型注釋

支持:

  • 變量的類(lèi)型注解
  • 函數(方法)形參列表和返回值的類(lèi)型注解

類(lèi)型注解的語(yǔ)法

基礎語(yǔ)法:變量:類(lèi)型

# 基礎數據類(lèi)型注解var1: int = 10var2: float = 3.1515926var3: bool = Truevar_4: str = "boost"# 類(lèi)對象類(lèi)型注解class Student:    passstu: Student = Student()# 基礎容器類(lèi)型注解my_list: list = [1, 2, 4]my_tuple: tuple = (1, 2, 3)my_set: set = {1, 2, 4}my_dict: dict = {"name": "張三"}my_str: str = "李四"# 容器類(lèi)型詳細注解"""    1. 元組類(lèi)型設置類(lèi)型詳細注解,需要將每一個(gè)元素都標記出來(lái)    2. 字典類(lèi)型設置類(lèi)型詳細注解,需要2個(gè)類(lèi)型,第一個(gè)是key,第二個(gè)是value"""my_list1: list[int] = {1, 2, 4}my_tuple1: tuple[str, int, bool] = ("張三", 34, True)my_set1: set[int] = {1, 2, 4}my_dict1: dict[str, int] = {"name": "張三"}

除了使用 變量: 類(lèi)型, 這種語(yǔ)法做注解外,也可以在注釋中進(jìn)行類(lèi)型注解。語(yǔ)法:#type: 類(lèi)型

# 在注釋中進(jìn)行類(lèi)型注解class Student:passvar_1 = random.randint(1, 10)  # type:intvar_2 = json.loads(data) # type:dict[str,int]var_3 = func()  # type:Student

tips:一般,無(wú)法直接看出變量類(lèi)型之時(shí)會(huì )添加變量的類(lèi)型注解。

類(lèi)型注解的限制

類(lèi)型注解主要功能在于:

  • 幫助第三方IDE工具對代碼進(jìn)行類(lèi)型判斷,協(xié)助做代碼提示
  • 幫助開(kāi)發(fā)者自身對變量進(jìn)行類(lèi)型注釋?zhuān)▊渥ⅲ?/li>

并不會(huì )真正的對類(lèi)型做驗證和判斷,也就是說(shuō),類(lèi)型注解僅僅是提示性的,不是決定性的。

var_1: int = "張三"var_2: str = 123# 該代碼是不會(huì )報錯的

總結

7.2 函數(方法)的類(lèi)型注解

7.2.1 函數(方法)的類(lèi)型注解 - 形參注解

函數和方法的形參類(lèi)型注解語(yǔ)法:

def 函數方法名(形參名:類(lèi)型,形參名:類(lèi)型,.......):pass
def add(x: int, y: int):    return x + yadd(1, 3)def func(data: list):    data.append(1)
7.2.2 函數(方法)的類(lèi)型注解 - 返回值注解

函數(方法)的返回值也是可以添加類(lèi)型注解的。語(yǔ)法如下:

def 函數方法名(形參:類(lèi)型,形參:類(lèi)型, .....) -> 返回值類(lèi)型:pass
def add(x: int, y: int) -> int:    return x + ydef func(data: list[int]) -> list[int]:    pass
7.2.3 總結

7.3 Union類(lèi)型

使用Union[類(lèi)型,...,類(lèi)型]可以定義聯(lián)合類(lèi)型注解

mylist: list[int] = [1, 2, 3]my_dict: dict[str, int] = {"age": 31, "num": 1}mylist = [1, 2, "name"]my_dict = {"name": "周杰倫", "age": 43}from typing import Unionmylist: list[Union[str, int]] = [1, 2, "name"]my_dict: dict[str, Union[str, int]] = {"name": "周杰倫", "age": 43}
# Union聯(lián)合類(lèi)型注解,在變量注解、函數(方法)形參和返回值注解中,均可使用。my_list: list[Union[int, str]] = [1, 2, "張三", "李四"]my_dict: dict[Union[int, str]] = [1, 2, "張三", "李四"]def func(data: Union[int, str]) -> Union[int, str]:    pass

總結:

七、案例

7.1 學(xué)生信息錄入

基本需求

實(shí)現代碼:

class Student:    def __init__(self, name, age, address, count):        self.name = name        self.age = age        self.address = address        self.count = count        print(f"學(xué)生{count}信息錄入完成,信息為:【學(xué)生姓名:{self.name},年齡:{self.age},地址:{self.address}】")        count += 1for i in range(1, 11):    print(f"當前錄入第{i}位學(xué)生信息,總共需錄入10位學(xué)生信息")    name = input("請輸入學(xué)生姓名:")    age = input("請輸入學(xué)生年齡:")    address = input("請輸入學(xué)生地址:")    student = Student(name, age, address, i)

7.2 數據分析案例

某公司,有2份數據文件,現需要對其進(jìn)行分析處理,計算每日的銷(xiāo)售額并以柱狀圖表的形式進(jìn)行展示。

數據內容

1月份數據是普通文本,使用逗號分割數據記錄,從前到后分別是(日期,訂單id,銷(xiāo)售額,銷(xiāo)售省份)

2月份數據是JSON數據,同樣包含(日期,訂單id,銷(xiāo)售額,銷(xiāo)售省份)

需求分析

實(shí)現代碼如下:

數據定義:data_define.py

"""數據定義的類(lèi)"""class Record:    def __init__(self, date, order_id, money, province):        self.date = date            # 訂單日期        self.order_id = order_id    # 訂單ID        self.money = money          # 訂單金額        self.province = province    # 銷(xiāo)售省份    def __str__(self):        return f"訂單日期={self.date},訂單ID={self.order_id},訂單金額={self.money},銷(xiāo)售省份={self.province}"

操作文件:file_define.py

"""和文件相關(guān)的類(lèi)定義"""import json# 導包from data_define import Record# 先定義一個(gè)抽象類(lèi)用來(lái)做頂層設計,確定有哪些功能需要實(shí)現class FileReader:    # 抽象方法    def reader_data(self) -> list[Record]:        # 讀取文件數據,讀到的每一條數據都轉換為Record對象,將他們都封裝到list內返回即可        passclass TextFileReader(FileReader):    def __init__(self, path):        self.path = path    # 定義成員變量記錄文件路徑    # 復寫(xiě)(實(shí)現抽象方法)父類(lèi)的方法    def reader_data(self) -> list[Record]:        f = open(self.path, "r", encoding="UTF-8")        record_list: list[Record] = []        for line in f.readlines():            line = line.strip()     # 消除讀取到的每一行數據中的\n            data_list = line.split(",")            record = Record(data_list[0], data_list[1], int(data_list[2]), data_list[3])            record_list.append(record)        f.close()        return record_listclass JsonFileReader(FileReader):    def __init__(self, path):        self.path = path  # 定義成員變量記錄文件路徑    # 復寫(xiě)(實(shí)現抽象方法)父類(lèi)的方法    def reader_data(self) -> list[Record]:        f = open(self.path, "r", encoding="UTF-8")        record_list: list[Record] = []        for line in f.readlines():            data_dict = json.loads(line)            record = Record(data_dict["date"], data_dict["order_id"], int(data_dict["money"]), data_dict["province"])            record_list.append(record)        f.close()        return record_list# 測試使用if __name__ == "__main__":    text_file_reader = TextFileReader("2011年1月銷(xiāo)售數據.txt")    json_filer_reader = JsonFileReader("2011年2月銷(xiāo)售數據JSON.txt")    list1 = text_file_reader.reader_data()    list2 = json_filer_reader.reader_data()    for l in list1:        print(l)    for l in list2:        print(l)

主文件:main.py

"""面向對象,數據分析案例,主業(yè)務(wù)邏輯代碼實(shí)現步驟:1.設計一個(gè)類(lèi),可以完成數據的封裝2.設計一個(gè)抽象類(lèi),定義文件讀取的相關(guān)功能,并使用子類(lèi)實(shí)現具體功能3.讀取文件,生產(chǎn)數據對象4.進(jìn)行數據需求的邏輯計算(計算每一天的銷(xiāo)售額)5.通過(guò)PyEcharts進(jìn)行圖形繪制"""from file_define import FileReader, TextFileReader, JsonFileReaderfrom data_define import Recordfrom pyecharts.charts import Barfrom pyecharts.options import *from pyecharts.globals import ThemeTypetext_file_reader = TextFileReader("2011年1月銷(xiāo)售數據.txt")json_file_reader = JsonFileReader("2011年2月銷(xiāo)售數據JSON.txt")jan_data: list[Record] = text_file_reader.reader_data()feb_data: list[Record] = json_file_reader.reader_data()# 將2個(gè)月份的數據合并為一個(gè)list來(lái)存儲all_data: list[Record] = jan_data + feb_data# 開(kāi)始進(jìn)行數據計算# {"2011-1-1": 1234, "2011-01-02": 100}data_dict = {}for record in all_data:    if record.date in data_dict.keys():        # 當前日期已經(jīng)有記錄了,所以和老記錄做累加即可        data_dict[record.date] += record.money    else:        data_dict[record.date] = record.money# 可視化圖表開(kāi)發(fā)bar = Bar(init_opts=InitOpts(theme=ThemeType.LIGHT))bar.add_xaxis(list(data_dict.keys()))             # 添加x軸的數據bar.add_yaxis("銷(xiāo)售額", list(data_dict.values()), label_opts=LabelOpts(is_show=False))  # 添加了y軸的數據bar.set_global_opts(    title_opts=TitleOpts(title="每日銷(xiāo)售額"))bar.render("每日銷(xiāo)售額柱狀圖.html")

程序運行結果如下:

免責聲明:本文不構成任何商業(yè)建議,投資有風(fēng)險,選擇需謹慎!本站發(fā)布的圖文一切為分享交流,傳播正能量,此文不保證數據的準確性,內容僅供參考

關(guān)鍵詞:

相關(guān)內容

熱門(mén)資訊

最新圖文

国产福利萌白酱精品一区|国产成人久久精品流白浆|国产一级A级免费视频|久久综合亚洲鲁鲁五月天欧|欧美黑人巨大视频HD