• 面向对象的思维去设计程序


    什么是面向对象编程

    面向对象编程是一种程序的范式,它把程序看成是对不同对象的相互调用,对现实世界建立的一种模型。在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法。

    什么是类

    class ClassMate:
           block
    
    类的名字常常以大写开头  驼峰命名法
    

      

    程序中类的用法
    . 专门用来访问属性,本质操作的就是__dict__
    OldboyStudent.school #等于经典类的操作OldboyStudent.__dict__['school']
    OldboyStudent.school='Oldboy' #等于经典类的操作OldboyStudent.__dict__['school']='Oldboy'
    OldboyStudent.x=1 #等于经典类的操作OldboyStudent.__dict__['x']=1
    del OldboyStudent.x #等于经典类的操作OldboyStudent.__dict__.pop('x')

    什么是类对象

    注意类名后面有个冒号,在block块里面就可以定义属性和方法了。当一个类定义完之后,就产生了一个类对象。类对象支持两种操作:引用和实例化。引用操作是通过类对象去调用类中的属性或者方法,而实例化是产生出一个类对象的实例,称作实例对象。比如定义了一个goods类

    class goods:
        name = 'apple'       #定义了一个属性
        #定义了一个方法
        def printName(self):
            print(self.name)
    abc=goods()
    abc.printName()
    '''apple
    '''

    goods类定义完成之后就产生了一个全局的类对象,可以通过类对象来访问类中的属性和方法了。

    在上面代码中注释的很清楚了,name是一个属性,printName( )是一个方法,与某个对象进行绑定的函数称作为方法。一般在类里面定义的函数与类对象或者实例对象绑定了,所以称作为方法;而在类外定义的函数一般没有同对象进行绑定,就称为函数。

    python为类内置的特殊属性

    类名.__name__# 类的名字(字符串)
    类名.__doc__# 类的文档字符串
    类名.__base__# 类的第一个父类(在讲继承时会讲)
    类名.__bases__# 类所有父类构成的元组(在讲继承时会讲)
    类名.__dict__# 类的字典属性
    类名.__module__# 类定义所在的模块
    类名.__class__# 实例对应的类(仅新式类中)

    更好的理解类对象

    class goods:
        name = 'apple'       #定义了一个属性
        def __init__(self,name):
             self.name=name
    #类对象产生,其实goods默认继承了object类,类对象的产生与object里面的内置方法有关系
    
    print(goods.__dict__)
    
    sdsd=goods('scscs')
    
    print(goods.__dict__)
    
    '''
    {'__module__': '__main__', 'name': 'apple', '__init__': <function goods.__init__ at 0x00000237D68798C8>, '__dict__': <attribute '__dict__' of 'goods' objects>, '__weakref__': <attribute '__weakref__' of 'goods' objects>, '__doc__': None}
    {'__module__': '__main__', 'name': 'apple', '__init__': <function goods.__init__ at 0x00000237D68798C8>, '__dict__': <attribute '__dict__' of 'goods' objects>, '__weakref__': <attribute '__weakref__' of 'goods' objects>, '__doc__': None}
    可以看出来类里面的__init__只是初始化类的实例化结果,类的名称空间不发生变化
    如果变量name没有被初始化,对象sdsd也可以使用父类的name变量
    '''
    
    print(sdsd.__dict__)
    '''{'name': 'scscs'}
    '''

    属性

    class people:  
        name = 'jack'  
        age = 12  
     
    p = people()  
    print(p.name,p.age)

    定义了一个people类,里面定义了name和age属性,默认值分别为'jack'和12。在定义了类之后,就可以用来产生实例化对象了,这句p = people( )实例化了一个对象p,然后就可以通过p来读取属性了。这里的name和age都是公有的,可以直接在类外通过对象名访问,如果想定义成私有的,则需在前面加2个下划线 ' __'

    class people:  
        __name = 'jack'  
        __age = 12  
      
    p = people()  
    print(p.__name,p.__age)

    程序运行会报错

    Traceback (most recent call last):  
      File "C:/PycharmProjects/FirstProject/oop.py", line 6, in <module>  
        print p.__name,p.__age  
    AttributeError: people instance has no attribute '__name

    提示找不到该属性,因为私有属性是不能够在类外通过对象名来进行访问的。在Python中没有像C++中public和private这些关键字来区别公有属性和私有属性,它是以属性命名方式来区分,如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性(方法也是一样,方法名前面加了2个下划线的话表示该方法是私有的,否则为公有的)

    类即类型

    python中一切皆为对象,且python3中类与类型是一个概念,类型就是类

    #类型dict就是类dict
    >>> list
    <class 'list'>
    
    #实例化的到3个对象l1,l2,l3
    >>> l1=list()
    >>> l2=list()
    >>> l3=list()
    
    #三个对象都有绑定方法append,是相同的功能,但内存地址不同
    >>> l1.append
    <built-in method append of list object at 0x10b482b48>
    >>> l2.append
    <built-in method append of list object at 0x10b482b88>
    >>> l3.append
    <built-in method append of list object at 0x10b482bc8>
    
    #操作绑定方法l1.append(3),就是在往l1添加3,绝对不会将3添加到l2或l3
    >>> l1.append(3)
    >>> l1
    [3]
    >>> l2
    []
    >>> l3
    []
    #调用类list.append(l3,111)等同于l3.append(111)
    >>> list.append(l3,111) #l3.append(111)
    >>> l3
    [111] 

    补充: 我们都知道Python一切皆对象,那么Python究竟是怎么管理对象的呢?

    1、无处不在的__dict__
    首先看一下类的__dict__属性和类对象的__dict__属性
    由此可见, 类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的
    对象的__dict__中存储了一些self.xxx的一些东西
    
    2、Python里什么没有__dict__属性
    虽然说一切皆对象,但对象也有不同,就好比不是每个人的女朋友都是一个人一样,一些内置的数据类型是没有__dict__属性的,如下
    num = 3
    ll = []
    dd = {}
    print num.__dict__
    print ll.__dict__
    print dd.__dict__
    
    3、发生继承时候的__dict__属性
     子类有自己的__dict__, 父类也有自己的__dict__,子类的全局变量和函数放在子类的dict中,父类的放在父类dict中
    1)每个类的类变量、函数名都放在自己的__dict__中
    2)子类对象可以用父类的__dict__里面的值
    
    总结:
    1) 内置的数据类型没有__dict__属性
    2) 每个类有自己的__dict__属性,就算存着继承关系,父类的__dict__ 并不会影响子类的__dict__
    3) 对象也有自己的__dict__属性, 存储self.xxx 信息
    无处不在的__dict__

    方法

    在类中可以根据需要定义一些方法,定义方法采用def关键字,在类中定义的方法至少会有一个参数,一般以名为'self'的变量作为该参数(用其他名称也可以),而且需要作为第一个参数。下面看个例子:

    class people:  
        __name = 'jack'  
        __age = 12  
      
        def getName(self):  
            return self.__name  
        def getAge(self):  
            return self.__age  
      
    p = people()  
    print p.getName(),p.getAge()  
    View Code

    类中定义的函数(没有被任何装饰器装饰的),其实主要是给对象使用的,而且是绑定到对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法

    总结:类的数据属性是大家共有的,而且大家的内部地址是一样的,用的就是一个
             类的函数属性是绑定到大家身上的,内部地址不一样,绑定方法指的是绑定到对象身上。
             绑定方法:绑定到谁的身上,就是给谁用的,谁来调用就会自动把自己当做第一个参数传入。
    
    定义在类内部的变量,是所有对象共有的,id全一样,
    如果类想调用绑定方法,就必须遵循函数的参数规则,有几个参数,就必须传递几个参数。 
    定义在类内部的函数,是绑定到所有对象的,是给对象来用的,obj.fun()会把obj本身当做一个参数来传递。
    
    
    
    在类内部定义的函数虽然可以由类来调用,但是并不是为了给类用的,在类内部定义的函数的目的就是为了绑定到对象身上的。
    
    在类的内部来说,__init__是类的函数属性,但是对于对象来说,就是绑定方法。
    
    命名空间的问题:先从对象的命名空间找,随后在从类的命名空间找,随后在从父类的命名
    空间找。
    
    在定义类的时候,可以想什么先写什么。
    总结绑定方法

    强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用,谁来调用,就会将‘谁’本身当做第一个参数传给方法,即自动传值(方法__init__也是一样的道理)

    s1.learn()     #等同于OldboyStudent.learn(s1)
    s2.learn()     #等同于OldboyStudent.learn(s2)
    s3.learn()     #等同于OldboyStudent.learn(s3)
    注意:绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self。

    如果对self不好理解的话,可以把它当做C++中类里面的this指针一样理解,就是对象自身的意思,在用某个对象调用该方法时,就将该对象作为第一个参数传递给self。

    #类的数据属性是所有对象共享的,id都一样
    print(id(OldboyStudent.school))
    
    print(id(s1.school))
    print(id(s2.school))
    print(id(s3.school))
    
    '''
    4377347328
    4377347328
    4377347328
    4377347328
    '''
    
    #类的函数属性是绑定给对象使用的,obj.method称为绑定方法,内存地址都不一样
    #ps:id是python的实现机制,并不能真实反映内存地址,如果有内存地址,还是以内存地址为准
    print(OldboyStudent.learn)
    print(s1.learn)
    print(s2.learn)
    print(s3.learn)
    '''
    <function OldboyStudent.learn at 0x1021329d8>
    <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x1021466d8>>
    <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146710>>
    <bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146748>>
    类的数据属性与函数属性分析

    注意点:

    构造方法__init__(self,....):在生成对象时调用,可以用来进行一些初始化操作,不需要显示去调用,系统会默认去执行。构造方法支持重载,如果用户自己没有重新定义构造方法,系统就自动执行默认的构造方法。

     __init__():__init__方法在类的一个对象被建立时,马上运行。这个方法可以用来对你的对象做一些你希望得到的初始化

    # Filename: class_init.py  
    class Person:  
        def __init__(self, name):  
            self.name = name  
        def sayHi(self):  
            print 'Hello, my name is', self.name  
      
    p = Person('Swaroop')  
    p.sayHi()  
      
    输出:  
    Hello, my name is Swaroop 
    
    
    #__init__的必须注意的点
    1、该方法内可以有任意的python代码
    2、一定不能有返回值
    

      

  • 相关阅读:
    CSS学习笔记07 盒子模型
    [Android]AndFix使用说明
    [Android]自定义控件LoadMoreRecyclerView
    [算法]Plus One
    [Android]android Service后台防杀
    [Android]android studio预览视图时报错
    [算法]删除无序单链表中值重复出现的节点
    [算法] 将单链表的每K个节点之间逆序
    [Android]热修复框架AndFix测试说明
    [算法]单链表的选择排序
  • 原文地址:https://www.cnblogs.com/596014054-yangdongsheng/p/9830265.html
Copyright © 2020-2023  润新知