Python面向对象编程(类与实例、数据封装、继承多态、type()、isinstance())-5

一、类和实例

1. 属性定义相关问题

  • 类名通常大写
  • 定义的形式为class Student(object):,Student后面的括号表示继承哪个类,如果没有合适的就是用object。
  • 一些我们认为必须绑定的类属性,通过定义一个__init__方法,该方法的第一个参数永远是self,因为self就是指向创建的实例本身。
  • 有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但是self不需要传,Python解释器自己会把实例变量传进去。
  • 和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。

2. 数据封装

  • 通过在类的内部定义访问类的属性函数,进行封装数据。
  • 方法就是与实例绑定的函数,和普通的函数不同,方法可以直接访问实例的数据。
  • 和静态语言不同,Python允许对于实例变量绑定任何数据,也就是说,对于两个实例变量,虽然他们都是同一个类的不同实例,但是拥有的变量名称都可能不同。

二、限制访问

  1. 如果要让内部的属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只能够内部访问,不能外部访问。
  2. 如果外部代码要访问,可以给Student类增加get_nameget_score方法进行外部访问。
  3. 如果又要修改score,可以增加set_name方法。
  4. 有些时候,你会看见一个下划线开头的实例变量名,比如_name,这样的实例变量名是可以访问的,但是按照规定是被当成私有变量。
  5. 双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量
  6. 但是强烈建议你不要这么干,因为不同版本的Python解释器可能会把__name改成不同的变量名。总的来说就是,Python本身没有任何机制阻止你干坏事,一切全靠自觉。
class Student(object):
    def __init__(self, name, gender):
        self.__name = name
        self.__gender = gender
    
    def get_name(self):
        return self.__name

    def get_gender(self):
        return self.__gender

    def set_gender(self, gender):
        self.__gender = gender


bart = Student('Bart', 'male')
if bart.get_gender() != 'male':
    print('测试失败!')
else:
    bart.set_gender('female')
    if bart.get_gender() != 'female':
        print('测试失败!')
    else:
        print('测试成功!')    

三、继承和多态

  1. 继承最大的好处就是,对于子类来说,获得了父类的全部功能。
  2. 当然也可以对子类增加一些方法,比如Dog类。
  3. 当子类和父类都存在相同的方法时,子类的方法会覆盖父类的方法,在代码运行时候,总会调用子类的方法,这样我们就获得了继承的另一个好处:多态
  4. 所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行
  5. 多态好处,调用方只管调用,不管细节,这就是著名的开闭原则:对扩展开放:允许新增Animal子类;对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。
  6. 静态语言 vs 动态语言,对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法;对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了。

四、获取对象信息

  1. 使用type()函数,可以用来判断对象的类型。返回对应的Class类型。
  2. 如果要判断一个对象是否为函数,可以使用types模块中定义的常量
  3. 使用isinstance()判断Class类型。并且还可判断一个变量是否是某些类型中的一种,isinstance([1, 2, 3], (list, tuple)
  4. 要获取一个对象的所有属性和方法,可以使用dir()函数。配合getattr()setattr()hasattr(),我们可以直接操作一个对象的状态。
>>> class MyObject(object):
...     def __init__(self):  
...         self.x = 9
...     def power(self):
...         return self.x * self.x
... 
>>> obj = MyObject()
>>> hasattr(obj, 'x')
True
>>> obj.x
9
>>> hasattr(obj, 'y')
False
>>> setattr(obj, 'y', 19)
>>> hasattr(obj, 'y')
True
>>> getattr(obj, 'y')
19
>>> obj.y
19
>>> getattr(obj, 'z')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyObject' object has no attribute 'z'
>>> getattr(obj, 'z', 404)
404
>>> hasattr(obj, 'power')
True
>>> getattr(obj, 'power')
<bound method MyObject.power of <__main__.MyObject object at 0x00000224FC11FF60>>
>>> fn = getattr(obj, 'power') 
>>> fn
<bound method MyObject.power of <__main__.MyObject object at 0x00000224FC11FF60>>
>>> fn()
81

五、实例属性和类属性

  1. 给实例绑定属性的方法是通过实例变量或通过self变量。
  2. 如果Student类本身需要绑定一个属性们可以直接在class中定义属性,这种属性是类属性,归Student类所有。
  3. ,在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性
posted @ 2020-03-29 21:44  睿晞  阅读(212)  评论(0编辑  收藏  举报