python面向对象进阶

1. 类的成员

python 类的成员有三种:字段、方法、属性前端

字段

字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不一样,python

  • 普通字段 
    属于对象,只有对象建立以后,才会有普通字段,并且只能经过对象来调用git

  • 静态字段 
    属于类,解释器在加载代码的时候已经建立,对象和类均可以调用程序员

  • 例子:web


  1. class Province:sql

  2.  country = '中国'           #静态字段数据库

  3.  def __init__(self,name):设计模式

  4.      self.name = name            #普通字段并发

  5. #调用字段:app

  6. obj = Province('河南')   #建立对象

  7. res1 = obj.name   #对象调用普通字典

  8. res2 = obj.country    #对象调用静态字段

  9. print('对象调用普通字典:',res1)

  10. print('对象调用静态字段:',res2)

  11. res3 = Province.country   #类调用静态字段

  12. res4 = Province.name    #类调用普通字段,会报错

  13. print('类调用静态字段:',res3)

  14. print('类调用普通字段:',res4)   #报错

  15. 输出结果:

  16. 对象调用普通字典: 河南

  17. 对象调用静态字段: 中国

  18. 类调用静态字段: 中国

  19. Traceback (most recent call last):

  20. File "D:/study-file/git/gitlab/study/code/day08/成员.py", line 24, in <module>

  21. res4 = Province.name  # 类调用普通字段,会报错

  22. AttributeError: type object 'Province' has no attribute 'name'

  23. 由于对象没有建立,因此在内存中并无name这个字段,因此,类直接调用会报错

总结:静态字段在内存中只保存一份 普通字段在每一个对象中都要保存一份 应用场景: 经过类建立对象时,若是每一个对象都具备相同的字段,那么就使用静态字段。普通字段只能用对象访问,静态字段对象和类均可以访问(优先使用类访问)

方法

方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不一样

  • 普通方法

    属于类,由对象去调用执行,参数至少有一个self,执行普通方法时,自动将调用该方法的对象赋值给self;

  • 静态方法

    属于类,由类直接调用.当方法内部不须要对象中封装的值时,能够将方法写成静态,而且使用 @staticmethoe装饰,而且参数中不带self,参数无关紧要

  • 类方法

    静态方法的特殊形式,至少有一个cls参数 由类执行 @classmethoe装饰,执行类方法时,自动将调用该方法的类复制给cls

  • 举例:


  1. class Province:

  2. country = '中国'  # 静态字段

  3. def __init__(self, name):

  4.    self.name = name  # 普通字段

  5. def show(self):             #普通方法

  6.    print(self.country,self.name)

  7. @staticmethod

  8. def f1(arg):                    #静态方法

  9.    print(arg)

  10. @classmethod

  11. def f2(cls):            #类方法   cls为类名

  12.    print(cls)

  13. # 调用字段:

  14. obj = Province('河南')  # 建立对象

  15. obj.show()        #类调用普通方法执行

  16. obj.f1('对象调用静态方法执行')

  17. Province.f1('类调用静态方法执行')

  18. Province.f2()    #类调用类方法执行,返回类名

  19. 执行结果:

  20. 中国 河南

  21. 对象调用静态方法执行

  22. 类调用静态方法执行

  23. <class '__main__.Province'>

总结 相同点:对于全部的方法而言,均属于类(非对象)中,因此,在内存中也只保存一份。不一样点:方法调用者不一样、调用方法时自动传入的参数不一样。

属性

属性是普通方法的变种,使用 @property来装饰,因此具备方法的表现形式,使用字段调用的方法来调用方法,因此也具备字段的访问形式。由对象来调用

  • 属性的基本使用


    从执行结果中能够看出,常规类中方法的调用是obj.方法()的形式,可是此时调用属性是obj.方法,不加括号,这种形式和静态字段调用的形式同样,因此说有静态字段的调用方法;而在代码中看,属性的表现形式都是普通方法的形式,即函数,而后使用property来装饰,因此说有普通方法的表现形式

  1. class Province:

  2.    country = '中国'  # 静态字段

  3.    def __init__(self, name):

  4.        self.name = name  # 普通字段

  5.    def show(self):             #普通方法

  6.        print(self.country,self.name)

  7.    @staticmethod

  8.    def f1(arg):                    #静态方法

  9.        print(arg)

  10.    @classmethod

  11.    def f2(cls):            #类方法   cls为类名

  12.        print(cls)

  13.    @property

  14.    def f3(self):  # 属性

  15.        print(self.name)

  16.    @f3.deleter

  17.    def f3(self):

  18.        print('del  f3')

  19.    @f3.setter

  20.    def f3(self,arg):

  21.        print('set f3',arg)

  22. #调用属性

  23. obj = Province('河南')  # 建立对象

  24. obj.f3    #调用属性,自动执行@f3.getter装饰的方法   此形态相似于静态字段的调用

  25. del obj.f3   #自动执行@f3.deleter装饰的方法,相似于静态字段的del

  26. obj.f3 = '123'  #自动执行@f3.setter装饰的方法,相似静态字段的set方法

  27. 执行结果:

  28. 河南

  29. del  f3

  30. set f3 123

