Python学习(25)--面向对象编程2

Python学习(25)--面向对象编程2

Python学习(25)--面向对象编程2

这一节我们将继续介绍面向对象编程,主要涉及到的内容有属性的访问权限,特殊属性,类中的继承的编程思想。

1.属性的访问权限

Python类中常用的有3种属性类型,第一种是形如XXX的属性,这种属性可以供对象在类的外部访问,访问权限比较大;第二种是形如_XXX的属性,这种属性也可以供对象在类的外部访问,但是一般不建议这样做,;第三种是形如__XXX的属性,即私有属性,这种属性不能在类的外部访问,仅限于类的内部使用,访问权限最小。以下是三种属性的代码例子:

(1)XXX属性

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight,money,score):
  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. per = Person("zhangsan"11123201000080)
  12. print(per.name)

打印结果如下:

Python学习(25)--面向对象编程2

通过打印结果可见,在Person类的外部可以访问形如XXX的属性name。

(2)_XXX属性

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight,money,score):
  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. per = Person("zhangsan"11123201000080)
  12. print(per._age)

 

打印结果如下:

Python学习(25)--面向对象编程2

虽然可以访问属性_age,但是在编程时请将其当做私有属性看待,在类的内部使用形如_XXX的属性。

(3)__XXX属性

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight,money,score):
  3.         self.name=name
  4.         self._age=age
  5.         self.height=height
  6.         self.weight=weight
  7.         self.__money=money
  8.     def run(self):
  9.         print("running...")
  10.     def eat(self, food):
  11.         print(self.name + " eat " + food)
  12. per = Person("zhangsan"11123201000080)
  13. print(per.__money)

 

打印结果如下:

Python学习(25)--面向对象编程2

打印结果含义为:Person类不存在属性__money。这是因为作为私有属性的__money,仅限于类的内部使用,在Person类的外部访问时不允许的。但私有属性并不是绝对的私有,Python只是将私有属性的变量名改变成为"_类名"+"私有属性名"。如私有属性__money,Python将属性名"__money"改变成了"_Person__money",所以在访问私有属性__money不能访问到。如下,我们直接访问Python改变之后的私有属性名"_Person__money",则可以访问到。

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight,money,score):
  3.         self.name=name
  4.         self._age=age
  5.         self.height=height
  6.         self.weight=weight
  7.         self.__money=money
  8.     def run(self):
  9.         print("running...")
  10.     def eat(self, food):
  11.         print(self.name + " eat " + food)
  12. per = Person("zhangsan"11123201000080)
  13. print(per._Person__money)

 

打印结果如下:

Python学习(25)--面向对象编程2

如上,我们使用Python改变之后的私有属性名"_Person__money"后可以访问到__money

的值。但是这种访问方式是不建议的,这样做会使数据的安全性降低。

那么如何访问私有属性呢?既然只能在类中访问私有属性,那么类中的私有属性值,可以通过将私有属性作为方法返回结果的方式读取;修改私有属性的值可以调用类中方法,通过传参的方式在类中修改私有属性的值。代码如下:

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight,money,score):
  3.         self.name=name
  4.         self._age=age
  5.         self.height=height
  6.         self.weight=weight
  7.         self.__money=money
  8.     def run(self):
  9.         print("running...")
  10.     def eat(self, food):
  11.         print(self.name + " eat " + food)
  12.     def getMoney(self):
  13.         return self.__money
  14.     def setMoney(self,money):
  15.         self.__money=money
  16. per = Person("zhangsan"11123201000080)
  17. print(per.getMoney())
  18. per.setMoney(999)
  19. print(per.getMoney())

 

如上代码,Person类中定义的方法getMoney(self)返回结果为私有属性__money的值,用于读取私有属性__money;调用方法setMoney(self,money),通过传参的方式在类中修改私有属性__money的值。

打印结果如下:

Python学习(25)--面向对象编程2

如上,我们使用get和set方法读取和修改对象的私有属性值,这样做的优点就是提高的

代码的安全性和灵活性。

提高安全性体现在当类中的属性只能读不能写时,我们可以把属性设置为私有,只提供

属性的get方法,不提供set方法,避免了因为修改属性的值而使数据不安全。

提高灵活性体现在使用get或者set方法时可以进行其他操作,不完全只是机械的修改

或者读取数据。例如当修改数据时,可以先判断传入的参数是否合法,如果不合法则不予修

改,而通过直接赋值来修改数据更加机械,灵活性不高。

2.特殊属性

Python类中形如__XXX__的属性称为特殊属性,代表着特殊的含义。例如,__class__

表示对象的类型,__name__表示类名,__dict__表示类属性组成的字典等等。代码例子如下:

[python] view plain copy

  1. class Person():
  2.     def __init__(self,name,age,height,weight,money,score):
  3.         self.name=name
  4.         self._age=age
  5.         self.height=height
  6.         self.weight=weight
  7.         self.__money=money
  8. per = Person("zhangsan"11123201000080)
  9. print(per.__class__)
  10. print(Person.__name__)
  11. print(per.__dict__)

代码打印结果如下:

Python学习(25)--面向对象编程2

如上为打印类的特殊属性结果,per.__class__表示对象的类型为<class '__main__.Person'>;per.__dict__为对象per属性组成的字典,字典中的每一个元素的键为属性名,值为属性值。更多的特殊属性如下:

