设为首页 收藏本站
查看: 856|回复: 0

[经验分享] 【Python之旅】第四篇(三):Python面向对象编程详解

[复制链接]

尚未签到

发表于 2018-8-5 07:50:52 | 显示全部楼层 |阅读模式
  终于是来到了Python的面向对象编程,以前是没有接触过其它的面向对象编程的语言,因此学习这一部分是相当带劲的,这里也总结一下。
  1.面向对象编程的相关名词及解释
  世界万物,皆可分类,一切皆为对象。
  所谓的面向对象编程,指的是一种编程的思想,通过对具体代码实现过程(面向过程编程)的不断抽象,以形成一个个的类别,以提高我们进行大型程序编写的效率(面向对象的具体实现需要面向过程,大型程序也可以用面向过程来编写,只是比较麻烦)。对于面向对象编程的相关名词和解释如下:
  对象 :类的实体\一个叫Rain的好色的男人
  类:人\动物\机器
  方法:人会走,会思考\狗会叫,会咬人\定义一个类的各个功能
  消息传递:狗叫了,人听见了,就叫通信
  继承:狗都四条腿走路
  封装:人不能引用狗的特性,比如四条腿走路
  多态性:一个叫的功能,可能是低吼,也可是大声叫
  抽象性:简化复杂的现实问题的途径,它可以为具体问题找到最恰当的类定义
  对“类”这个名词举个简单的例子:
  杯子:类
  这个杯子:对象(实体),属于“杯子”这个类
  对“方法”这个名词举个例子:动态方法(动态属性)与静态方法(静态方法可以理解为类的属性)。
  2.类、对象、方法
  关于三者的关系,用下面的一张图片可以非常清晰明确的说明:
DSC0000.jpg

  3.类的语法:第一个面向对象程序
程序代码如下:  
class dog:                    #定义一个类
  def name(self):       #定义类的方法
  print "Hello master, my name is Python."
  

  
D = dog()    #类的实例化,产生类的对象,如果不实例化,将无法访问该类
  
D.name()     #使用类的方法
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python myclass4.py
  
Hello master, my name is Python.
  4.类的方法:有关self
  类的方法(类函数)与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称,但是在调用这个方法的时候你不为这个参数赋值,Python会提供这个值。这个特别的变量指对象本身,按照惯例它的名称是self。
  如你有一个类称为MyClass和这个类的一个实例MyObject。当你调用这个对象的方法MyObject.method(arg1, arg2)的时候,这会由Python自动转为MyClass.method(MyObject, arg1, arg2)。
  类中如果有多个不同的方法,并且类中的变量需要相互访问,这时候就需要使用self即用类自身来作为中间变量以进行变量在不同类中的传递了,可以看下面的一个例子:
程序代码如下:  
class Dog:
  class_object = 'food' #这是一个类变量
  def sayHi(self):
  print 'Hi master , I am your little dog, who do you want me to bite...'
  favorate_food = 'bone'
  self.FavorFood = favorate_food    #将favorate_food变为全局变量,让其它方法可以引用
  def eat(self, food_type):
  if food_type == self.FavorFood:  #不同类方法之间的变量调用,需要通过类本身
  print 'I like it very much..thanks'
  else:
  print 'Do not give me this bull shit...'
  

  
d = Dog()
  
d.sayHi()   '''如果不调用sayHi(),则无法将favorrate_food变成一个类变量,所谓类变量,
  即是类下定义的第一级变量'''
  
d.eat('bone')
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python class7.py
  
Hi master , I am your little dog, who do you want me to bite...
  
I like it very much..thanks
  当然这里实际上是把sayHi方法中的favorate_food变量变为变中的全局变量,需要注意的是,下面的方法是不可以的:
程序代码如下:  
class Dog:
  class_object = 'food'
  def sayHi(self):
  print 'Hi master , I am your little dog, who do you want me to bite...'
  favorate_food = 'bone'
  

  def eat(self, food_type):
  if food_type == self.sayHi().favorate_food: #这样使用是不行的
  print 'I like it very much..thanks'
  else:
  print 'Do not give me this bull shit...'
  

  
d = Dog()
  
d.sayHi()
  
d.eat('bone')
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python class7.py
  
Hi master , I am your little dog, who do you want me to bite...
  
Hi master , I am your little dog, who do you want me to bite...
  
Traceback (most recent call last):
  
  File "class7.py", line 16, in <module>
  
    d.eat('bone')
  
  File "class7.py", line 9, in eat
  
    if food_type == self.sayHi().favorate_food:
  
