千家信息网

Python进阶版定义类时应用的最佳做法有哪些

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,本篇内容主要讲解"Python进阶版定义类时应用的最佳做法有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Python进阶版定义类时应用的最佳做法有哪
千家信息网最后更新 2026年11月01日Python进阶版定义类时应用的最佳做法有哪些

本篇内容主要讲解"Python进阶版定义类时应用的最佳做法有哪些",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"Python进阶版定义类时应用的最佳做法有哪些"吧!

作为一种OOP语言,Python通过支持以对象为主的各种功能来处理数据和功能。例如,数据结构是所有对象,包括原始类型(例如整数和字符串),而在某些其他语言中,原始类型则不视为对象。对于另一个实例,函数是所有对象,它们仅仅是定义了其他对象的属性(例如类或模块)。

尽管可以使用内置数据类型,而且无需创建任何自定义类就能编写一组函数,但随着项目范围的扩大,代码可能会越来越难维护。这些单独代码部分的主题并不相同,尽管有很多信息是相关的,但管理它们之间的联系却并不简单。

在这些情况下,定义自己的类就很划得来了,这样一来你可以对相关信息进行分组并且改善项目的结构设计。而且由于你即将处理更少的分段代码,代码库的长期可维护性将得到改善。但要注意,仅当以正确方式完成类声明时,操作才可以实现,定义自定义类的益处才能超过管理它们的支出。

1. 好的命名

定义自己的类,就好比在代码库中添加了一位新成员。因此应该给类起个好名字。虽然类名的唯一限制是合法Python变量的规则(例如,不能以数字开头),但是有一些好用的方法来命名类。

  • 使用易于发音的名词。在参与团队项目时,这一点尤其重要。在小组演讲中,你恐怕不愿意这样讲:"在这种情况下,我们创建Zgnehst类的实例。" 另外,易于发音也意味着名称不应太长,使用三个以上的单词来定义类名简直无法想象。一个字是最佳,两个字其次,三个字不能再多啦!

  • 反映其存储的数据和预期功能。就像在现实生活中一样——当看到男性化的名字时,我们就会默认这个孩子是男孩。同样的方式也适用于类名(或通常的任何其他变量),命名规则很简单——不要让人感觉奇怪。如果要处理学生的信息,那么该课程应该命名为Student,KiddosAtCampus并不是一个常规的好名字。

  • 遵循命名约定。应该对类名使用骆驼拼写法,例如GoodName。以下是非常规类名称的不完整列表:goodName,Good_Name,good_name以及GOodnAme。遵循命名约定是为了使意图表现明确。在别人阅读你的代码时,可以毫无疑问地假定命名为GoodName的对象是一个类。

也有适用于属性和功能的命名规则和约定,以下各节将在使用情况下简要提及,但是总体原理是相同的。

2. 显式实例属性

在大多数情况下,我们都想定义自己的实例初始化方法(即__init__)。在此种方法中,设置了新创建的类实例的初始状态。但是,Python并没有限制可以在何处使用自定义类定义实例属性。换句话说,你可以在创建实例之后的后续操作中定义其他实例属性。

classStudent:            def__init__(self, first_name, last_name):                self.first_name = first_name                self.last_name = last_name                  defverify_registration_status(self):                status = self.get_status()                self.status_verified = status =="registered"                  defget_guardian_name(self):                self.guardian ="Goodman"                  defget_status(self):                # get the registration status from a database                status =query_database(self.first_name, self.last_name)                return status

(1) 初始化方法

如上所示,可以通过指定学生的名字和姓氏来创建"学生"类的实例。稍后,在调用实例方法(即verify_registration_status)时,将设置"学生实例"的status属性。

但这不是理想的模式,因为如果在整个类中散布了各种实例属性,那么该类就无法明确实例对象拥有哪些数据。因此,最佳做法是将实例的属性放在__init__方法中,这样代码阅读器就可以通过单一位置来了解你的类的数据结构,如下所示:

classStudent:            def__init__(self, first_name, last_name):                self.first_name = first_name                self.last_name = last_name                self.status_verified =None                self.guardian =None

(2) 更好的初始化方法

对于最初无法设置的那些实例属性的问题,可以使用占位符值(例如None)进行设置。尽管没什么好担心的,但是当忘记调用某些实例方法来设置适用的实例属性时,此更改还有助于防止可能的错误,从而导致AttributeError(‘Student’ object has noattribute ‘status_verified’)。

