python学习之-- 面向对象

面向对象(简写:OOP)

面向对象编程定义:利用类和对象来创建各种模型,来实现对真实世界的描述。

优点:使程序更容易理解和维护以及扩展代码。

类定义:用来描述具有相同的属性和方法的对象的集合。(简单讲就是个模板)

实例化定义:创建一个类的实例,类的具体对象。

对象定义:通过类定义的数据结构的实例

举例:一个最简单最小结构的类写法如下:

class class_name(object):
    print('bababa')

举例一个正常类的写法:

class 类名称(object):
    def __init__(self,name..) #构造函数
        self.arg1 = name # 普通属性(成员变量),注:self就是实例对象本身,保存在对象内存里
    def fun1(self): # 普通方法(动态属性)
        print('...')

类进行实例化的运行原理:

  1:将类中的对象和方法存储于内存中,
  2:类进行实例化时,先在内存申请一块空间用于存放实例对象
  3:把实例对象的内存地址和赋值参数传递给类模板
  4:模板对传入的值进行self变量赋值,然后将self变量发送到实例对象内存空间。

类的三大特性:封装,继承,多态

  -- 封装:类内部的数据和方法,对数据的赋值和内部调用对类外部而言是透明的。简单说就是隐藏实现的细节,使代码模块化。

      特性:防止数据被随意修改,可以通过此对象对外接口进行直接访问。

       另(类封装了属性和方法,对象封装了普通属性的值)

  -- 继承:一个父类派生出的子类,在父类里定义的属性和方法自动被子类继承,实现一个角色的共同点和不同点的同时存在。使代码重用

      注意:承可以多级继承,不过越多代码会越复杂,建议继承2-3级即可,继承的2个类之间应该是属于的关系。

    -- 被继承的类命名:父类,基类,超类

    -- 继承的类命名:子类,派生类

      --种类:单继承和多继承。

      --继承的过程:从一般到特殊的过程。

             这里“一般”指:父类这样的对一个角色具有共同点。

             这里“特殊”指:子类这样的对每一个角色的不同点的单独定义

      --实现方式有2类:实现继承 和 接口继承

             实现继承:指父类具有的功能,子类继承后直接调用不需再修改。

             接口继承:指仅使用父类的属性和方法的名称,具体实现需要在子类里单独实现。

举例:单继承基本继承写法

 1 class Person(object):
 2     def __init__(self,name,age=22):
 3         self.NAME = name
 4         self.AGE = age
 5         self.storage = 'Normal'
 6     def talk(self):
 7         print('custom ......')
 8 class blackPerson(Person):
 9     def __init__(self,name,age,job):
10         Person.__init__(self,name,age)  #继承父类的属性(经典写法)
11         self.JOB = job
12     def talk(self):
13         Person.talk(self)   # 继承父类的方法,不过这样没有意义,
14         print('非洲语言')
15 class writePerson(Person):
16     def __init__(self,name,mess):
17         Person.__init__(self,name)
18         self.MESS = mess
19     def talk(self):
20         print('speak ENGLISH')
View Code

 -- 多态:同样的方法名的同时又对父类的方法做了不同的实现,这就是同一事务表现的多种形态。特点接口重用。

     (举例:父类定义人会说话,子类分黄种人说汉语,白种人说英语)这就是多态。实现是改写父类的talk方法

举例:python中多态的写法

 1 class Animal(object):
 2     def __init(self,name):
 3         self.name = name
 4     def talk(self):
 5         raise NotImplementedError('Subclass must implement abstrace method') #提示一个需要子类重写的错误
 6 class Cat(Animal):
 7     def talk(self):  # 子类重写
 8         return 'miao'
 9 class dog(Animal):
10     def talk(self):  # 子类重写
11         return 'wang'
12 d = dog()
13 c = Cat()
14 def animal_talk(arg):  # 这里使用单独一个函数实现多态功能
15     return arg.talk()
16 print(animal_talk(d))
17 print(animal_talk(c))
View Code

