从零开始的Python计划#8.1【自己创建一个类】

为了对类有一个更加清晰的认识,我们应该深入一下并尝试构建一个较复杂的类

1·我们先从分析问题开始吧。

矩形“Rectangle”对象将具有以下字段:
—height是保存矩形高度的长度字段
—width是保存矩形宽度的宽度字段
-------------------------------------
矩形类还将具有以下方法:
—get_perimeter(获取参数),用于计算形状外部周围的距离(周长)
— is_square是一个检查我们的实际矩形是否为正方形的方法(如果宽度等于高度,那么就是正方形)
—get_area是一个返回矩形面积的方法(就是height 乘 width的结果,矩形面积公式长乘宽)
—get_width此方法将返回对象宽度“width”字段中的值。
—get_height此方法将返回对象高度“height”字段中的值。

以上就是我们需要实现的全部方法

2·接下去我们应该使用UML图(统一建模语言图表)

可以看到以下一组标准图表,可以方便地以图形方式描述面向对象的系统:
在这里插入图片描述

第一行:类的名称
第二行:属性
第三行:方法

我们需要在每个元素的前面加上一个加号和减号以表示该元素是私有还是公有,大多数情况下在属性名称之后,还可以指定属性本身的类型。
在方法名称后面,不仅可以指定返回元素的类型,还可以在括号之间指定该方法是否接受任何属性,如果可以接受,那么属性应该是哪种。

我们把UML图应用到之前分析过的矩形上面:
在这里插入图片描述

可以看到它的名字是Rectangle,它有两个属性,height和width,都是浮点数。并且有五种方法,除了is_square返回布尔值(true或false),其它都是浮点数。

但是这个图表有一个错误,我们少了正负号
所以应该在第二排的前面都加上“-”,我们要保密我们的属性;在第三排里面全部加上“+”,因为我们希望方法可以从外部访问,以便让代码的其余部分和用户能够与类和对象交互。

3·开始编写类字段的代码

当我们创建一个类时,我们需要输入class,类的名称和冒号来实例化;创建类时最重要的事情是初始化方法(init方法:开头和结尾有两个下划线)

class Rectangle:
    def __init__(self, h, w):
        self.__height = h
        self.__width = w

要记住使用的“self.”,这是希望我们的方法知道引用的是特定的这个Rectangle类的实例。并且我们必须在height和width之前加上两个下划线来确保它是私有属性。

init创建类的一个新实例并将这个对象赋给本地变量
我们可以根据通用的类(饼干模具)创建对象(饼干):

在这里插入图片描述
self参数指的是对象的实例,在创建实例时分配的局部变量在这个例子中是h和w。

类可以具有称为__init__函数的特殊方法
----- __init__是在创建对象时自动调用的方法;
----- __init__用于在创建对象时执行操作;
----- __init__通常初始化实例字段并执行其他对象初始化任务。

你可以看到我们不止有刚才描述的init方法,还有别的方法get_width和get_height:

class Rectangle:
	def __init__(self, h, w):
		self.__height = h 
		self.__width = w
		
	def get_width(self):  #我们把self传给方法,我们不传递任何属性或参数,只是传递对象自己给方法
		return self.__width
		
	def get_height(self): 
		return self.__height

4·为矩形类编写更多方法

之前分析的五个方法全写进去:

class Rectangle:
	def __init__(self, h, w):
		self.__height = h
		self.__width = w 
	def perimeter(self):
		return (2 * self.__height) + (2 * self.__width) 
	def area(self):
		return self.__height * self.__width 
	def isSquare(self):
		return (self.__height == self.__width) 
	def get_width(self):
		return self.__width 
	def get_height(self):
		return self.__height

可以根据之前写的一一对应,都在内部传递,看起来很清楚。

5·创建矩形对象

如果我们要从类中实例化一个对象,我们可以:在这里插入图片描述
这意味着box现在是Rectangle对象,我们可以在类的方法中使用box变量。

在这里插入图片描述
box变量保存矩形对象的地址(如果我们打印box,Python会告诉我们box是一个Rectangle对象,存储在一个特定的地址和内存中),然而我们知道在我们的box中,我们有由宽和高参数组成的Rectangle对象。

6·为矩形类编写赋值函数方法