在命名规则方面,应使用小写字母命名属性,并遵循蛇形命名法——如果使用多个单词,请在它们之间使用下划线连接。此外,所有名称都应对其存储的数据有具有意义的指示(例如first_name比fn更好)。

3. 使用属性;但要精简

有些人在具备其他OOP语言(例如Java)背景的情况下学习Python编码,并且习惯于为实例的属性创建getter和setter。可以通过在Python中使用属性装饰器来模仿这一模式。以下代码展示了使用属性装饰器实现getter和setter的基本形式:

classStudent:            def__init__(self, first_name, last_name):                self.first_name = first_name                self.last_name = last_name                @property           defname(self):                print("Getter for the name")                returnf"{self.first_name}{self.last_name}"                @name.setter           defname(self, name):                print("Setter for the name")                self.first_name, self.last_name = name.split()

(3) 属性装饰

创建此属性后,尽管它是通过内部函数实现的,我们仍然可以使用点符号将其用作常规属性。

>>> student =Student("John", "Smith")                 ... print("StudentName:", student.name)                 ... student.name ="JohnnySmith"                 ... print("Aftersetting:", student.name)                 ...                Getterfor the name                StudentName: JohnSmith                Setterfor the name                Getterfor the name

(4) 使用属性

使用属性实现的优点包括验证正确的值设置(检查是否使用字符串,而不是使用整数)和只读访问权限(通过不实现setter方法)。但应该同时使用属性,如果自定义类如下所示,可能会很让人分心——属性太多了!

classStudent:            def__init__(self, first_name, last_name):                self._first_name = first_name                self._last_name = last_name                @property            deffirst_name(self):                return self._first_name                @property            deflast_name(self):                return self._last_name                @property            defname(self):                returnf"{self._first_name}{self._last_name}"

(5) 滥用属性

在大多数情况下,这些属性可以用实例属性代替,因此我们可以访问它们并直接设置它们。除非对使用上述属性的好处有特定的需求(例如:值验证),否则使用属性优先于在Python中创建属性。

4. 定义有意义的字符串表示法

在Python中,名称前后带有双下划线的函数称为特殊方法或魔术方法,有些人将其称为dunder方法。这些方法对解释器的基本操作有特殊的用法,包括我们先前介绍的__init__方法。__repr__和__str__这两种特殊方法对于创建自定义类的正确字符串表示法至关重要,这将为代码阅读器提供有关类的更直观信息。

它们之间的主要区别在于__repr__方法定义了字符串,你可以使用该字符串通过调用eval(repr("therepr"))重新创建对象,而__str__方法定义的字符串则更具描述性,并允许更多定制。换句话说,你可以认为__repr__方法中定义的字符串由开发人员查看,而__str__方法中使用的字符串由常规用户查看。请看以下示例:

classStudent:            def__init__(self, first_name, last_name):               self.first_name = first_name               self.last_name = last_name                 def__repr__(self):               returnf"Student({self.first_name!r}, {self.last_name!r})"                  def__str__(self):               returnf"Student: {self.first_name}{self.last_name}"

字符串表示法的实现:

请注意,在__repr__方法的实现中,f字符串使用!r来显示带引号的这些字符串,因为使用格式正确的字符串构造实例很有必要。如果不使用!r格式,则字符串将为Student(John, Smith),这不是构造"学生"实例的正确方法。

来看看这些实现如何为我们显示字符串:在交互式解释器中访问对象时会调用__repr__方法,而在打印对象时默认会调用__str__方法。

>>> student =Student("David", "Johnson")                  >>> student                 Student('David', 'Johnson')                  >>>print(student)                 Student: DavidJohnson

字符串表示法

5. 实例方法,类方法和静态方法

在一个类中,我们可以定义三种方法:实例方法、类方法和静态方法。我们需要考虑针对所关注的功能应使用哪些方法,以下是一些常规准则。

例如,如果方法与单个实例对象有关,那么需要访问或更新实例的特定属性。在这种情况下,应使用实例方法。这些方法具有如下签名:def do_something(self):,其中self自变量引用调用该方法的实例对象。

如果方法与单个实例对象无关,则应考虑使用类方法或静态方法。可以使用适用的修饰符轻松定义这两种方法:类方法(classmethod)和静态方法(staticmethod)。

两者之间的区别在于,类方法允许你访问或更新与类相关的属性,而静态方法则独立于任何实例或类本身。类方法的一个常见示例是提供一种方便的实例化方法,而静态方法可以只是一个实用函数。请看以下代码示例:

