比尔云BierYun--阿里云最新优惠活动
阿里云优惠码丨阿里云代金券

Python学习(24)–面向对象编程1

Python学习(24)–面向对象编程1http://www.bieryun.com/2378.html

这一节我们将介绍使用面向对象的编程思想来组织和编写Python代码,首先我们会讲解面向对象的思想,类和对象的概念。接着,将会介绍类中一些常用的方法,如构造函数,打印函数,析构函数等等。

1.面向对象思想

面向对象和面向过程都是一种编程思想,之前我们编写的代码,实现的功能都很简单,代码量也不多,也没有涉及到面向对象的编程思想,但当我们需要编写大量的代码去完成一个工程时,就需要考虑如何组织代码来高效的完成这个工程,这个时候就用到了面向对象。那么什么是面向对象?

面向对象可以和面向过程对比着来理解.例如盖一间房子,面向过程考虑的事情是盖房子的过程,比如先打地基,然后用砖砌墙,再搭房梁等等。面向过程会把盖房细节和盖房需要完成任务的先后次序都会林列出来,然后按部就班的完成盖房子这件事情。

而面向对象考虑的是房子这个对象是由哪些部件组成的,比如一个房子有地基,窗户,墙,房梁,房顶等等。而不会考虑如何打好地基,如何去砌墙等等这些细节问题,只会考虑一个房子有什么?具体房子某一个部分如何做的任务会交给相应的工人去完成。

2.类的概念

在面向对象中,类是一个抽象的概念,抽象的东西描述的都是事物的共性。例如人就是一个抽象的概念,人的共性有姓名,年龄,身高,体重等等标签,人的共性还有走路,吃东西等等行为。具体的每个人又有不同的姓名年龄,喜欢吃不同的东西,又体现出具体事物间的个性。

人这种抽象概念,在面向对象的世界里对应的是一个类;人的共性中的标签,在面向对象中对应的是类的属性;人的共性中的行为,在面向对象中对应的是类中的方法。具体的人又是人这个类的实例对象。在Python中定义一个类的格式如下:

在Python中定义一个类使用的是关键字class,表示这是一个类。后跟类的名字和父类列表,父类列表中是类的父类,涉及到继承的概念,以后会介绍到。所有的类都会有一个共同的父类(或者称之为超类或基类),就是object类,如果一个类没有特殊指定的父类,那么在定义类时父类列表一般只有object类,或者为空。最后,在类中定义类的属性和方法行为。

以人这个抽象概念为例,类的定义代码如下:

 

[python] view plain copy

  1. class Person():
  2.     name=””
  3.     age=0
  4.     height=0
  5.     weight=0
  6.     def run(self):
  7.         print(“running…”)
  8.     def eat(self,food):

[python] view plain copy

  1. print(self.name+” eat “+food)

如上为一个类名为Person的类,父类列表为空,默认直接继承于object类。Person类的属性有name,age,height,weight;定义的方法行为有,run(self)和eat(self,food)。这里需要注意的是,在Python中,每一个类中的方法参数列表不能为空,至少要有参数self,self表示的是类的当前对象。例如,Person类有一个实例对象zhangsan,那么self表示的就是zhangsan这个对象。代码如下:

 

[python] view plain copy

  1. zhangsan=Person()#创建一个变量名为zhangsan的Person对象
  2. zhangsan.name=“zhangsan”#将对象zhangsan的属性name的值设置为”zhangsan”
  3. zhangsan.eat(“Apple”)

通过如上代码,可以发现创建类的实例化对象的方式为:对象名=类名(参数列表),参数列表在之后的构造函数中会介绍到,如zhangsan=Person()就是创建了一个Person类的对象;获取对象属性的方式为:对象名.属性名,如zhangsan.name=”zhangsan”;对象调用方法的方式为:对象名.方法名(参数列表),如zhangsan.eat(“Apple”),为调用Person类中定义的方法eat(self,food),打印结果如下:

Person类的方法eat(self,food)中的代码如下:

 

[python] view plain copy

  1. def eat(self,food):
  2.     print(self.name+” eat “+food)