属性的表现形式
  • 装饰器:

即在一个方法上应用@property装饰器,使方法变为一个属性

  ```
  class Foo:
      @property
      def f1(self):
          pass
      @f1.deleter
      def f1(self):
          pass
       @f1.setter
       def f3(self):
          pass
   ```

 * 静态字段: 在类中定义値为property对象的静态字段

      ```
      class Province:
            country = '中国'  # 静态字段

            def __init__(self, name):
                self.name = name  # 普通字段

            def show(self):             #普通方法
                print(self.country,self.name)

            @staticmethod
            def f1(arg):                    #静态方法
                print(arg)

            @classmethod
            def f2(cls):            #类方法   cls为类名
                print(cls)

            def f4(self):
                print(1234)

            def f5(self,arg):
                print('执行set')

            def f6(self):
                print('执行del')

            foo = property(fget=f4, fset=f5, fdel=f6)  # 属性的静态字段表达方式
         #调用属性
        obj = Province('河南')  # 建立对象
        obj.foo    #自动执行f4方法
        del obj.foo  #自动执行f6方法
        obj.foo = '123'   #自动执行f5方法

        输出结果:
        1234
        执行del
        执行set
      ```
  • 总结:

    属性存在乎义是:访问属性时能够制造出和访问字段彻底相同的假象,按字段的操做来执行对象类中定义的属性中特定的方法,如执行obj.foo会自动执行f4方法,del obj.foo 会自动执行f6方法,此映射关系都使用foo = property(fget=f4, fset=f5, fdel=f6)定义好,属性只是伪造了字段的操做方式而已,不会删除对应的东西,只是根据字段的操做方式来执行对应的方法,而具体执行什么方法,方法有什么功能,这都是本身灵活定义 
    属性由方法变种而来,若是Python中没有属性,方法彻底能够代替其功能。

2. 类的成员修饰符

类的成员修饰符使用类的全部成员,包括以下:

  • 公有:在任何地方都能访问和调用

  • 私有:只能在类内部进行调用

    “` 
    class Foo: 
    contry = ‘china’ #公有静态字段 
    __contry1 = ‘china’ #私有静态字段

    def __init__(self,name):
        self.name = name    #公有普通字段
        self.__name1 = name   #私有普通字段
    
    def __f1(self):         #私有方法
        print(self.name)
    
    def f2(self):           #公有方法
        print(self.__contry)
        self.__f1()

    “`

    • 特例 
      若是想要强制访问私有字段,能够经过 对象._类名__ 私有成员名访问 
      如:obj._Foo__\f1, obj_Foo__contry1, 不建议强制访问私有成员

    • 定义:私有成员命名时,前两个字符是下划线。(特殊成员除外,例如:initcalldict 等)

3. 类的特殊成员

python的特殊成员是采用__方法名__ 表示含有特殊意义的成员

  • init 构造方法,该方法在对象建立时自动建立


  1. class Foo:

  2.  def __init__(self,name):

  3.      self.name = name    #公有普通字段

del 析构方法。

当对象在内存中被释放时,自动触发执行,此方法通常无须定义,由于Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,由于此工做都是交给Python解释器来执行,因此,析构函数的调用是由解释器在进行垃圾回收时自动触发执行

  • doc 表示类的描述信息

  class Foo:    """ 描述类信息,牛逼的python """    def func(self):        passprint(Foo.__doc__) #输出:类的描述信息输出结果:    描述类信息,牛逼的python
  • module 和 class

module 表示当前操做的对象在那个模块

class 表示当前操做的对象的类是什么

  class Foo:    def f1(self):        pass
  from test import Foo  obj = Foo()  print(obj.__class__)  print(obj.__module__)  输出:  <class 'test.Foo'>  test
  • call

