python用法 - 我什麼時候應該在Python中使用類?




python plt plot points (4)

我已經在python中編程了大約兩年; 主要是數據(pandas,mpl,numpy),還有自動腳本和小型網絡應用程序。 我正在努力成為一個更好的程序員並增加我的python知識,困擾我的一件事是我從未使用過類(除了為小型web應用程序複製隨機燒瓶代碼之外)。 我一般都明白它們是什麼,但我似乎無法理解為什麼我需要它們通過一個簡單的功能。

為了增加我的問題的特異性:我寫了大量的自動報告,這些報告總是涉及從多個數據源(mongo,sql,postgres,apis)中提取數據,執行大量或少量數據修改和格式化,將數據寫入csv / excel / html,通過電子郵件發送出去。 腳本範圍從~250行到~600行。 我是否有理由使用課程來完成這項工作?為什麼?


我認為你做得對。 當您需要模擬某些業務邏輯或困難的現實流程以及困難的關係時,類是合理的。 例如:

  • 具有共享狀態的幾個功能
  • 多個相同狀態變量的副本
  • 擴展現有功能的行為

我還建議你觀看 這個經典視頻


每當你需要維持你的功能狀態時,它就無法用發生器完成(產生而不是返回的功能)。 發電機保持自己的狀態。

如果要覆蓋任何 標準 運算符,則需要一個類。

每當您使用訪客模式時,您都需要課程。 使用生成器,上下文管理器(它們也更好地實現為生成器而不是類)和POD類型(字典,列表和元組等),可以更有效和乾淨地完成所有其他設計模式。

如果你想編寫“pythonic”代碼,你應該更喜歡上下文管理器和生成器而不是類。 它會更清潔。

如果要擴展功能,您幾乎總能通過包含而不是繼承來完成它。

每個規則都有例外。 如果要快速封裝功能(即編寫測試代碼而不是庫級可重用代碼),可以將狀態封裝在類中。 它很簡單,不需要重複使用。

如果你需要一個C ++風格的析構函數(RIIA),你肯定不想使用類。 你想要上下文管理器。


類定義了一個真實世界的實體。 如果您正在處理單獨存在且具有與其他邏輯分離的邏輯的事物,則應為其創建一個類。 例如,封裝數據庫連接的類。

如果不是這種情況,則無需創建類


類是 面向對象編程 的支柱。 OOP高度關注代碼組織,可重用性和封裝。

首先,免責聲明:OOP與 功能編程 部分形成對比,後者是Python中使用的不同範例。 並非每個使用Python(或肯定是大多數語言)編程的人都使用OOP。 你可以在不太面向對象的Java 8中做很多事情。 如果您不想使用OOP,那麼請不要。 如果您只是編寫一次性腳本來處理您再也不會使用的數據,那麼請繼續按照您的方式編寫。

但是,使用OOP有很多原因。

一些原因:

  • 組織:OOP定義了在代碼中描述和定義數據和過程的眾所周知的標準方法。 數據和過程都可以存儲在不同的定義級別(在不同的類中),並且有關於這些定義的標準方法。 也就是說,如果您以標準方式使用OOP,它將幫助您以後的自己和其他人理解,編輯和使用您的代碼。 此外,您可以命名數據結構並方便地引用它們,而不是使用複雜的,任意的數據存儲機制(dicts或列表或dicts或集合的dicts列表,或其他)。

  • 狀態:OOP可幫助您定義和跟踪狀態。 例如,在一個典型的例子中,如果您正在創建一個處理學生的程序(例如,成績計劃),您可以在一個地方(姓名,年齡,性別,年級,課程,成績,教師,同齡人,飲食,特殊需要等),只要對象存活,並且易於訪問,這些數據就會持久存在。

  • Encapsulation :通過封裝,程序和數據一起存儲。 方法(函數的OOP術語)與它們操作和生成的數據一起定義。 在Java等允許 訪問控制 的語言中,或者在Python中,根據您描述公共API的方式,這意味著可以向用戶隱藏方法和數據。 這意味著如果您需要或想要更改代碼,您可以執行任何您想要的代碼實現,但保持公共API相同。

  • Inheritance :繼承允許您在一個位置(在一個類中)定義數據和過程,然後稍後覆蓋或擴展該功能。 例如,在Python中,我經常看到人們創建 dict 類的子類以添加其他功能。 一個常見的更改是覆蓋當從不存在的字典請求密鑰以基於未知密鑰提供默認值時拋出異常的方法。 這允許您現在或以後擴展自己的代碼,允許其他人擴展您的代碼,並允許您擴展其他人的代碼。

  • 可重用性:所有這些原因和其他原因使代碼具有更高的可重用性。 面向對象的代碼允許您編寫一次實體(已測試)代碼,然後一遍又一遍地重複使用。 如果需要針對特定用例調整某些內容,則可以從現有類繼承並覆蓋現有行為。 如果您需要更改某些內容,則可以在保留現有公共方法簽名的同時更改所有內容,並且沒有人更明智(希望如此)。

同樣,有幾個原因不使用OOP,你不需要。 但幸運的是,使用像Python這樣的語言,你可以使用一點點或者很多,這取決於你。

學生用例的例子(不保證代碼質量,只是一個例子):

面向對象

class Student(object):
    def __init__(self, name, age, gender, level, grades=None):
        self.name = name
        self.age = age
        self.gender = gender
        self.level = level
        self.grades = grades or {}

    def setGrade(self, course, grade):
        self.grades[course] = grade

    def getGrade(self, course):
        return self.grades[course]

    def getGPA(self):
        return sum(self.grades.values())/len(self.grades)

# Define some students
john = Student("John", 12, "male", 6, {"math":3.3})
jane = Student("Jane", 12, "female", 6, {"math":3.5})

# Now we can get to the grades easily
print(john.getGPA())
print(jane.getGPA())

標準字典

def calculateGPA(gradeDict):
    return sum(gradeDict.values())/len(gradeDict)

students = {}
# We can set the keys to variables so we might minimize typos
name, age, gender, level, grades = "name", "age", "gender", "level", "grades"
john, jane = "john", "jane"
math = "math"
students[john] = {}
students[john][age] = 12
students[john][gender] = "male"
students[john][level] = 6
students[john][grades] = {math:3.3}

students[jane] = {}
students[jane][age] = 12
students[jane][gender] = "female"
students[jane][level] = 6
students[jane][grades] = {math:3.5}

# At this point, we need to remember who the students are and where the grades are stored. Not a huge deal, but avoided by OOP.
print(calculateGPA(students[john][grades]))
print(calculateGPA(students[jane][grades]))




oop