类的属性分如下:

  -- 公有属性(静态字段):所有属于这个类的对象都可以访问的属性,(在类里直接定义的属性,class下一行定义的)

       修改方法:1:通过对象修改,只改变该对象的属性值,相当于在对象本地内存新创建一个属性值(默认是引用类里的全局变量)

            2:通过“类.公有属性名”修改,将改变的是全局属性值。

            (疑问解释:类中的构造函数不都可以访问么,说的是实例对象,一个实例对象赋给的参数值在其他对象是无法访问的。所以构造函数不属于公有属性。

                  比如:实例化了2个对象a,b,其中实例化a的参数值(a=fun(1,2,3)),对象b就无法访问a的参数值。)

  --成员属性(普通字段):构造函数中的self变量。

  --私有属性:在类中以“__字符串”,双下划线开始的变量名即为私有属性。正常情况下私有属性在类外部是无法访问的。

     访问方法有2种:1:通过在类里定义普通方法来return返回私有属性。2:强制访问写法:实例名._类名__私有属性名。

          举例:使用第一个方法对外提供私有属性访问接口

              def get_hart():

                return self.__heart  #这里就直接返回私有属性值

类的方法分如下:

  -- 普通方法:类中定义的常用方法。def定义的

      小知识(如何将普通方法变为私有方法,1:单独写一个函数,比如名为fun2,然后重写对象的方法名,如d1.fun = fun2,最后执行此对象的方法d1.fun(d1))

  -- 析构方法:语法:def __del__(self),在引用的变量被清空的时候或者通过手工del删除引用的变量后就会自动调用此方法进行内存回收。

      一般用于程序的收尾,比如服务器端要停止服务,这时就需要它来清空客户端的连接。(另说明,只要类被实例化了就算是使用中,将不会自动回收)

  -- 类方法:只能访问类变量(公有属性),不能访问实例变量,一般用在实例化对象后,无法对本身限定好的数据进行修改。

        举例说明:          

            class f1:
              name = 'jack'  #类变量
              @classmethod #类方法
              def fun(self):
                print('classmethod %s' % self.name) # 这里数据只用使用name的值,无法修改

  -- 静态方法:类里定义的方法,当不需要通过self往里传值的时候,就可以将此方法定义为静态方法。

        举例说明:

            class f1:
              @staticmethod  # 静态方法写法
              def fun():     # 注意 静态方法是不需要self传值,这里不写self
              print('staticmethod')
            调用方法为: f1.fun()

  -- 属性方法:把一个方法变成一个静态属性,属性就不需要加括号调用,一般用于最终展示给用户看得结果  

        举例说明:

            class f1:
              def __init__(self):
                self.__food = None # 为属性方法设置的私有属性(用于传值的,如果不使用setter方法,就可以不写)
              @property #属性方法 (静态属性)默认这里只能打印固定数据,无法赋值
              def fun(self): # 方法名
                print('property: %s' % self.name,self.__food)
              @fun.setter # 实现对属性方法赋值功能(注意这里的fun要和上面的方法名一致)
              def fun(self,food):
                print('set to food:',food)
                self.__food = food    # 实现对私有属性的赋值
              @fun.deleter # 实现删除属性方法的赋值
              def fun(self):
                del self.__food # 删除私有变量

            调用方法:d = f1() ; d.fun # 打印属性方法
            赋值方法:d.fun = 'baozi' # 赋值
            删除赋值:del d.fun #删除

  -- 内置方法:类里以:__名称__  这样结构的方法称为类的内置方法。

        1:__doc__:类的描述信息,就是打印类名下的注释信息
        2:__module__:表示当前操作的对象在哪个模块
           __class__:表示当前操作的对象的类名
        3:__init__:构造函数,通过类创建对象时,自动触发执行。
        4:__del__:析构函数,当对象在内存中被释放时,自动触发。
        5:__call__:对象后面加括号,触发执行。

            举例说明:

              class cla1(object):
                def __call__(self, *args, **kwargs):
                  print(args,kwargs)
              ins = cla1()
              ins('jace','vivi',name='jack',age=22)  # 这里执行对象直接返回
              返回:('jace', 'vivi') {'name': 'jack', 'age': 22}        

        6:__dict__:查看类或对象中的所有成员
            print(类名.__dict__):打印类里的所有属性,不包括实例属性。print(实例名.__dict__):打印实例里所有的属性,不包括类属性
        7:__str__:如果一个类中定义了此方法,那么在打印实例对象时,默认输出该方法的返回值

 1 class Person(object):
 2     def __init__(self, name, gender):
 3         self.name = name
 4         self.gender = gender
 5     def __str__(self):
 6         return '(Person: %s, %s)' % (self.name, self.gender)
 7 现在,在交互式命令行下用 print 试试:
 8 
 9 >>> p = Person('Bob', 'male')