classStudent:     def__init__(self,first_name, last_name):        self.first_name = first_name        self.last_name = last_name                defbegin_study(self):         print(f"{self.first_name}{self.last_name} beginsstudying.")                @classmethod      deffrom_dict(cls,name_info):         first_name = name_info['first_name']        last_name = name_info['last_name']         returncls(first_name,last_name)             @staticmethod      defshow_duties():          return"Study,Play, Sleep"

不同的方法

也可以用类似的方式创建类属性。与前面讨论的实例属性不同,类属性由所有实例对象共享,并且它们应当反映一些独立于各个实例对象的特征。

6. 使用私有属性进行封装

在为项目编写自定义类时,需要考虑封装问题,尤其期望其他人也使用你的类的话就更应如此。当类的功能增长时,某些功能或属性仅与类内数据处理相关。换句话说,除了类之外,这些函数都将不会被调用,并且除你之外其他使用类的用户甚至不会在意这些函数的实现细节。在这些情况下,应该考虑封装。

按照惯例,应用封装的一种重要方法是为属性和函数加上下划线或两个下划线。二者之间有着细微的区别:带有下划线的被认为是受保护的,而带有两个下划线的被认为是私有的,这涉及在创建后进行名称处理。

从本质上来说,像这样命名属性和功能,是在告诉IDE(即集成开发环境,例如PyCharm),尽管在Python中不存在真正的私有属性,但它们不会在类之外被访问。

classStudent:     def__init__(self,first_name, last_name):        self.first_name = first_name        self.last_name = last_name                defbegin_study(self):         print(f"{self.first_name}{self.last_name} beginsstudying.")                @classmethod      deffrom_dict(cls,name_info):         first_name = name_info['first_name']        last_name = name_info['last_name']         returncls(first_name,last_name)             @staticmethod      defshow_duties():          return"Study,Play, Sleep"

封装

上面的代码展示了一个简单的封装示例。如果想了解学生的评价GPA,那么我们可以使用get_mean_gpa方法获得GPA。用户不需要知道平均GPA的计算方式,我们可以通过在函数名称前添加下划线来保护相关方法。

这一最佳做法的主要收获是,与用户使用你的代码相关的公共API,仅公开最少的数量。对于仅在内部使用的那些代码,请将其设置为受保护的方法或私有方法。

7. 分离关注点和解耦

随着项目的发展,你会发现自己正在处理更多数据,如果你只坚持使用一个类会变得很麻烦。继续以"学生"类为例,假设学生在学校吃午餐,并且每个人都有一个餐饮帐户,可以用来支付餐费。从理论上讲,我们可以处理学生类中与帐户相关的数据和功能,如下所示:

classStudent:            def__init__(self, first_name, last_name, student_id):                self.first_name = first_name                self.last_name = last_name                self.student_id = student_id                  defcheck_account_balance(self):                account_number =get_account_number(self.student_id)                balance =get_balance(account_number)               return balance                  defload_money(self, amount):                account_number =get_account_number(self.student_id)                balance =get_balance(account_number)               balance += amount               update_balance(account_number, balance)

混合功能

上面的代码向展示了一些有关检查账户余额和向账户充值的伪代码,这两种伪代码都在Student类中实现。还有更多与该帐户相关的操作,例如冻结丢失的卡、合并帐户——实施所有这些操作会使"学生"类越来越大,从而使维护变得越来越困难。你应该分离这些职责并使学生类不负责这些与帐户相关的功能,即一种称为解耦的设计模式。

classStudent:            def__init__(self, first_name, last_name, student_id):                self.first_name = first_name                self.last_name = last_name                self.student_id = student_id                self.account =Account(self.student_id)                  defcheck_account_balance(self):                return self.account.get_balance()                  defload_money(self, amount):                self.account.load_money(amount)              classAccount:           def__init__(self, student_id):                self.student_id = student_id                # get additional information from the database                self.balance =400                  defget_balance(self):                # Theoretically, student.account.balance will work, but just in case                # we need to have additional steps to check, such as query the database                # again to make sure the data is up to date                return self.balance                  defload_money(self, amount):                # get the balance from the database                self.balance += amount                self.save_to_database()

分离关注点

上面的代码展示了我们如何使用附加的Account类来设计数据结构。如你所见,我们将所有与帐户相关的操作移至Account类。要实现检索学生的帐户信息的功能,学生类将通过从Account类中检索信息来处理。如果想实现更多与该类相关的功能,只需简单地更新Account类即可。

设计模式的主要要点是,希望各个类具有单独的关注点。通过将这些职责分开,你的类将变小,处理较小的代码组件会使将来的更改变得更容易。

8. 考虑使用__slots__进行优化