AttributeError: 'NoneType' object has no attribute 'favorate_food'
  上面程序不行是因为,self.sayHi()时,其实会执行sayHi()方法,因为它本来就是一个函数,并且没有定义返回值,因此会返回None值,导致程序执行出错。
  上面的例子意在说明,不同类方法之间调用变量时,需要将其变为全局变量,并且要通过self即类本身进行引用。即类下的各个方法(函数,name也认为是一个函数),不能独自相互通信,必须要通过类作为中间人来进行通信,self即代表self本身,通过self.name即可完成通信,所以在定义类下的方法时,必须要加一个参数,即self,来代表类本身,否则这个方法就不能被使用当然参数不一定要是self。
  5.类的构造函数__init__()与解构函数__del__()
  关于两个函数的说明,可以看下面一个例子:
程序代码如下:  
class Person:
  def __init__(self,name,age):                #构造函数,只要把类实例化,就会执行此函数
  print 'I am being called right now...'
  self.Name = name
  self.Age = age
  

  def sayHi(self):                            #类的普通方法
  print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age)
  

  def __del__(self):                          #解构函数,当实例在内存中释放时,才会执行此函数
  print 'I got killed just now...bye...', self.Name
  

  
p = Person('Alex',29)
  
p.sayHi()
  
#del p
  
print '*'*60
  

  
p2 = Person('Jack',40)
  
p2.sayHi()
  
#del p2
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python person_class5.py
  
I am being called right now...
  
Hi my name is Alex, i am 29 years old
  
************************************************************
  
I am being called right now...
  
Hi my name is Jack, i am 40 years old
  
I got killed just now...bye... Jack
  
I got killed just now...bye... Alex
  可以看到程序最后有两行相同内容的输出(除了名字不一样),是因为程序结束时,会把该程序在内存中占用的空间释放,于是执行两次解构函数(因为进行了两次类的实例化),才出现这样的情况为了验证这个结论,将程序代码修改为如下并执行:
程序代码如下:  
class Person:
  def __init__(self,name,age):
  print 'I am being called right now...'
  self.Name = name
  self.Age = age
  

  def sayHi(self):
  print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age)
  

  def __del__(self):
  print 'I got killed just now...bye...', self.Name
  

  
p = Person('Alex',29)
  
p.sayHi()
  
del p    #其它不变,只是在做类的另一个实例前,删除该实例
  
print '*'*60
  

  
p2 = Person('Jack',40)
  
p2.sayHi()
  
#del p2
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python person_class5.py
  
I am being called right now...
  
Hi my name is Alex, i am 29 years old
  
I got killed just now...bye... Alex
  
************************************************************
  
I am being called right now...
  
Hi my name is Jack, i am 40 years old
  
I got killed just now...bye... Jack
  上面的程序代码及执行结果便可以说明,解构函数在类完成调用并且在内存中释放时才会执行。
  6.类的公有属性与私有属性及其调用
  类的公有属性即是类下的普通方法,这些方法是可以直接被调用的;而类的私有属性只有在类中不同方法之间可以相互调用,一般情况下是不能在类外直接调用的。
  可以看下面一个例子:
程序代码如下:  
class Person:
  def __init__(self,name,age):
  print 'I am being called right now...'
  self.Name = name
  self.Age = age
  

  def sayHi(self):
  print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age)
  self.__talk()    #可以引用类中的私有属性
  

  def __talk(self):    #私有属性的定义方法
  print "I'm private..."
  

  
p=Person('Alex',29)
  
p.sayHi()
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python private6.py
  
I am being called right now...
  
Hi my name is Alex, i am 29 years old
  
I'm private...
  如果将代码修改为如下,即在类外调用私有属性:
程序代码如下:  
class Person:
  def __init__(self,name,age):
  print 'I am being called right now...'
  self.Name = name
  self.Age = age
  

  def sayHi(self):
  print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age)
  self.__talk()
  

  def __talk(self):
  print "I'm private..."
  

  
p=Person('Alex',29)
  
p.sayHi()
  
p.__talk()    #在类外通过普通方式调用类的私有属性
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python private6.py
  
I am being called right now...
  
Hi my name is Alex, i am 29 years old
  
I'm private...
  
Traceback (most recent call last):
  
  File "private6.py", line 17, in <module>
  
    p.__talk()
  
AttributeError: Person instance has no attribute '__talk' #会出现找不到类方法的错误提示
  当然可以通过特殊的方法引用类中的私有属性:
程序代码:  
class Person:
  def __init__(self,name,age):
  print 'I am being called right now...'
  self.Name = name
  self.Age = age
  

  def sayHi(self):
  print 'Hi my name is %s, i am %s years old' % (self.Name,self.Age)
  self.__talk()
  

  def __talk(self):
  print "I'm private..."
  

  
p=Person('Alex',29)
  
p.sayHi()
  

  
print '*'*30
  

  
p._Person__talk()
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python private6.py
  
I am being called right now...
  
Hi my name is Alex, i am 29 years old
  
I'm private...
  
******************************
  
