Python面向物件程式設計的8個技巧
面向物件程式語言是一種廣泛應用於軟體設計的程式設計正規化,因為它可以提高程式碼的可重用性並減少程式碼冗餘。它使用類和物件在程式設計中實現現實世界中的物件。Python和其他語言(如C++、Java、Javascript等)都支援面向物件程式設計。在本文中,我們將瞭解面向物件程式設計的特點以及在Python中使用面向物件程式設計的一些技巧。
在面向物件程式設計中,物件是由其類藍圖建立的。這些物件代表現實世界中的物件,因為它們具有一些稱為屬性的方法,就像現實世界中的物件具有自身的屬性和行為一樣。例如,如果我們將狗視為現實世界中的物件,那麼它具有一定的屬性,例如品種、顏色、大小,以及一些行為,例如吠叫、奔跑速度等。這些屬性和行為可以封裝在一個Dog物件中,該物件將具有其屬性和方法來在程式設計中表示一隻狗。
面向物件程式設計具有4個特性,可以使程式碼更模組化、更可重用和更易於維護:
繼承
在繼承中,一個新類是從一個已存在的類建立的,即新類使用現有類的方法和行為,這使得程式碼更易於重用和維護。繼承還提供了向新類新增新函式以及在繼承類中覆蓋舊類現有函式的功能。繼承降低了程式碼複雜性,使程式碼更易於重用和擴充套件。
封裝
封裝是將資料及其使用該資料的函式封裝到單個實體中的過程。OOP將資料及其使用該資料的函式封裝在類中,並允許以受控的方式訪問和修改該資料和函式。封裝使用public、private和protected等訪問修飾符來限制對類的資料和函式的訪問。
多型
物件在不同情況下以不同方式執行是透過多型實現的。在OOP中,多型可以透過方法過載和方法覆蓋來實現。方法過載是在建立多個具有相同名稱但引數不同的方法的過程,而方法覆蓋是在子類中建立方法的新實現的過程。多型允許開發人員編寫更靈活和更易於適應的程式碼,從而更容易向系統新增新功能或特性,而不會破壞現有程式碼。
資料抽象
抽象是隱藏物件實現細節並僅顯示功能的過程。由於抽象,使用者能夠知道函式的作用,但無法理解其工作方式或函式的內部細節。抽象允許開發人員建立系統的更高級別的檢視,從而更容易理解和管理程式碼的複雜性。
現在,讓我們來看一些在Python中進行面向物件程式設計的技巧:
使用類來建模任何現實世界中的物件
類是定義物件屬性和方法的藍圖。在建立物件之前,確保它是從有效的類建立的,因為當我們建立類的例項時,我們建立了一個物件,其屬性具有實際值。
示例
如果您正在建立一個遊戲,首先為玩家、敵人、武器和物品建立類,然後建立這些類的例項來建立遊戲邏輯。
class Player: def __init__(self, player_name): self.player_name = player_name class Enemy: def __init__(self, enemy_name, enemy_health): self.enemy_name = enemy_name self.enemy_health = enemy_health class Weapon: def __init__(self, weapon_name, weapon_damage): self.weapon_name = weapon_name self.weapon_damage = weapon_damage class Game: def __init__(self, players, enemies, weapons): self.players = players self.enemies = enemies self.weapons = weapons def start_game(self): print("Game has started") def end_game(self): print("Game has ended") # create some players, enemies, and weapons player1 = Player("John") player2 = Player("Jane") enemy1 = Enemy("Zombie", 50) enemy2 = Enemy("Goblin", 75) weapon1 = Weapon("Sword", 25) weapon2 = Weapon("Axe", 30) # create a game object with the players, enemies, and weapons game = Game([player1, player2], [enemy1, enemy2], [weapon1, weapon2]) # start the game game.start_game() # play the game... # end the game game.end_game()
輸出
Game has started Game has ended
使用有意義的命名約定
為類以及類中定義的屬性和函式使用有意義的名稱。名稱應指定類的行為和函式。在業界,駝峰式命名法用作預設命名約定。始終確保一個類、屬性和方法只負責一項任務。
示例
在下面的示例中,建立了一個Person類,類名為“Person”,屬性如姓名、年齡和職業。
class Person: def __init__(self, person_name, person_age,person_occupation): # type: (str, int, str) -> None self.person_name = person_name self.person_age = person_age self.person_occupation = person_occupation def introduce(self): # type: () -> str return "Myself {}, I am {} years old, and I work as a {}.".format(self.person_name, self.person_age, self.person_occupation) # Create a person object person1 = Person("John Smith", 35, "Software Engineer") # Call the introduce method to get the person's introduction introduction = person1.introduce() # Print the introduction print(introduction)
輸出
Myself John Smith, I am 35 years old, and I work as a Software Engineer.
區分類級別資料和例項級別資料
由於繼承是OOPs的重要支柱,因此有必要區分類級別資料和例項級別資料,以便更好地理解繼承。類的例項屬性僅限於該物件,這些屬性是在類的建構函式內定義的;而專門屬於類的屬性是在類的建構函式外部定義的。
示例
在下面的示例中,我們建立了一個具有類級別屬性和例項級別屬性的Car類。類級別屬性和例項級別屬性可以按如下方式訪問:
class Car: # class-level attribute category = 'Vehicle' def __init__(self, make, model): # instance-level attribute self.make = make self.model = model # creating instances of Car class car1 = Car('Toyota', 'Corolla') car2 = Car('Honda', 'Civic') # accessing class-level attribute print(Car.category) # output: Vehicle # accessing instance-level attributes print(car1.make, car1.model) # output: Toyota Corolla print(car2.make, car2.model) # output: Honda Civic # changing class-level attribute value Car.category = 'Automobile' # accessing updated class-level attribute print(Car.category) # output: Automobile # changing instance-level attribute value car1.make = 'Nissan' # accessing updated instance-level attribute print(car1.make, car1.model) # output: Nissan Corolla
輸出
Vehicle Toyota Corolla Honda Civic Automobile Nissan Corolla
使用多型編寫靈活的程式碼
多型是函式或物件可以用不同形式使用的方法。使用多型,您可以編寫靈活的程式碼,使來自不同類的物件可以互換地使用相同的函式,從而減少程式碼並避免冗餘。例如,如果您有一個以物件列表作為引數的函式,則可以傳入具有相同介面的任何物件的列表。這允許您編寫可以與各種物件一起工作的通用程式碼。
Python中的文件字串
為了更好地理解程式碼,開發人員會在程式碼中編寫註釋,以便其他人閱讀時能夠輕鬆理解函式的作用。但這對於大型Python包、模組和函式來說不是一種方便的方式。因此,Python結構化文件(也稱為文件字串)提供了一種方便的方式來記錄公共Python包、函式和方法,以描述函式的作用。您可以使用“'''三單引號'''”或“"""三雙引號"""”在Python中編寫文件字串。
示例
在下面的示例中,我們建立了一個名為calculate_area的函式,用於計算給定長和寬的矩形的面積。文件字串用三引號括起來,描述了函式、函式的引數和函式的返回型別。
def calc_area(len, wid): """ Given the length and width of the rectangle , calculate its area. Parameters: len (float): The length of the rectangle. wid (float): The width of the rectangle. Returns: Float: Reactangle calculated area. """ area = length * width return area
我們可以使用help函式訪問文件字串,如下所示:
print(help(calculate_area)) print(calculate_area.__doc__)
輸出
Help on function calc_area in module __main__: calc_area(len, wid) Given the length and width of the rectangle , calculate its area. Parameters: len (float): The length of the rectangle. wid (float): The width of the rectangle. Returns: Float: Reactangle calculated area. None Given the length and width of the rectangle , calculate its area. Parameters: len (float): The length of the rectangle. wid (float): The width of the rectangle. Returns: Float: Reactangle calculated area.
設定屬性訪問
屬性是在類內定義的物件屬性,物件使用它們來獲取、設定或更新其值及其關聯的方法。Python提供一些內建函式來訪問和操作類的屬性。
getattr() - 此函式用於獲取或訪問屬性的值。
setattr() - 此函式用於更新屬性的值。
hasattr() - 此函式用於檢查屬性是否存在。
delattr() - 此函式用於刪除屬性。
示例
在下面的示例中,我們使用getter和setter函式設定Car類屬性的訪問許可權,如下所示:
class Car: def __init__(self, car_company, car_model): self.car_company = car_company self.car_model = car_model car1 = Car('Toyota', 'Corolla') # setting attribute value using setattr setattr(car1, 'color', 'red') # getting attribute value using getattr print(getattr(car1, 'car_company')) # output: Toyota # checking attribute existence using hasattr print(hasattr(car1, 'car_model')) # output: True print(hasattr(car1, 'year')) # output: False # deleting attribute using delattr delattr(car1, 'color') print(hasattr(car1, 'color')) # output: False
輸出
Toyota True False False
使用抽象類
抽象類為元件的實現提供了通用介面。在抽象類中建立的方法可以在從抽象類建立的任何子類中使用。抽象類減少了開發人員的程式碼量,並使程式碼更易於維護。
示例
在下面的示例中,我們建立了一個名為Animal的抽象類,其中包含make_sound方法,並且所有其他從其繼承的類都應實現make_sound方法。
try: from abc import ABC, abstractmethod except ImportError: # Python 2.x fallback class ABCMeta(type): def __new__(cls, name, bases, namespace): return type.__new__(cls, name, bases, dict(namespace)) class ABC(object): __metaclass__ = ABCMeta def abstractmethod(method): method.__isabstractmethod__ = True return method class Animal(ABC): @abstractmethod def make_sound(self): pass class Cat(Animal): def make_sound(self): print("Meow") class Dog(Animal): def make_sound(self): print("Woof") # creating objects cat = Cat() dog = Dog() # calling methods cat.make_sound() # output: Meow dog.make_sound() # output: Woof
輸出
Meow Woof
PEP 8 指南
2001年,Guido van Rossum、Barry Warsaw和Nick Coghlan建立了一些編碼約定,在建立Python包時必須注意這些約定。這些編碼約定被稱為Python增強提案或PEP指南。除了程式碼質量之外,在建立Python包時還應注意其他因素。PEP指南中提到了所有這些因素。一些重要的因素是:
每一行程式碼應限制在80個字元以內。
在程式碼開頭匯入所有所需的庫。
不要在程式碼中使用冗餘變數。
示例
在下面的示例中,我們以兩種不同的方式建立了一個calculate_area方法。好的示例是使用PEP 8指南實現的,而不好的示例沒有遵循PEP 8指南。
# Good Example def calc_area(wid, ht): """Calculate the area of a rectangle.""" calculated_area = wid * ht return calculated_area # Bad Example def Calc_Area(Wid, Ht): calculated_area=Wid*Ht return calculated_area # PEP 8 naming conventions print(calc_area.__name__) print(Calc_Area.__name__)
輸出
calc_area Calc_Area
結論
在本文中,我們討論了面向物件程式設計的各種技巧以及相應的示例。透過遵循本文中討論的技巧,我們可以編寫組織良好、模組化且易於維護的面向物件程式碼。