对象后面加括号,触发执行。注:构造方法的执行是由建立对象触发的,即:对象 = 类名() ;而对于 call 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

  class Foo:      def __init__(self):          pass      def __call__(self, *args, **kwargs):          print('__call__')  obj = Foo() # 执行 __init__  obj()       # 执行 __call__
  • dict 类或对象中的全部成员

 class Foo:    def __init__(self):        self.name = 123    def f1(self):        passprint(Foo.__dict__)   #打印类的全部成员obj = Foo()print(obj.__dict__)     #打印对象中的全部成员输出结果:{'__init__': <function Foo.__init__ at 0x01FA1348>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__doc__': None, 'f1': <function Foo.f1 at 0x01FA11E0>}{'name': 123}
  • str 指定print对象的时候输出的内容

class Foo:    def __init__(self):        self.name = 123    def f1(self):        pass    def __str__(self):        return  "打印对象输出结果"    obj = Foo()print(obj)     #打印对象输出结果:打印对象输出结果
  • getitemsetitemdelitem

用于索引操做,如字典。以上分别表示获取、设置、删除数据

 class Foo:   def __init__(self):       self.name = 123   def __getitem__(self, item):       print('__getitem__',item)   def __delitem__(self, key):       print('__delitem',key)   def __setitem__(self, key, value):       print('__setitem__',key,value)obj = Foo()result = obj['k1']      # 自动触发执行 __getitem__obj['k2'] = 'hahhahhhha'   # 自动触发执行 __setitem__del obj['k1']               ## 自动触发执行 __delitem__输出结果:__getitem__ k1__setitem__ k2 hahhahhhha__delitem k1
  • iter 用于迭代器,之因此列表、字典、元组能够进行for循环,是由于类型内部定义了 iter

class Foo:   def __init__(self,num):       self.num = num   def __iter__(self):       i = 1       while True:           if i <= self.num:               yield i               i += 1           else:               break  obj = Foo(4)  for i in obj:      print(i)  输出结果:  1  2  3  4

以上是经常使用的特殊成员,还有不少不经常使用的,不在举例

4. 面向对象其余

  • isinstance(obj, cls)

    检查是否obj是不是类 cls 的对象

class Foo(object):    passobj = Foo()isinstance(obj, Foo)
  • issubclass(sub, super)

检查sub类是不是 super 类的派生类

class Foo(object):    passclass Bar(Foo):    passissubclass(Bar, Foo)
  • 执行父类的方法

默认状况下当子类和父类的方法同样时,优先执行子类的方法,以下:

class Foo:  def f1(self):      print('Foo.f1')class Bar(Foo):  def f1(self):      print('Bar.f1')obj = Bar()obj.f1()输出结果:Bar.f1

若是想要强制执行父类的方法呢?可使用super(子类名,self).父类方法 格式以下:

