Think Deep,Work Lean

python之面向对象

Posted on By zack

概述

关于python的编程有以下几种方式

  • 面向过程:根据业务逻辑从上到下写垒代码
  • 函数式: 将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
  • 面向对象: 对函数进行分类和封装,让开发“更快更好更强”

创建类和对象

面向对象其实就是对类和对象的使用,类就是一个模版,模版里包含多个函数,函数里实现一些功能;对象则是根据模版创建实例,通过实例对象可以执行类中的函数。

class Foo:  
  #创建类中的函数
  def Bar(self):
    #do something

#根据类Foo创建对象obj
obj = Foo()

python 自醒反射继承鸭子类型类方法静态方法静态字段属性装饰器

面向对象的三大特性

封装

封装故名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

class Foo:
  def __init__(self,name,age):
    self.name = name
    self.age = age

#根据类Foo创建对象
#创建对象时,会自动执行类的__init__方法
obj1 = Foo('kaiz',18)
obj2 = Foo('amm',28)
#如上,即是将kaiz,18分别封装到obj1/self的name和age属性中
#self是一个形式参数,当执行obj1 = Foo('kaiz',18)时,self等于obj1

调用被封装的内容

  • 通过对象直接调用
class Foo:
  def __init__(slef,name,age):
    self.name = name
    self.age = age
obj1 =Foo('kaiz',18)
print obj1.name
print obj1.age
  • 通过self间接调用
class Foo:
  def __init__(slef,name,age):
    self.name = name
    self.age = age

  def detail(self):
    print self.name
    print self.age

继承

继承,子类继承父类(派生类继承基类)

class Father:
  def __init__(self,name,age):
    self.name = name
    self.age = age

  def bad_hobby:
    print "smoke,drink"

class Son(Father):
  def __init__(self,name,age):
    self.name = name
    self.age = age
#创建Son类的对象
obj = Son('amm',18)
#由于是继承,因此obj具由Father类的方法
obj.bad_hobby
> smoke,drink

同时继承后,子类可以改良父类的方法。另:类分经典类和新式类,如果父类继承了object类,那么该类就是新式类,否则便是经典类。在多继承中,当类是经典类时,会按照深度优先方式查找;当类是新式类时,会按照广度优先试查找。

#多继承
class A(B,C)

多态

class F1:
    pass


class S1(F1):

    def show(self):
        print 'S1.show'


class S2(F1):

    def show(self):
        print 'S2.show'

def Func(obj):
    print obj.show()

s1_obj = S1()
Func(s1_obj)

s2_obj = S2()
Func(s2_obj)

类的成员

类的成员可以分为三大类:

  • 字段:普通字段、静态字段
  • 方法:普通方法、类方法、静态方法
  • 属性: 普通属性

字段

普通字段和静态字段在定义和使用中有所区别,本质区别是内存中保存位置不同;普通字段属于类对象,静态字段属于类

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

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

 #直接访问普通字段
obj = Province('河北省')
print obj.name

 #直接访问静态字段
Provice.country

由上述代码可以看出普通字段需要创建对象来访问,静态字段通过类来访问。

方法

  • 普通方法:由对象调用,至少一个self参数,执行普通方法时,自动将调用该方法的对象赋值给self
  • 类方法:由类调用,至少一个cls参数,执行类方法时,自动将调用该方法的类复制给cls 被classmethod修饰的函数不需要实例化就可以直接调用,不需要self参数,传入cls参数
  • 静态方法:由类调用,无默认参数
class Foo:
  def __init__(self,name):
    self.name = name

  def ord_func(self):
    """定义普通方法,至少一个self参数"""
    #print self.name
    print 普通方法

  @classmethod
  def class_func(cls):
    """定义类方法,至少有一个cls参数"""
    print "类方法"

  @staticmethod
  def static_func():
    """定义静态方法,无默认参数"""
    print '静态方法'

#调用普通方法
f = Foo()
f.ord_func()

#调用类方法
Foo.class_func()

#调用静态方法
Foo.static_func()

补充一个类方法的示例

In [9]: class A:
   ...:     def __init__(self):
   ...:         self.name="zk"
   ...:     def get_name(self):
   ...:         print(self.name)
   ...:     @classmethod
   ...:     def get_name_cls(cls):
   ...:         cls().get_name()

In [10]: A.get_name_cls()
zk
In [24]: class foo(object):
    ...:     price = 5
    ...:     def __init__(self,name):
    ...:         self.name = name
    ...:     def regular_func(self):
    ...:         print(self.name)
    ...:     @staticmethod
    ...:     def static_method_func():
    ...:         print("static_method_func")
    ...:     @classmethod
    ...:     def classmethod_func(cls,name):
    ...:         cls(name).regular_func()


 In [26]: A=foo("kaiz")

 In [27]: A.regular_func()
 kaiz

 In [28]: A.price
 Out[28]: 5

 In [29]: A.static_method_func()
 static_method_func

 In [30]: A.classmethod_func("amm")
 amm