10 >>> print p
11 (Person: Bob, male)
View Code

        8:__repr__:在python3里发现直接运行实例和使用pring 输出的状态和__str__ 相同。没看出有什么区别。但是通过sqlalchemy的创建表结构里可以看出区别,

                 通过在表结构里定义__str__返回来的数据是内存对象,通过在表结构里定义__repr__返回来的是转换后的字符串。

        9:__getitem__ / __setitem__ / __delitem__ :用于索引操作,分别表示获取,设置,删除数据。

            举例说明:

 1 class cla1(object):
 2     def __init__(self):
 3         self.data = {}
 4     def __getitem__(self, key):
 5         print("__getitem__: %s" % key)
 6         return self.data.get(key)
 7     def __setitem__(self, key, value):
 8         print('__setattr__:%s,%s' % (key,value))
 9         self.data[key] = value
10     def __delitem__(self, key):
11         print('__delitem__:%s' % (key))
12 ins = cla1()
13 ins['name'] = 'jack'  #调用setitem赋值
14 print(ins['name']) # 调用getitem打印
15 print(ins.data)   # 打印实例属性
View Code        

        10:__new__:先于构造函数执行,构造函数是通过New来自动执行的。所以new是用来创建实例的,默认不用写
             用处:可以在类进行实例化之前,通过new进行定制

1 class foo(object):
2     def __init__(self,name):
3         self.name = name
4         print('foo --init--')
5     def __new__(cls, *args, **kwargs):
6         print('foo --new--')
7         return object.__new__(cls) # 继承父类的new方法,如果注销这个,将不会自动执行构造函数,
8         #以上这行解释,类foo也是一个对象,这里的cls就是foo对象本身,也就相当于self概念。
9 f = foo('jack')
View Code

        11:__metaclass__ : 指定当前类的原类名称,可以修改原类对当前类进行重新设置。在上面的new执行之前,
          执行顺序为:第一步执行metaclass的init方法,第二步执行metaclass的call方法,第三步执行foo函数的new方法,第四步执行foo的initd方法,

                这就是实例化整个路线图。
            看代码:

 1 class Mytype(type):
 2     def __init__(self):                #第一步
 3         super(Mytype.self).__init__(what,bases,dict)
 4     def __call__(self,*args,**kwargs):        #第二步
 5         .....
 6 class foo(object):
 7     __metaclass__ = 'Mytype'
 8     def __init__(self,..):            # 第四步 实例化完成
 9         .....
10     def __new__(cls,*args,**kwargs):
11         return object.__new__(cls)        #第三步
View Code

            看图:

类的 分类:有2种,第一种是:新式类。第二种是:经典类

  -- 他们的区别:1:新式类需要在类名后加(object),经典类不需要,直接定义类名。2:继承方式写法不同。

  -- 继承方式:在Python3中全部(新式类/经典类)为广度优先,在Python2中经典为深度优先,新式类为广度优先。

  -- 继承写法:新式类使用super,经典类直接使用父类名初始化。

        举例说明:

            class A(object):
              def __init__(self):
                self.n = 'A'
            class B(A):
              def __init__(self):
                self.n = 'B'
            class C(A):
                def __init__(self):
                self.n = 'C'
            class D(B,C):
              pass

            mess = fun4() ; print(mess.n)
解释:在python3中,无论是新式类还是经典类,继承顺序都是广度优先,以上顺序为:B->C-A
     在python2中,新式类继承顺序为广度优先,如上,经典类是深度优先为:B->A->C

举例单独说明类中的self。(self == 实例对象)

class dog(object):
  def __init__(self,name):
    self.NAME = name
  def sayhi(self):
    print('wang wang wang , dog name %s' % (self.NAME))

dg1 = dog('jinba')  # 相当于:dog(dg1,'jinba') 注意:self == dg1(实例对象)
dg1.sayhi()     #  就相当于:dg1.sayhi(dg1),因为self在类中默认是传入的。

原文地址:https://www.cnblogs.com/zy6103/p/6911663.html