美文网首页
Python 面向对象编程

Python 面向对象编程

作者: _YZG_ | 来源:发表于2017-12-21 15:43 被阅读18次

    访问限制

    class Student(object):
    
        def __init__(self, name, score):
            self.__name = name
            self.__score = score
    
        def print_score(self):
            print('%s: %s' % (self.__name, self.__score))
    
    实例变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
    
    
        def get_score(self):
            return self.__score
    
        def set_score(self, score):
            self.__score = score
    
    注意__XX__,是特殊变量,特殊变量是可以直接访问的,不是private
    
    
    如果看到类似于:_name这样的实例变量外部是可以访问的,
    但是按照约定俗称的规定,当你看到这样的变量时,
    “虽然我可以被访问,但是,请把我视为私有变量,不要随意访问” 
    
    双下划线开头的实例变量也可以访问,不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,
    所以,仍然可以通过_Student__name来访问__name变量,但是不要这么干,
    因为不同版本的Python解释器可能会把__name改成不同的变量名
    
    
    最后注意下面的这种错误写法:
    >>> bart = Student('Bart Simpson', 59)
    >>> bart.get_name()
    'Bart Simpson'
    >>> bart.__name = 'New Name' # 设置__name变量!
    >>> bart.__name
    'New Name'
    

    继承多态

    class Animal(object):
        def run(self):
            print('Animal is running...')
    
    
    class Dog(Animal):
    
        def run(self):
            print('Dog is running...')
    
        def eat(self):
            print('Eating meat...')
    
    判断一个变量是否是某个类型可以用isinstance()判断:
    >>> isinstance(a, list)
    True
    >>> isinstance(b, Animal)
    True
    >>> isinstance(c, Dog)
    True
    
    def run_twice(animal):
        animal.run()
        animal.run()
    
    
    对于静态语言(例如Java)来说,如果需要传入Animal类型,
    则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。
    
    对于Python这样的动态语言来说,则不一定需要传入Animal类型。
    我们只需要保证传入的对象有一个run()方法就可以了:
    
    class Timer(object):
        def run(self):
            print('Start...')
    
    

    获取对象信息

    >>> type('t')
    <class 'str'>
    >>> type (None)
    <class 'NoneType'>
    >>> 
    
    type()也可以判断函数或者类
    >>> type(abs)
    <class 'builtin_function_or_method'>
    
    type()函数返回对应的Class类型
    
    >>> type('abc')==str
    True
    >>> type('abc')==type(123)
    False
    
    判断一个对象是否是函数怎么办?可以使用types模块中定义的常量
    >>> import types
    >>> def fn():
    ...     pass
    ...
    >>> type(fn)==types.FunctionType
    True
    >>> type(abs)==types.BuiltinFunctionType
    True
    >>> type(lambda x: x)==types.LambdaType
    True
    >>> type((x for x in range(10)))==types.GeneratorType
    True
    
    对于class的继承关系来说,使用type()就很不方便,我们要判断class的类型,
    可以使用isinstance()函数
    
    >>> a = Animal()
    >>> d = Dog()
    >>> h = Husky()
    然后,判断:
    
    >>> isinstance(h, Husky)
    True
    
    能用type()判断的基本类型也可以用isinstance()判断:
    >>> isinstance('a', str)
    True
    >>> isinstance(123, int)
    True
    >>> isinstance(b'a', bytes)
    True
    
    并且还可以判断一个变量是否是某些类型中的一种
    >>> isinstance([1, 2, 3], (list, tuple))
    True
    >>> isinstance((1, 2, 3), (list, tuple))
    True
    
    
    使用dir()获取一个对象的所有的属性和方法
    >>> dir('ABC')
    ['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
    
    
    >>> len('ABC')
    3
    >>> 'ABC'.__len__()
    3
    
    >>> class MyDog(object):
    ...     def __len__(self):
    ...         return 100
    ...
    >>> dog = MyDog()
    >>> len(dog)
    100
    
    
    仅仅把属性和方法列出来是不够的,配合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') # 有属性'x'吗?
    True
    >>> obj.x
    9
    >>> hasattr(obj, 'y') # 有属性'y'吗?
    False
    >>> setattr(obj, 'y', 19) # 设置一个属性'y'
    >>> hasattr(obj, 'y') # 有属性'y'吗?
    True
    >>> getattr(obj, 'y') # 获取属性'y'
    19
    >>> obj.y # 获取属性'y'
    19
    
    
    >>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
    404
    
    获取对象方法
    >>> hasattr(obj, 'power') # 有属性'power'吗?
    True
    >>> getattr(obj, 'power') # 获取属性'power'
    <bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
    >>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
    >>> fn # fn指向obj.power
    <bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
    >>> fn() # 调用fn()与调用obj.power()是一样的
    81
    
    
    如果可以直接写
    sum = obj.x + obj.y
    就不要写:
    
    sum = getattr(obj, 'x') + getattr(obj, 'y')
    
    
    一个正确的用法的例子如下:
    
    def readImage(fp):
        if hasattr(fp, 'read'):
            return readData(fp)
        return None
    

    实例属性和类属性

    
    实例属性属于各个实例所有,互不干扰;
    
    类属性属于类所有,所有实例共享一个属性;
    
    不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。
    
    >>> class Student(object):
    ...     name = 'Student'
    ...
    >>> s = Student() # 创建实例s
    >>> print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
    Student
    >>> print(Student.name) # 打印类的name属性
    Student
    >>> s.name = 'Michael' # 给实例绑定name属性
    >>> print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
    Michael
    >>> print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
    Student
    >>> del s.name # 如果删除实例的name属性
    >>> print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了
    Student
    

    相关文章

      网友评论

          本文标题:Python 面向对象编程

          本文链接:https://www.haomeiwen.com/subject/bhhiwxtx.html