属性

属性就是普通方法的变种,在定义时,在普通方法的基础上添加@property装饰器,属性仅有一个self参数,调用时无需括号;方法: foo_obj.func(),属性: foo_obj.prop; 属性两种定义方式,一种是用装饰器的形式,一种是静态字段

  • 属性的基本使用
###########定义#########
class Foo:
  def Func(self):
    pass
  #定义属性
  @property
  def prop(self):
    return "kaiz"
    pass
###########调用##########
foo_obj = Foo()
foo_obj.func()
foo_obj.prop      
#调用属性
result = foo_obj.prop

类成员的修饰符

类成员的修饰符

  • 私有成员:私有成员在命名时,前两个字符是下划线,特殊成员除外如: _init_、_call_、__dict__等
class C:
  def __init__(self):
    self.name = '公有字段'
    self.__foo = '私有字段'
  • 公有成员:公有静态字段类可可以访问,类内部也可以访问,派生类中也可以访问;私有静态字段,仅类内部可以访问
class C:
  name = '公有静态字段'
  def func(self):
    print C.name

class D(C):
  def show(self):
    print C.name

C.name #类访问

obj = C()
obj.func() #类内部可以访问

obj_son = D()
obj_son.show() #派生类中可以访问

对照如下

class C:
  __name = "公有静态字段"
  def func(self):
    print C.__name

class D:
  def show(self):
    print C.__name

C.__name  #类访问  --> 错误

obj = C()
obj.func()  #类内部可以访问  -->正确

obj_son = D()
obj_son.show() #派生类中可以访问  -->错误

类的特殊成员

 __doc__

表示类的描述信息

class Foo:
  """描述类信息"""
  def func(self):
    pass

print Foo.__doc
#输入类的描述信息
  • _module_:表示当前操作的对象在哪个模块
  • __class__表示操作的对象的类是什么
  • _init_
  • _del_:析构方法,对对象在内存在被释放时,自动触发执行,最后一次呐喊。注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
    def __del__(self):
        pass
  • _call_:对象后面加括号触发执行
class Foo:
    def __init__(self):
        pass    
    def __call__(self, *args, **kwargs):
        print '__call__'
obj = Foo() # 执行 __init__
obj()       # 执行 __call__
  • _dict_:类或对象中的所有成员
  • _str_:如果一个类中定义了__str__方法,那就在打印对象时,默认输入该方法的返回值。如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
      def __str__(self):
          return 'kaiz'
    obj = Foo()
    print obj
    # 输出:kaiz
    
  • _getitem_、_setitem_、_delitem_:用于索引操作,如字典。以上分别表示获取、设置、删除数据
#!/usr/bin/env python
# -*- coding:utf-8 -*-
class Foo(object):
    def __getitem__(self, key):
        print '__getitem__',key
    def __setitem__(self, key, value):
        print '__setitem__',key,value
    def __delitem__(self, key):
        print '__delitem__',key
obj = Foo()
result = obj['k1']      # 自动触发执行 __getitem__
obj['k2'] = 'wupeiqi'   # 自动触发执行 __setitem__
del obj['k1']           # 自动触发执行 __delitem__
  • _getslice_、_setslice_、_delslice_ 该三个方法用于分片操作,如列表:
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    class Foo(object):
      def __getslice__(self, i, j):
          print '__getslice__',i,j
      def __setslice__(self, i, j, sequence):
          print '__setslice__',i,j
      def __delslice__(self, i, j):
          print '__delslice__',i,j
    obj = Foo()
    obj[-1:1]                   # 自动触发执行 __getslice__
    obj[0:1] = [11,22,33,44]    # 自动触发执行 __setslice__
    del obj[0:2]                # 自动触发执行 __delslice__
    
  • _iter_ 用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 _iter_

eg:

class foo(object):
    def __init__(self,name):
        self.name=name
    def __call__(self):
        print("this is call function")
    def __del__(self):
        print("this is del function")
    def __str__(self):
        return "amm"

In [22]: A=foo("kaiz")
In [24]: A.__dict__
Out[24]: {'name': 'kaiz'}
In [25]: A='asdf'
this is del function

装饰器

对函数进行封装,直接上代码

import time
def timeit(f):
    def timer(*arg):
        start = time.time()
        result = f(*arg)
        end = time.time()
        print("Function runtime is %s" % (end-start))
        return result  #记住此处处最好有个返回值
    return timer


@timeit
def factorial_two(n):
    if n == 1:
        return 1
    elif n > 1:
        return n * factorial_two(n-1)
    else:
        return 0

print(factorial_two(4))

Function runtime is 0.0
Function runtime is 0.0
Function runtime is 0.0
Function runtime is 0.0
24