在对象zhangsan调用方法eat(self,food)时,参数self表示的是对象zhangsan;self.name表示的是对象zhangsan的name属性值:”zhangsan”,所以zhangsan.eat(“Apple”)的打印结果为”zhangsan eat Apple”。

其实,类和Python中其他基本数据类型一样,都只是一种数据类型,只不过类的数据结构更加复杂,更加抽象。使用类创建的对象相当于基本数据类型的一个变量,是占据内存空间的一个实例。

3.参数self

在类中的,一个方法的参数列表的第一个参数代表的含义是该类的当前对象。之前我们在设计Person类时,方法eat(self,food),其中第一个参数为self,表示的就是Person类的当前对象,但是需要注意的是self并不是一个关键字,Python中只是默认类中方法参数列表的第一个参数代表该类的当前对象,self只是一个形参名,也可以使用其它形参名来代替,只不过使用self含义更加见名知意。如下,我们可以换一个形参名来证明以上所述:

 

[python] view plain copy

  1. class Person():
  2.     name=””
  3.     age=0
  4.     height=0
  5.     weight=0
  6.     def run(I):
  7.         print(I.name)
  8.         print(“running…”)
  9.     def eat(I,food):
  10.         print(I.name+” eat “+food)
  11. per=Person()
  12. per.name=“zhangsan”
  13. per.run()

 

如上代码所示,将Person类中方法的参数名self全部替换为I。然后创建一个Person类的对象per,并修改其name属性的值为”zhangsan”,当per调用方法run()时,参数列表第一个参数I表示的就是当前对象per,打印结果如下:

通过打印结果可以看出,将Person类中的方法参数名self全部替换为I后,并没有出现错误提示,这是因为Python默认将类中方法参数列表的第一个参数识别为当前对象,这也决定了类中每一个方法的参数列表至少有一个参数,如果只有一个参数,那么这个参数的含义就是代表当前对象。

一般并不建议修改参数名self,这样降低程序的可读性。

4.类的构造函数

构造函数用于在创建一个类的实例对象时,初始化对象的属性值。对应到现实中,每个具体的人在出生时,姓名、体重、身高这些属性都可能有不同的属性值。而定义一个类的构造函数和定义方法的形式是一样的,如下是Person类的构造函数:

 

[python] view plain copy

  1. def __init__(self,name,age,height,weight):
  2.     self.name=name
  3.     self.age=age
  4.     self.height=height
  5.     self.weight=weight

 

每个类的构造函数的函数名都是__init__,参数列表一般为类的属性,在构造函数中执行的操作为初始化对象的属性值。如self.name=name为初始化当前被构造对象的name属性值。如下代码:

 

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight):
  3.         self.name=name
  4.         self.age=age
  5.         self.height=height
  6.         self.weight=weight
  7.     def run(self):
  8.         print(self.name)
  9.         print(“running…”)
  10.     def eat(self,food):
  11.         print(self.name+” eat “+food)
  12. per=Person(“zhangsan”,12,123,50)
  13. print(per.name,per.age,per.height,per.weight)

 

如上代码,通过构造函数创建并初始化了一个Person对象per,并打印per的属性值,打印结果如下:

需要注意的是,一个类没有构造函数也能创建这个类的对象,之所以如此,是因为类中有一个默认的构造函数,如下:

[python] view plain copy

  1. def __init__(self):
  2.     pass

如果没有为类定义构造函数,创建对象时使用的是默认构造函数。

5.析构函数

构造函数是在内存中创建 一个类的对象,而析构函数是销毁该类在内存中的对象。在类中定义一个析构函数,用于动态的释放程序内存。但是由于Python中有垃圾回收机制,所以一般不需要用户自己释放内存。析构函数也一般不常用,这里只做简单的介绍。

在类中定义一个析构函数,就是定义一个函数名为__del__的方法,如下就是一个简单的析构函数,当用户销毁类的实例对象时,会调用这个方法。

 

[python] view plain copy

  1. def __del__(self):
  2.     print(“this is person’s del”)