I'm private...
  7.类的继承
  类有分父类和子类,在有多个子类的情况下,子类通过继承父类的属性或方法,就可以节省很多代码空间。可以先看下面一个没有参数传递的类的继承简单例子:
程序代码如下:  
class person:                #父类
  

  def tell(self, name):
  print 'hi my name is', name
  

  
class student(person):       #子类,继承父类
  

  def study(sefl):
  print 'I am studying Py right now.'
  

  
s = student()
  

  
s.study()
  
s.tell('MengFanHao') #子类继承父类后便可以直接调用父类的方法
  
                     #在有多个需要同时执行相同功能的子类情况下,使用类的继承可以节省代码空间
  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python cla_with_no_arg9.py
  
I am studying Py right now.
  
hi my name is MengFanHao
  看过上面的例子后,再看下面一个含有参数传递的例子,通过该例子也可以很好地理解前面第2点中关于类、对象、方法的理解:
class SchoolMember:        #父类,学校成员  school_name = 'Oldboy Linux edu.'    #第一级变量,即类属性
  def __init__(self,name,gender,nationality = 'CN'):    #构造函数
  self.name = name
  self.gender = gender
  self.nation = nationality
  

  def tell(self):    #普通的类方法
  print 'Hi, my name is %s , I am from %s' % (self.name,self.nation)
  

  
class Student(SchoolMember):    #子类,学生,继承父类学校成员的相关属性
  def __init__(self, Name, Gender, Class, Score, Nation = 'US'): #子类下的方法
  SchoolMember.__init__(self, Name, Gender, Nation) #让父类使用子类传递过去的参数
  self.Class = Class
  self.Score = Score
  

  def payTuition(self, amount):    #子类下的方法
  if amount < 6499:
  print 'Get the fuck off...'
  else:
  print 'Welcome onboard!'
  

  
class Teacher(SchoolMember):    #子类,老师,继承父类学校成员的相关属性
  def __init__(self, Name, Gender, Course, Salary, Nation = 'FR'):
  SchoolMember.__init__(self, Name, Gender, Nation)
  self.course = Course
  self.Salary = Salary
  

  def teaching(self):
  print 'I am teaching %s, i am making %s per month !' % (self.course, self.Salary)
  

  
S1 = Student('WangFanHao', 'Male', 'Python', 'C+', 'JP') #实例化一个子类对象,学生
  
S1.tell()    #直接继承父类中的tell()方法
  
S1.payTuition(4999)    #使用子类Student()自身中的类方法
  
print S1.school_name   #直接继承父类的一个属性
  

  
print '*'*60
  

  
S2 = Student('ShitTshirt', 'Male', 'Linux', 'B')
  
S2.tell()
  
S2.payTuition(6500)
  
#S2.age = 29
  
#print S2.age
  

  
print '*'*60
  

  
T1 = Teacher('Alex', 'Male', 'C++', 5000)   #实例化一个子类对象,学生
  
T1.tell()            #直接继承父类中的tell()方法
  
T1.teaching()        #直接继承父类的一个属性
  

  
print 'S1.name:', S1.name    #测试用,观察输出结果
  
print 'S2.name:', S2.name
  
print 'T1.name:', T1.name
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python class_continue8.py
  
Hi, my name is WangFanHao , I am from JP
  
Get the fuck off...
  
Oldboy Linux edu.
  
************************************************************
  
Hi, my name is ShitTshirt , I am from US
  
Welcome onboard!
  
************************************************************
  
Hi, my name is Alex , I am from FR
  
I am teaching C++, i am making 5000 per month !
  
S1.name: WangFanHao
  
S2.name: ShitTshirt
  
T1.name: Alex
  通过上面的例子便可以很好地理解类的继承的作用了,即如果需要在多个子类中执行相同的代码功能时,就可以通过类的继承来节省代码空间。
  8.类的属性修改:setattr(),delattr()与getattr()
  以上面程序为例,做如下的演示:
  首先在交互器中导入该类:
>>> import class_continue8  
Hi, my name is WangFanHao , I am from JP
  
Get the fuck off...
  
Oldboy Linux edu.
  
************************************************************
  
Hi, my name is ShitTshirt , I am from US
  
Welcome onboard!
  
************************************************************
  
Hi, my name is Alex , I am from FR
  
I am teaching C++, i am making 5000 per month !
  
S1.name: WangFanHao
  
S2.name: ShitTshirt
  
T1.name: Alex
  
>>> import tab
  
>>> class_continue8.
  