Python学习(25)--面向对象编程2

3.类的继承

面向对象中继承的编程思想来源于现实,在现实世界中,子女从父母那里继承财产,或者子女与父母长得相像,其实是继承了父母的基因。而面向对象中的继承也是类似,子类继承了父类,就继承了父类的属性和方法,拥有了父类中的属性和方法。以下,我们使用一个小例子来了解面向对象中继承的规则和优点。

在本例中有两个模块,Student.py和Person.py,两个类分别是Student类和Person类,Student类继承自Person类。类图如下:

Python学习(25)--面向对象编程2

如上类图所示,Person类中的属性有name,age,__money;方法有eat(),run(),getMoney(),setMoney();Student类中的独有属性有stuId;Student类继承了Person类,便拥有了Person类的属性和方法,可以访问相关属性和方法。

其中模块Person.py的代码如下:

[python] view plain copy

  1. class Person:
  2.     def __init__(self,name,age,money):
  3.         self.name=name
  4.         self.age=age
  5.         self.__money=money
  6.     def run(self):
  7.         print("running")
  8.     def eat(self,food):
  9.         print("eat "+food)
  10.     def getMoney(self):
  11.         return self.__money
  12.     def setMoney(self,money):
  13.         self.__money=money

以上是Person类定义的属性和方法。

模块Student.py的代码如下:

[python] view plain copy

  1. from Person import Person#导入父类
  2. class Student(Person):#父类列表中为Student类的父类,这里继承的父类是Person类
  3.     def __init__(self,name,age,stuId,money):
  4.         Person.__init__(self,name,age,money)#使用父类的构造函数初始化子类对象的属性值
  5.         self.stuId=stuId#子类的独有属性
  6.     def getStuMoney(self):#读取__money属性值
  7.         return self.__money

[python] view plain copy

[python] view plain copy

  1. #测试代码部分
  2. stu=Student("zhangsan",12,"0001",100)
  3. print("name:",stu.name)
  4. print("age:",stu.age)
  5. stu.run()
  6. stu.eat("Apple")
  7. print("stuId:",stu.stuId)
  8. print(stu.getStuMoney())

 

以上为Student类的定义和测试代码。首先如果父类和子类并不位于同一模块中,需要从其他模块导入父类;子类的父类列表中为父类的类名;初始化子类对象时,可以调用父类的构造函数初始化,调用的方式有两种,第一种如上super(Student,self).__init__(name,age,money);第二种方式为Person.__init__(self,name,age,money)。以上两种方式都是使用父类的构造函数,并将当前对象self和属性实参传入,初始化父类和子类共同拥有的属性。

Student.py中测试代码的打印结果如下:

Python学习(25)--面向对象编程2

如上所示,Student对象stu可以访问父类的属性name,age和方法eat(),run()都没有报错,这说明Student类作为Person类的子类,继承了父类的这些方法和属性。但是当调用方法getStuMoney(self)时访问继承自父类的私有属性"__money"时,却报错为:" 'Studnet' object has no attribute '__money' ",含义为:Student对象不存在属性'__money'。

这是因为子类Student并没有继承父类Person的私有属性__money。如果继承了父类的私有属性__money,那么Student类便拥有了私有属性__money,当通过get方法访问__money时便不会出错。但是,通过getStuMoney(self)访问私有属性__money时发生错误,说明Student类并没有从父类Person继承私有属性__money。

其实,在继承关系中子类并不能继承父类的私有属性,只能继承父类的非私有属性,这也是继承的规则,应注意这一点。

那么子类对象如何访问没有继承到的父类属性呢?虽然没有继承父类的私有属性,但继承了父类访问私有属性的get和set方法,调用继承到的get和set方法就可以访问父类的私有属性。代码修改模块Student.py的测试代码如下:

 

[python] view plain copy

  1. from Person import Person#导入父类
  2. class Student(Person):#父类列表中为Student类的父类,这里继承的父类是Person类
  3.     def __init__(self,name,age,stuId,money):
  4.         Person.__init__(self,name,age,money)#使用父类的构造函数初始化子类对象的属性值
  5.         self.stuId=stuId#子类的独有属性
  6.     def getStuMoney(self):#读取__money属性值
  7.         return self.__money
  8. stu=Student("zhangsan",12,"0001",100)
  9. print(stu.getMoney())

代码打印结果如下:

Python学习(25)--面向对象编程2

之前的Student.py的测试代码中,调用Student类中的自定义方法getStuMoney()访问没有从父类Person继承到的私有属性__money,报出错误。而直接调用父类访问私有属性__money的getMoney(),可以访问私有属性__money,没有报错。这说明,子类访问没有从父类继承到的私有属性的方式为:调用父类访问私有属性的get和set方法,因为get和set方法是子类可以继承到的父类方法。

下面来分析下继承的优点。

继承的优点:当有若干个类是属于相同的类型时,可以将多个类的相同属性抽象在父类中,使得每个类只需要继承父类,相同的属性不需在类中重新编写,简化了代码,减少了冗余。

当需要修改类的属性时,只需要修改父类中的属性,而不需要修改子类中的属性,提高了代码的健壮性。

继承时实现多态的前提。

下一节继续介绍面向对象中的多继承和多态,敬请期待。

原文地址http://www.bieryun.com/2382.html