8个Python面向对象编程的技巧
面向对象编程语言是一种广泛应用于软件设计的编程范式,它使代码可重用并减少代码冗余。它使用类和对象来实现编程中的现实世界对象。Python和其他语言如C++、Java、JavaScript等都支持面向对象编程。在本文中,我们将了解面向对象编程的特点以及在Python中使用面向对象编程的一些技巧。
在面向对象编程中,对象是从其类蓝图创建的。这些对象代表现实世界对象,因为它们具有某些称为属性和方法的属性,就像现实世界对象具有自己的属性和行为一样。例如,如果我们将狗视为现实世界对象,则它具有品种、颜色、大小等属性,还具有吠叫、奔跑速度等行为。这些属性和行为可以封装在一个狗对象中,该对象将具有其自己的属性和方法来表示编程中的一只狗。
面向对象编程具有4个特征,可以使代码更模块化、可重用和可维护 –
继承
在继承中,从已有类创建一个新类,即新类使用现有类的方法和行为,使代码更可重用和可维护。继承还使新类具有向新类中添加新函数的功能,以及在继承类中覆盖旧类的现有函数。继承减少了代码复杂性,使代码更可重用和可扩展。
封装
封装是将数据和使用该数据的函数封装在一个实体中的过程。面向对象编程将数据及其使用该数据的函数封装在类中,并以受控的方式允许访问和修改该数据和函数。封装使用访问修饰符如public、private和protected来提供对类的数据和函数的受限访问。
多态
通过多态来实现对象在不同情况下以不同方式行为。在面向对象编程中,可以通过方法重载和方法重写来实现多态。方法重载是创建具有相同名称但不同参数的多个方法的过程,而方法重写是在子类中创建方法的新实现的过程。多态使开发人员能够编写更加灵活和适应性强的代码,更容易向系统中添加新功能或特性,而不会破坏现有代码。
数据抽象
抽象是隐藏对象的实现细节并仅显示功能的过程。由于抽象,用户能够知道函数在做什么,但无法理解其工作原理或函数的内部细节。抽象使开发人员能够创建系统的高级视图,使代码的复杂性更易于理解和管理。
现在,让我们来看看在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类,并定义了属性,如“name”,“age”和“occupation”。
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.
区分类级别和实例级别数据
由于继承是面向对象编程的重要支柱,因此有必要区分类级别和实例级别的数据以更好地理解继承。一个类的实例的属性限定于该对象,这些属性在类的构造函数中定义,而专属于类的属性则在类的构造函数之外定义。
示例
在下面的示例中,我们创建了一个名为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
Pep8指南
在2001年,Guido van Rossum、Barry Warsaw和Nick Coghlan创建了一些编码规范,这些规范在创建Python包时必须注意。 这些编码规范被称为Python企业提案或PEP指南。 除了代码质量之外,在创建Python包时还应注意其他因素。 所有这些因素都在PEP指南中提到。 一些重要因素包括:
- 每行代码的长度不得超过80个字符
-
在代码开头导入所有所需的库。
-
不要在代码中使用冗余变量。
示例
在下面的示例中,我们以两种不同的方式创建了一个 calculate_area 方法。 良好的示例是使用pep8指南实现的,而坏的示例则没有遵循pep8指南。
# 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
结论
在这篇文章中,我们讨论了用适当的例子介绍了面向对象编程的各种技巧。通过遵循本文中讨论的技巧,我们可以编写出良好组织、模块化且易于维护的面向对象的代码。