美文网首页
Day4面向对象编程1/2

Day4面向对象编程1/2

作者: 林清猫耳 | 来源:发表于2018-03-28 23:36 被阅读28次

    关于以下程序的笔记:

    Python函数式编程2/3

    def count():
        fs = []
        for i in range(1,4):
            def f():
                return i*i
            fs.append(f)
        return fs
    
    f1,f2,f3 = count()
    

    输出结果是

    >>> f1()
    9
    >>> f2()
    9
    >>> f3()
    9
    

    首先,程序阅读出来f1,f2,f3=count(),然后要调用count()函数,首先读出他返回的是一个包含3个函数的列表fs,然后再去读取其中的3个函数。

    for i in range(1, 4):
            def f():
                 return i*i
            fs.append(f)
    

    这段代码中实际是先读取for,然后执行fs.append(f),因为f()函数没有参数,所以在连续为append写入3段f()以后,再执行f()的赋值或者计算,在f()函数中,由于已经执行完3次写入过程,因此return 后面的i已经变成了3

    def count():
        fs = [3,4,5]
        return fs
    
    f1,f2,f3 = count()
    
    >>> f1
    3
    >>> f2
    4
    >>> f3
    5 
    

    这段代码调用count()函数,读出他返回的是一个包含三个元素的列表fs,然后读取其中的三个元素。

    def maxx(my_list):
        if len(my_list) == 2:
            return my_list[0] if my_list[0] > my_list[1] else my_list[1]
        sub_max = maxx(my_list[1:])
        return my_list[0] if my_list[0] > sub_max else sub_max
    

    类和实例

    面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

    class Student(object):
        pass
    

    定义好了Student类,就可以根据Student类创建出Student的实例,创建实例是通过类名+()实现的:

    >>> bart = Student()
    >>> bart
    <__main__.Student object at 0x05B765D0>
    >>> Student
    <class '__main__.Student'>
    

    变量bart指向的就是一个Student的实例,后面的0x05B765D0是内存地址,每个object的地址都不一样,而Student本身则是一个类。
    由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的init方法,在创建实例的时候,就把name,score等属性绑上去:

    class Student(object):
    
        def __init__(self, name, score):
            self.name = name
            self.score = score
    

    __init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
    有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:

    >>> bart = Student('Bart Simpson', 59)
    >>> bart.name
    'Bart Simpson'
    >>> bart.score
    59
    
    • 类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响;
    • 方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据;
    • 通过在实例上调用方法,我们就直接操作了对象内部的数据,但无需知道方法内部的实现细节。

    访问限制

    在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。
    但是,从前面Student类的定义来看,外部代码还是可以自由地修改一个实例的namescore属性:

    >>> bart = Student('Bart Simpson', 59)
    >>> bart.score
    59
    >>> bart.score = 99
    >>> bart.score
    99
    

    如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在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))
    

    改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量.__name和实例变量.__score了:

    >>> bart = Student('Bart Simpson', 59)
    >>> bart.__name
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Student' object has no attribute '__name'
    

    这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。
    如果外部代码要获取name和score怎么办?可以给Student类增加get_nameget_score这样的方法:

    class Student(object):
        ...
    
        def get_name(self):
            return self.__name
    
        def get_score(self):
            return self.__score
    

    如果又要允许外部代码修改score怎么办?可以再给Student类增加set_score方法:

    class Student(object):
        ...
    
        def set_score(self, score):
            self.__score = score
    

    注意下面的这种错误写法

    >>> bart = Student('Bart Simpson', 59)
    >>> bart.get_name()
    'Bart Simpson'
    >>> bart.__name = 'New Name' # 设置__name变量!
    >>> bart.__name
    'New Name'
    

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

    >>> bart.get_name() # get_name()内部返回self.__name
    'Bart Simpson'
    

    相关文章

      网友评论

          本文标题:Day4面向对象编程1/2

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