先来看看类的访问器和变异器方法:
由于我们使用私有变量遇到了数据隐藏的概念,类中的字段是私有的。
检索字段数据的方法称为访问器accessor(我们之前实现的那些方法,它们进入一个对象并返回一个存储在该对象中的值)

修改字段数据的方法称为mutator(它们不仅进入也检索值,也有能力接受改变它的值并改变它在对象方法中的存储方式)
程序员希望其他类查看的每个字段都需要一个访问器。(当我们想要什么东西可见时,提供accessor方法可以让用户进来使用数据)
程序员希望被其他类修改的每个字段都需要一个变异器。(mutator允许其他类进入一个类并更改存储的值)

那么我们如何为Rectangle类编写一个mutator方法呢?
在这里插入图片描述
这里的所有方法都是mutator方法

7·调用 setLength 方法

举一个可视的例子,用点符号在box对象上调用set_height
在这里插入图片描述
结果是box变量保存矩形对象的地址,python进入了地址,搜索对象并存储高度为10.
这是执行set_height方法后box对象的状态。我们没有宽的值,但高度成了我们从外面传递的值。

8·对于Rectangle的例子,accessor和mutator是:

在这里插入图片描述
get_width,get_height是accessor;
set_width,set_height是mutator。
这些方法的其他名称是getter和setter。(但这些只对数量,重要的是我们要理解:一个mutator方法能够进入一个对象并改变存储在其中的数据;一个accessor方法则访问数据,不修改数据。)

9·将UML图转换为代码

回到我们的UML图,我们现在需要更复杂的东西。
一旦测试了类结构,就可以编写和测试方法主体。

这个图少了正负号:
在这里插入图片描述
void意识是无意义,所以没什么返回的,但是它们会被传递。

class Rectangle:
	def __init__(self, h, w):
		self.__height = h
		self.__width = w 
	def perim(self):
		return (2 * self.__height) + (2 * self.__width ) 
	def area(self):
		return self.__height * self.__width 
	def isSquare(self):
		return (self.__height == self.__width) 
	def get_width(self):
		return self.__width 
	def get_height(self):
		return self.__height 
	def set_width(self, w):
		self.__width = w 
	def set_height(self, h):
		self.__height = y

10·陈旧的数据

陈旧的数据可能有问题
创建一个返回动态运算的方法而不是用变量,可以避免在对象中出现陈旧数据的情况。

而不是在矩形类中使用区域变量:
在这里插入图片描述

在这种情况下,我们没有变量包含面积的值,我们只有一个返回乘法结果的方法。
当调用这个方法时,它会动态地计算矩形区域的值。(所以更容易理解,我们用的变量少了一个。值是动态创建和返回的,而不是创建和存储的,只是稍后再返回。
现在,对height或width变量的任何更改都不会离开矩形的积。(stale就是:如果我们有一个area变量在计算矩形的面积,当我们改变宽度和高度的值时,除非我们重新开始计数area,否则我们无法更新它。这会导致面积值错误,依据于更改后的宽高值。)

11·类布局约定

源代码文件的布局可能因需求者的不同而不同。
其中一个常见的布局是字段首先列出(init方法放在第一位);第二列方法accessor和mutator通常分组(然后所有方法确保accessor和mutator组在一起,顺序无关紧要,这样当我们看类的时候能更容易认出发生了什么。使代码更加有条理秩序)

12·运行/测试 矩形类

现在我们来谈谈测试

box = Rectangle(3,5)
print ("Perimitar value is %.2f" %box.perim())
print ("Rectangle total area is %.2f" %box.area())
print (box.is_square())
print ("Rectangle height %.2f and width %.2f" %(box.get_height(), box.get_width()))

在这种情况下得出的结果:
在这里插入图片描述
我们类一切正常,因为测试顺利进行。

如果我们最终要使用某些mutator,我们可以将宽高度设置成一样:

box.set_height(9)
box.set_width(9)
print ("Perimitar value is %.2f" %box.perim()) print ("Rectangle total area is %.2f" %box.area()) print ("is it a Square? : ", box.is_square()) print ("Rectangle height %.2f and width %.2f" %(box.get_height(), box.get_width()))

然后重新运行整个代码程序来查看结果:
在这里插入图片描述
这里面使用了mutator方法更改实例变量(高度和宽度)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章