class Foo:    def f1(self):        print('Foo.f1')class Bar(Foo):    def f1(self):        super(Bar,self).f1()           #使用super 来强制执行父类的f1方法        print('Bar.f1')obj = Bar()obj.f1()输出结果:Foo.f1        #执行父类f1的结果Bar.f1
  • 应用1,扩展原来代码的功能

    需求:一个开源的web框架,在保证不改变源码的状况下,个性定制本身的环境,适应需求。这就用到了类的继承,我新扩展的功能是在原来功能的基础上进行扩展的,因此,我只须要将新功能类继承源代码的相关功能类,而后使用super强制执行父类的方法,实现基本功能,最后在新类中扩展基本功能便可。此区别于装饰器,使用装饰器须要在原来的类上应用装饰器,那就改变了源码


    若是我要扩展该功能,须要在每次f1执行前打印一个start,执行结束以后,打印一个end,看下面代码

    from test import Foo #从源代码中导入Foo类


    前端调用的时候,我直接调用本身建立的类便可,这就实现了基本的扩展,也不改变源代码


    字典key 的排序是无序的,若是要实现一个有序字典,能够根据类的继承来本身写一个有序字典类 
    实现思路: 
    1.继承dict类,使新定义的类有dict的全部方法 
    2.定一个列表,用来存放字典中的key,输出的时候循环这个列表,那么这个字典就变成有序输出 
    3.使用__setitem__特殊方法实现能够自定义key value 
    4.使用__str__特殊方法实现print字典

    代码以下:


    下面来测试


    • 应用2 实现有序字典

  1. obj = Mydict()              #建立一个字典

  2. obj['k1'] = 'v1'            #字典key value赋值

  3. obj['k2'] = 'v2'

  4. print(obj)              #打印字典

  5. print(type(obj))        #打印类型

  6. 输出:

  7. {'k1':v1,'k2':v2}

  8. <class '__main__.Mydict'>

  1. class Mydict(dict):

  2. def __init__(self):

  3.    self.li = []

  4.    super(Mydict,self).__init__()

  5. def __setitem__(self, key, value):              #获取obj['k1'] = 'v1'形式的赋值

  6.    self.li.append(key)                   #将key存入列表

  7.    super(Mydict, self).__setitem__(key,value)      #强制执行父类的__setitem__,实现字典功能

  8. def __str__(self):  

  9.    temp  = []

  10.    for key in self.li:             #循环列表中的key

  11.        value = self.get(key)

  12.        temp.append("'%s':%s" % (key,value))  #将key value 组成元组存入一个临时列表

  13.    ret = "{" + ','.join(temp) + '}'    #join 来替换key value中间的空格为冒号:,并拼接成字典形式

  14.    return ret

  1. obj = New()

  2. obj.f1()

  3. 输出效果:

  4. ===start====

  5. 源代码

  6. 基本功能执行完毕

  7. ===end===

  1. class New(Foo):

  2.    def f1(self):

  3.        print('===start====')

  4.        super(New,self).f1()

  5.        print('===end===')

  1. #这是源代码类,实现打印输出

  2. class Foo:

  3. def f1(self):

  4.    print('源代码')

  5.    print('基本功能执行完毕')

5. 设计模式-单例模式

单例模式指的是是多个对象建立时,若是每次都须要建立一个实例,在经过该实例去执行指定的方法,这样每次频繁的建立实例,对内存的读写消耗很大,若是将他们共同的实例,经过一种判断机制,若是实例不存在,则建立实例,而后调用某个方法;若是实例存在,则直接调用某个方法,那么在内存中就仅仅保留了一份实例,这样岂不更好

看下面实例,若是class Mysql 是一个数据库链接池

  ```
  class Mysql:
      def __init__(self):
          self.host = 127.0.0.1
          self.port = 3306
          self.dbname = test
          self.user = jeck
          self.passwd = 123123
      def create(self):
          #执行create语句
          pass
      def delete(self):
          #执行delete语句
          pass
  ```

若是用户须要操做数据库,那么须要进行下面操做 
user1 = Mysql() 
user1.create()

user2 = Mysql() 
user2.delete() 
….

发现,每来一个用户,都须要建立一个地址池实例,而后执行某个方法,这样在高并发的网站,直接就崩溃了 
换种思路,若是,我只建立一个地址池对象,用户请求来以后,先进行判断,没有实例的话,就建立,有的话就直接使用,岂不更高效。

“`

class Mysql: 
instance = False 
def init(self): 
self.host = ‘127.0.0.1’ 
self.port = 3306 
self.dbname = ‘test’ 
self.user = ‘jeck’ 
self.passwd = ‘123123’

  def create(self):
      # 执行create语句
      pass

  def delete(self):
      # 执行delete语句
      pass
  @classmethod
  def get_instance(cls):
      if cls.instance:                 #判断instence 是否有値,若是有的话,直接返回
          return cls.instance
      else:
          obj = cls()              #instence没有値的话,建立对象,并将对象赋给instence
          cls.instance = obj
          return obj

obj1 = Mysql() #多例模式 
obj2 = Mysql() #多例模式

obj3 = Mysql.get_instance() #单例模式 
obj4 = Mysql.get_instance() #单例模式

#打印内存地址 
print(‘多例模式:’,obj1) 
print(‘多例模式:’,obj2) 
print(‘单例模式:’,obj3) 
print(‘单例模式:’,obj4)

输出结果: 
多例模式: <main.Mysql object at 0x013AAC70> 
多例模式: <main.Mysql object at 0x013AACD0> 
单例模式: <main.Mysql object at 0x013AAD30> 
单例模式: <main.Mysql object at 0x013AAD30> 
“`

发现使用单例模式后,第二次建立的对象和第一次建立的对象内存地址是同样的,即便再有成千上万后实例,其都是公用的一个链接池 
总结:单利模式存在的目的是保证当前内存中仅存在单个实例,避免内存浪费!

同步更新地址:http://www.cnblogs.com/pycode

相关文章
相关标签/搜索