当前位置: 首页 > 后端技术 > Python

【Python1-15】Python上手教程-类详解及类的使用

时间:2023-03-26 19:46:02 Python

作者|弗拉德来源|.让我们编写一个代表小狗的简单类Dog——不是特定的小狗,而是任何小狗。我们对大多数宠物狗了解多少?他们都有名字和年龄,我们也知道大多数小狗都是蹲着打滚的。由于大多数小狗都有以上两条信息(名字和年龄)和两种行为(蹲下和打滚),我们的Dog类将包含它们。这个类让Python知道如何创建代表小狗的对象。编写此类后,我们将使用它来创建代表特定小狗的实例。创建Dog类从Dog类创建的每个实例都将存储名称和年龄。我们赋予每只小狗蹲下(sit())和翻身(roll_over())的能力:classDog():"""模拟小狗的简单尝试"""def__init__(self,name,age):"""初始化属性name和age"""self.name=nameself.age=agedefsit(self):"""模拟小狗下单时蹲下"""print(self.name.title()+"isnowsitting.")defroll_over(self):"""模拟小狗在命令时翻身"""print(self.name.title()+"rolledover!")首先我们定义一个名为Dog的类.按照惯例,在Python中,大写的名称指的是类。此类定义中的括号是空的,因为我们将从空白开始创建此类。然后,我们编写了一个描述类功能的文档字符串。方法__init__()类中的函数称为方法,让我们先说,方法__init__()是一种特殊方法,每当您从Dog类创建新实例时,Python都会自动运行该方法。在该方法的名称中,开头有两个下划线,结尾有两个下划线,这是为了避免Python默认方法与普通方法名称冲突而设计的约定。我们将方法__init__()定义为包含三个参数:self、name和age。在这个方法的定义中,形参self是必不可少的,必须放在其他形参之前。因为当Python调用这个__init__()方法创建Dog实例时,会自动传入实参self。每个与类关联的方法调用都会自动传递参数self,它是对实例本身的引用,使实例可以访问类中的属性和方法。当我们创建一个Dog实例时,Python会调用Dog类的方法__init__()。我们将把姓名和年龄作为参数传递给Dog()。self是自动传递的,所以我们不需要传递它。每当我们从Dog类创建一个实例时,我们只需要为最后两个形参(name和age)提供值。__init__()中的两个变量都以self为前缀。以self为前缀的变量对于类中的所有方法都是可用的,我们也可以通过类的任何实例来访问这些变量。self.name=name获取形参name中存储的值,并将其存储在变量name中,然后与当前创建的实例相关联。self.age=age的工作原理类似。可通过此类实例访问的变量称为属性。Dog类还定义了另外两个方法:sit()和roll_over()。由于这些方法不需要额外的信息,例如姓名或年龄,因此它们只有一个形参,self。我们稍后创建的实例将可以访问这些方法,换句话说,它们都会蹲伏和滚动。目前,sit()和roll_over()做的很少,它们只是打印一条消息,说明小狗正在蹲下或翻身。但是这些方法可以扩展到模拟真实情况:如果这个类包含在计算机游戏中,这些方法将包含创建小狗蹲伏和滚动动画效果的代码。如果用这个类来控制机器狗,这些方法会引导机器狗蹲下和打滚。从类创建实例将类视为有关如何创建实例的说明。Dog类是一组指令,让Python知道如何创建代表特定小狗的实例。让我们创建一个代表特定小狗的实例:my_dog=Dog('willie',6)print("Mydog'snameis"+my_dog.name.title()+".")print("Mydogis"+str(my_dog.age)+"yearsold.")这里使用了前面例子中写的Dog类。我们要求Python创建一只名为'willie'且年龄为6的小狗。当遇到这行代码时,Python会使用参数'willie'和6调用Dog类中的方法__init__()。方法__init__()创建一个代表特定小狗的实例,并使用我们提供的值设置属性名称和年龄。方法__init__()没有显式包含return语句,但Python会自动返回一个代表小狗的实例。我们将这个实例存储在变量my_dog中。在这里,命名约定是有用的,我们通常可以认为像Dog这样的大写名称是指类,而像my_dog这样的小写名称是指从类创建的实例。1.访问属性要访问实例的属性,请使用句号。我们编写了以下代码来访问my_dog的属性名称的值:my_dog.name句号在Python中很常见,此语法演示了Python如何学习属性的值。在这里,Python首先找到实例my_dog,然后查找与该实例关联的属性名称。在Dog类中引用此属性时,使用self.name。然后我们用同样的方法获取属性age的值。输出如下:Mydog'snameisWillie。我的狗6岁了。2.调用方法从Dog类创建实例后,您可以使用句号来调用Dog类中定义的任何方法。让小狗蹲下翻身:my_dog=Dog('willie',6)my_dog.sit()my_dog.roll_over()调用方法,可以指定实例名(这里是my_dog)和调用的方法,并用句点分隔它们。当执行代码my_dog.sit()时,Python会在类Dog中查找方法sit()并运行它的代码。Python以相同的方式解释代码my_dog.roll_over()。这个语法很有用。如果为属性和方法赋予适当的描述性名称,例如name、age、sit()和roll_over(),我们甚至可以从我们以前从未见过的代码块中轻松推断出它的作用。3.创建多个实例您可以根据需要创建任意数量的实例。接下来创建另一个名为your_dog的实例:my_dog=Dog('willie',6)your_dog=Dog('lucy',3)print("Mydog'snameis"+my_dog.name.title()+".")print("我的狗是"+str(my_dog.age)+"岁。")my_dog.sit()print("\n你的狗的名字是"+your_dog.name.title()+".")print("Yourdogis"+str(your_dog.age)+"yearsold.")your_dog.sit()在这个例子中,我们创建了两只名叫威利和露西的小狗。每只小狗都是一个独立的实例,具有自己的一组属性,能够执行相同的操作:我的狗的名字是威利。我的狗6岁了。威利现在坐着。你的狗的名字是露西。你的狗今年3岁。露西现在坐着。即使我们给第二只小狗取了相同的名字和年龄,Python仍然会创建Dog类的另一个实例。您可以根据需要创建任意数量的类实例,前提是每个实例都存储在不同的变量中,或者在列表或字典中占据不同的位置。使用类和实例您可以使用类来模拟现实世界中的许多情况。一旦编写了类,您的大部分时间将花在使用从类创建的实例上。您需要执行的一项重要任务是修改实例的属性。您可以直接修改实例属性,也可以编写方法以特定方式修改它们。Car类让我们编写一个表示汽车的类,它存储有关汽车的信息,以及一个总结此信息的方法:classCar():"""Asimpleattempttosimulateacar"""def__init__(self,make,model,year):"""初始化描述汽车的属性"""self.make=makeself.model=modelself.year=yeardefget_descriptive_name(self):"""Returnneatdescriptive_name"""long_name=str(self.year)+''+self.make+''+self.modelreturnlong_name.title()my_new_car=Car('audi','a4',2016)print(my_new_car.get_descriptive_name())我们定义方法__init__()。和前面的Dog类一样,这个方法的第一个参数是self,我们在这个方法中还包含了另外三个参数:make、model和year。方法__init__()获取这些形式参数的值,并将它们存储在从此类创建的实例的属性中。创建新的Car实例时,我们需要指定其品牌、型号和生产年份。然后我们定义一个名为get_descriptive_name()的方法,它使用属性year、make和model创建一个描述汽车的字符串,从而使我们不必分别打印每个属性的值。要在此方法中访问属性值,我们使用self.make、self.model和self.year。我们创建了Car类的实例并将其存储在变量my_new_car中。接下来,我们调用方法get_descriptive_name()指出我们有什么样的车:2016AudiA4assigndefaultvaluestoattributes类中的每个属性都必须有一个初始值,即使值为0或空字符细绳。在某些情况下,比如设置默认值时,在方法__init__()中指定这样的初始值是可行的,如果你对属性这样做,就不需要包含提供初始值的参数为了它。让我们添加一个名为odometer_reading的属性,其初始值始终为0。我们还添加了一个名为read_odometer()的方法来读取汽车的里程表:classCar():def__init__(self,make,model,year):"""初始化描述汽车的属性"""self.make=makeself.model=modelself.year=yearself.odometer_reading=0defget_descriptive_name(self):"""返回简洁的描述信息"""long_name=str(self.year)+''+self.make+''+self.modelreturnlong_name.title()defread_odometer(self):"""打印一条消息说明汽车的里程数"""print("这辆车有"+str(self.odometer_reading)+"milesonit.")my_new_car=Car('audi','a4',2016)print(my_new_car.get_descriptive_name())my_new_car.read_odometer()现在,当Python调用方法__init__()要创建一个新实例,制造商、型号和制造年份将像上一个示例一样存储为属性。接下来,Python将创建一个名为odometer_reading的属性并将其初始值设置为0。我们还定义了一个名为read_odometer()的方法,它可以让您轻松获取汽车的里程数。最初汽车有0英里:2016AudiA4这辆车有0英里。里程表上没有0英里的汽车出售,因此我们需要一种方法来修改此属性的值。修改属性的值可以通过三种不同的方式修改属性的值:直接通过实例;通过方法设置;并通过一种方法递增(增加一个特定值)。下面依次描述这些方法。1、直接修改属性的值要修改属性的值,最简单的方法就是直接通过实例访问。下面的代码直接将里程表读数设置为23:my_new_car=Car('audi','a4',2016)print(my_new_car.get_descriptive_name())my_new_car.odometer_reading=23my_new_car.read_odometer()我们使用句号来直接访问并设置汽车的属性odometer_reading。这行代码告诉Python在实例my_new_car中找到属性odometer_reading并将该属性的值设置为23:2016AudiA4Thiscarhas23milesonit。有时您需要像这样直接访问属性,但有时您需要编写更新的方法。2.通过方法修改属性的值如果有一种方法可以为您更新属性,那将会很有帮助。这样,您可以将值传递给一个方法,而不是直接访问该属性,该方法将在内部更新它。下面的例子演示了一个名为update_odometer()的方法:classCar():####前面代码省略defupdate_odometer(self,mileage):"""设置里程表读数为指定值"""self.odometer_reading=mileagemy_new_car=Car('audi','a4',2016)print(my_new_car.get_descriptive_name())my_new_car.update_odometer(23)my_new_car.read_odometer()对Car类所做的唯一修改是添加方法update_odometer().此方法获取里程表值并将其存储到self.odometer_reading中。然后我们调用update_odometer(),为其提供参数23(对应于方法定义中的形式参数mileage)。它将里程表读数设置为23;read_odometer()方法打印读数:2016AudiA4Thiscarhas23milesonit。可以扩展方法update_odometer()以在修改里程表读数时做一些额外的工作。让我们添加一些逻辑来禁止任何人回调里程表读数:classCar():####之前的代码省略defupdate_odometer(self,mileage):"""将里程表读数设置为指定值ProhibitedCallback里程表读数"""ifmileage>=self.odometer_reading:self.odometer_reading=mileageelse:print("Youcan'trollbackanodometer!")现在,update_odometer()检查指定的读数是否合理?如果新指定的里程(mileage)大于或等于原里程(self.odometer_reading),则将里程表读数更改为新指定的里程,否则发出里程表无法拨回的警告。3.通过方法增加属性的值有时需要将属性的值增加特定数量而不是将其设置为新值。假设我们购买了一辆二手车并在购买和注册之间增加了100英里,以下方法允许我们传递此增量并相应地增加里程表读数:classCar():defincrement_odometer(self,miles):"""Increasetheodometer按指定量读取"""self.odometer_reading+=milesmy_used_car=Car('subaru','outback',2013)print(my_used_car.get_descriptive_name())my_used_car.update_odometer(23500)my_used_car.read_odometer()my_used_car.increment_odometer(100)my_used_car.read_odometer()新方法increment_odometer()获取一个以英里为单位的数字并将其添加到self.odometer_reading。然后我们创建一辆二手车-my_used_car。我们调用update_odometer()方法并传入23500以将这辆二手车的里程表读数设置为23500。然后我们调用increment_odometer()并传入100以在购买和注册之间增加100英里的行驶里程:2013斯巴鲁傲虎这辆车有23500英里就可以了。这辆车有23600英里。你可以很方便的修改这个方法来禁止增量为负数,防止有人利用它来拨回里程表。作业15-1User:创建一个名为User的类,具有first_name和last_name属性。在User类中定义一个名为describe_user()的方法,打印用户信息摘要,创建代表不同用户的多个实例,并为每个实例调用以上两个方法。15-2在你为练习15-1编写的用户类中,添加一个名为login_attempts的属性。编写一个名为increment_login_attempts()的方法,将属性login_attempts的值递增1。编写另一个名为reset_login_attempts()的方法,将属性login_attempts的值重置为0。创建基于User类的实例,然后调用该方法increment_login_attempts()多次。打印属性login_attempts的值以确认它已正确递增;然后,调用reset_login_attempts()方法,再次打印属性login_attempts的值,确认重置为0。如果要查看作业答案,可以到我的Githu仓库15-1_15-2文件夹下