class_continue8.S1                 class_continue8.__hash__(
  
class_continue8.S2                 class_continue8.__init__(
  
class_continue8.SchoolMember       class_continue8.__name__
  
class_continue8.Student            class_continue8.__new__(
  
class_continue8.T1                 class_continue8.__package__
  
class_continue8.Teacher            class_continue8.__reduce__(
  
class_continue8.__class__(         class_continue8.__reduce_ex__(
  
class_continue8.__delattr__(       class_continue8.__repr__(
  
class_continue8.__dict__           class_continue8.__setattr__(
  
class_continue8.__doc__            class_continue8.__sizeof__(
  
class_continue8.__file__           class_continue8.__str__(
  
class_continue8.__format__(        class_continue8.__subclasshook__(
  
class_continue8.__getattribute__(
  
  setattrr():在类中添加属性
1.子类有的属性,属于该子类的对象没有定义,会继承该属性;如果有定义,则不会继承子类的该属性  
>>> class_continue8.Student.age    #原来Student类中并没有age属性
  
Traceback (most recent call last):
  
  File "<stdin>", line 1, in <module>
  
AttributeError: class Student has no attribute 'age'
  
>>> setattr(class_continue8.S)
  
class_continue8.S1            class_continue8.SchoolMember
  
class_continue8.S2            class_continue8.Student
  
>>> setattr(class_continue8.Student,'age',29)    #在Student类中添加age属性
  
>>> class_continue8.Student.age    #再次查看age属性
  
29
  
>>> class_continue8.S1.age    #S1与S2作为Student类的实例化对象,也会有age属性
  
29
  
>>> class_continue8.S2.age
  
29
  
>>> setattr(class_continue8.S1,'age',26)
  
>>> class_continue8.S1.age        #此时S1对象有定义,因此不会继承所属子类的该属性
  
26
  

  
2.子类的对象有的属性,但在其所属子类没有定义,则该子类不会反继承该属性
  
>>> setattr(class_continue8.S1,'tuition',5000)    #如果仅仅是在对象中添加tuition属性
  
>>> class_continue8.Student.age
  
29
  
>>> class_continue8.Student.tuition    #则在S1对象所属的类Student中并不会有tuition属性
  
Traceback (most recent call last):
  
  File "<stdin>", line 1, in <module>
  
AttributeError: class Student has no attribute 'tuition'
  
>>> class_continue8.S1.tuition
  
5000
  
>>> class_continue8.S2.tuition        #因此S2对象也不会有该属性
  
Traceback (most recent call last):
  
  File "<stdin>", line 1, in <module>
  
AttributeError: Student instance has no attribute 'tuition'
  

  
3.父类有的属性,子类中没有定义,则子类会继承该属性;如果子类中有定义,则不会继承
  
>>> setattr(class_continue8.SchoolMember,'name','Python')    #在子类在没有定义
  
>>> class_continue8.SchoolMember.name
  
'Python'
  
>>> class_continue8.Student.name    #因此子类会继承该属性
  
'Python'
  
>>> setattr(class_continue8.SchoolMember,'age',25)    #在父类中定义子类有定义的属性
  
>>> class_continue8.SchoolMember.age
  
25
  
>>> class_continue8.Student.age    #子类已经定义了age属性,因此不会再继承父类的该属性
  
29
  从上面的例子可以看出,对于父类、子类、对象,属性的优先级以本地定义的为主,如果本地没有定义,则继承上一级的属性,如果有定义,则使用本地的。
  delattr():删除类中的属性
>>> class_continue8.SchoolMember.name  
'Python'
  
>>> delattr(class_continue8.SchoolMember,'name')
  
>>> class_continue8.SchoolMember.name
  
Traceback (most recent call last):
  
  File "<stdin>", line 1, in <module>
  
AttributeError: class SchoolMember has no attribute 'name'
  getattr()的主要用法如下:
程序代码如下:  
class person:
  

  def tell(self, name):
  print 'hi my name is', name
  

  def study(sefl):
  print 'I am studying Py right now.'
  

  
class student(person):
  

  def study(sefl):
  print 'I am studying Py right now.'
  

  
p = person()
  

  
vars = ['tell', 'study']
  

  
v1 = vars[0]
  

  
getattr(p, v1)('Oldboy')
  

  
执行情况如下:
  
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python cla_getattr_with_no_arg10.py
  
hi my name is Oldboy
  对于该程序,如果直接使用p.v1('name')来访问类中的方法是不行的,会有如下的提示错误:
xpleaf@xpleaf-machine:/mnt/hgfs/Python/day4$ python cla_getattr_with_no_arg10.py  
Traceback (most recent call last):
  
  File "cla_getattr_with_no_arg10.py", line 21, in <module>
  
    p.v1('Oldboy')
  
AttributeError: person instance has no attribute 'v1'
  因此getattr()的主要用途就在于有一个类有多个方法时,需要对该类的所有方法都执行一遍,那么可以将类中的方法都写入一个列表中,再通过getattr()和循环的方法来完成,这样就可以节省很多代码空间。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-546730-1-1.html 上篇帖子: 为什么要学习Python及Python环境安装 下篇帖子: python使用元组、字典向函数传递多个参数、python冗余参数处理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表