那么如何销毁一个实例对象呢?其实和之前介绍的在内存中销毁一个基本类型数据的方式是一样的,即del 对象名。如下代码:

 

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight):
  3.         self.name=name
  4.         self.age=age
  5.         self.height=height
  6.         self.weight=weight
  7.     def run(self):
  8.         print(self.name)
  9.         print(“running…”)
  10.     def eat(self,food):
  11.         print(self.name+” eat “+food)
  12.     def __del__(self):
  13.         print(“this is person’s del”)
  14. person1=Person(“zhangsan”,10,123,40)
  15. del person1

 

如上,创建了一个Person类的对象person1,并销毁它。当销毁对象person1时,就会调用Person类的析构函数__del__(self)。代码打印结果如下:

6.打印函数__str__(self)和__repr__(self)

在Python编程过程中,有时候我们可能需要打印一个对象的具体属性信息。这个时候就用到了打印函数__str__(self)和__repr__(self)。两者主要有两个不同点:一是在命令窗口模式下打印结果的不同;二是优先级的不同。如下我们在不使用打印函数的情况下打印一个对象。

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight):
  3.         self.name=name
  4.         self.age=age
  5.         self.height=height
  6.         self.weight=weight
  7.     def run(self):
  8.         print(self.name)
  9.         print(“running…”)
  10.         print(self.__class__)
  11.         person = self.__class__(“wangwu”1312340)
  12.     def eat(self,food):
  13.         print(self.name+” eat “+food)
  14. person1 = Person(“zhangsan”1012340)
  15. print(person1)

 

打印的结果如下:

可见在不使用打印函数的情况下,打印一个对象,显示的只是对象的类型和对象在内存中的地址,而用户真正关心的对象属性信息并没有打印出来。使用打印函数不仅可以打印用户真正关心的信息,还可以可以自定义信息打印的形式。如下是一个使用打印函数打印对象的例子:

 

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight):
  3.         self.name=name
  4.         self.age=age
  5.         self.height=height
  6.         self.weight=weight
  7.     def run(self):
  8.         print(“running…”)
  9.     def eat(self,food):
  10.         print(self.name+” eat “+food)
  11.     def __repr__(self):
  12.         return “__repr__:”+self.name+“-“+str(self.age)+“-“+str(self.weight)+“-“+str(self.height)
  13.     def __str__(self):
  14.         return “__str__:”+self.name+“-“+str(self.age)+“-“+str(self.weight)+“-“+str(self.height)
  15. person1=Person(“zhangsan”,10,123,40)
  16. print(person1)

如上,在Person类中定义了两个打印函数__repr__(self)和__str__(self),都用于打印对象的属性信息。打印结果如下:

通过打印结果可见,在打印Person对象时,调用了方法__str__(self),打印了此方法返回的字符串。如果类中__str__(self)和__repr__(self)两个打印函数都存在,使用print函数打印对象时,Python会先调用方法__str__(self),因为前者的优先级要比后者的优先级要高。只有当类中只有函数__repr__(self)时,打印对象才会调用__repr__(self)。

两者的不同点还体现在命令窗口的交互模式下,在命令窗口模式下,一般适用于使用__repr__(self)。两者在打印结果上有着稍微的不同。如下:

如上,当类中只有方法__repr__(self)时,无论是>>>person 回车或者直接print(person)都会调用Person对象的__repr__(self)方法打印结果。

如上,当类中只有方法__str__(self)时,print(person)会调用Person对象的方法__str__(self);而>>>person 回车却没有调用打印函数,只是打印的对象的类型和内存地址。

如上,在交互模式下,>>>person 回车调用的是打印函数__repr__(self);而print(person)调用的是打印函数__str__(self)。可以这样理解,在交互模式下>>>对象名 回车,打印一个对象时,打印函数__repr__(self)的优先级要比__str__(self)高,所以使用这种方式打印对象,会调用对象的__repr__(self);而使用print(对象名)打印一个对象时,__str__(self)优先级较高,所以会优先调用函数__str__(self)打印对象。

以上就是这节介绍的所有内容,下一节将会继续介绍面向对象中的继承和多态的编程思想,敬请期待。

未经允许不得转载:比尔云 » Python学习(24)–面向对象编程1
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

强烈推荐

高性能SSD云服务器ECS抗攻击,高可用云数据库RDS