• 面向对象


    面向对象最重要的概念就是类(Class)和实例(Instance)

    类是抽象的模板

    而实例是根据类创建出来的一个个具体的“对象”

    每个对象都拥有相同的方法,但各自的数据可能不同。

    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))
    
    Lilei=Student('Lilei',100)
    Lilei.print_score()

    和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。

    访问限制

    如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:

    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))
    
    Lilei=Student('Lilei',100)
    print(Lilei.__score)

    直接访问会报错

    Traceback (most recent call last):
      File "D:/pyfile/func.py", line 11, in <module>
        print(Lilei.__score)
    AttributeError: 'Student' object has no attribute '__score'

    可以通过方法调用返回值

    需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name____score__这样的变量名。

    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))
    
        def get_name(self):
            return self.__name
    
        def get_score(self):
            return self.__score
    
    bart = Student('Bart Simpson', 59)
    bart.get_name()
    bart.__name = 'New Name' # 设置__name变量!
    print(bart.__name)
    print(bart.get_name())

    表面上看,外部代码“成功”地设置了__name变量,但实际上这个__name变量和class内部的__name变量不是一个变量!内部的__name变量已经被Python解释器自动改成了_Student__name,而外部代码给bart新增了一个__name变量。

    继承和多态

    继承有什么好处?最大的好处是子类获得了父类的全部功能。

    继承的另一个好处:多态。

    判断一个变量是否是某个类型可以用isinstance()

    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...')
    
    a = list() # a是list类型
    b = Animal() # b是Animal类型
    c = Dog() # c是Dog类型
    
    print(isinstance(a, list))          #Ture
    print(isinstance(b, Animal))        #Ture
    print(isinstance(c, Dog))           #Ture
    
    print(isinstance(c,Animal))         #Ture
    print(isinstance(b,Dog))            #False

    要理解多态的好处,我们还需要再编写一个函数,这个函数接受一个Animal类型的变量:

    多态的好处就是对于一个变量,我们只需要知道它是Animal类型,无需确切地知道它的子类型,就可以放心地调用run()方法,而具体调用的run()方法是作用在AnimalDogCat还是Tortoise对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal的子类时,只要确保run()方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:

    对扩展开放:允许新增Animal子类;

    对修改封闭:不需要修改依赖Animal类型的run_twice()等函数。

    静态语言 vs 动态语言

    对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

    对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了:

    如上述程序中Dog不继承Animal也可以运行这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。Python的“file-like object“就是一种鸭子类型。对真正的文件对象,它有一个read()方法,返回其内容。但是,许多对象,只要有read()方法,都被视为“file-like object“。许多函数接收的参数就是“file-like object“,你不一定要传入真正的文件对象,完全可以传入任何实现了read()方法的对象

    使用isinstance()

    对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。

    使用dir()

    如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:

    >>> dir('ABC')
    ['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']

    实例属性和类属性

    给实例绑定属性的方法是通过实例变量,__init__方式

    但是,如果Student类本身需要绑定一个属性呢?可以直接在class中定义属性,这种属性是类属性,归Student类所有:

    class Student(object):
        name = 'Student'
    
    s = Student() # 创建实例s
    print(s.name) # 打印name属性,因为实例并没有name属性,所以会继续查找class的name属性
    print(Student.name) # 打印类的name属性
    s.name = 'Michael' # 给实例绑定name属性
    print(s.name) # 由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性
    print(Student.name) # 但是类属性并未消失,用Student.name仍然可以访问
    del s.name # 如果删除实例的name属性
    print(s.name) # 再次调用s.name,由于实例的name属性没有找到,类的name属性就显示出来了

    从上面的例子可以看出,在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性

  • 相关阅读:
    几种简单的素数判定法(转)
    在Ubuntu下编译WebKit源码
    Struts2+JSON特别让人恶心的一个问题
    强大的asp.net 绑定组件
    关于单点登陆的示例代码
    NHibernate 如何高效的数据翻页?
    FLEX学习网站大全
    pku1207
    windows7试用过程常见问题解答
    什么是HTTPS?
  • 原文地址:https://www.cnblogs.com/zsc329/p/8955302.html
Copyright © 2020-2023  润新知