如果你的类主要用于存储数据的数据容器,那么可以考虑使用__slots__来优化类的性能。它不仅可以提高属性访问的速度,还可以节省内存,如果需要创建数千个或更多实例对象,就是它发挥大作用之处啦。

原因是,对于常规类,实例属性是通过内部托管的字典存储的。相比之下,通过使用__slots__,实例属性将使用在幕后使用C语言实现的与数组相关的数据结构存储,并且以更高的效率优化了它们的性能。

classStudentRegular:                     def__init__(self,first_name, last_name):                         self.first_name = first_name                         self.last_name = last_name              classStudentSlot:                    __slots__ = ['first_name', 'last_name']                  def__init__(self,first_name, last_name):                         self.first_name = first_name                         self.last_name = last_name

在类的定义中使用__slots__

上面的代码展示了如何在类中实现__slots__的简单示例。具体来说,将所有属性列为一个序列,这将在数据存储中创建一对一匹配,以加快访问速度并减少内存消耗。如前所述,常规类使用字典进行属性访问,但不使用已实现__slots__的字典。以下代码证实了这一点:

 
>>> student_r =StudentRegular('John', 'Smith')                        >>>student_r.__dict__                        {'first_name': 'John', 'last_name': 'Smith'}                        >>> student_s =StudentSlot('John', 'Smith')                        >>>student_s.__dict__                        Traceback (most recentcall last):                         File"", line 1, in                         AttributeError: 'StudentSlot' object has noattribute '__dict__'

具有__slots__的类中没有__dict__

有关使用__slots__的详细讨论可以在Stack Overflow找到答案,你也可以从官方文档中找到更多信息(https://docs.python.org/3/reference/datamodel.html)。

需要注意,使用__slots__会有一个副作用——它会阻止你动态创建其他属性。有人建议将其作为一种控制类拥有的属性的机制,但这并不是它的设计初衷。

9. 文件

最后我们必须讨论一下类的文档。我们需要明白编写文档并不能替代任何代码,编写大量文档并不能提高代码的性能,也不一定会使代码更具可读性。如果必须依靠文档字符串来澄清代码,那么你的代码很可能有问题。

以下代码将向大家展示一个程序员可能犯的错误——使用不必要的注释来补偿错误的代码(即,在这种情况下,无意义的变量名)。相比之下,一些有好名字的好代码甚至不需要注释。

# how many billable hours         a =6         # the hourly rate         b =100         # total charge         c = a * b              # The above vs.the below with no comments              billable_hours =6         hourly_rate =100         total_charge = billable_hours * hourly_rate

失败解释案例

我并不是说反对写评论和文档字符串,这实际上取决于自己的实例。如果你的代码被多个人使用或多次使用(例如,你是唯一一个多次访问同一代码的人),那么就应考虑编写一些好的注释。

这些注释可以帮助你自己或者团队伙伴阅读你的代码,但是他们都不可以假定你的代码完全按照注释中的说明进行。换句话说,编写好的代码始终是需要牢记的头等大事。

如果最终用户要使用代码的特定部分,那么需要编写文档字符串,因为这些人对相关的代码库并不熟悉。他们只想知道如何使用相关的API,而文档字符串将构成帮助菜单的基础。因此,作为程序员,你有责任确保提供有关如何使用程序的明确说明。

到此,相信大家对"Python进阶版定义类时应用的最佳做法有哪些"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

方法 属性 实例 代码 字符 字符串 对象 数据 功能 学生 函数 情况 处理 文档 下划线 信息 帐户 常规 更多 静态 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网高科技 广东猪兼强互联网科技有限公司 互联网科技公司起名 科技创新与互联网经济 互联网金融与金融科技 猪兼强互联网科技 丰台科技园 互联网 互联网科技咨询 成都玖崟互联网科技有限公司乐商圈怎么样 中国的互联网科技企业的崛起 中化能源互联网科技招聘 互联网科技创新的路径 工业互联网等科技实现智能化赋能 徐州市互联网科技有限公司 深圳无忧互联网科技 安徽零酒互联网科技有限公司 互联网科技品牌 互联网科技大佬云集 中国主要互联网科技公司 株洲百竞科技的互联网营销顾问 云信互联网科技有限公司 互联网金融 科技金融 广州宏创互联网科技 银优互联网科技有限公司 青岛中康互联网医疗科技有限公司 互联网科技博主是什么意思 互联网科技中介 广州梦谷互联网科技有限公司领导 玉溪新华互联网科技怎么选 恒生科技指数 中概互联网
0