Python 面向对象

什么是面向对象编程?

面向对象编程是一种程序设计范式

对现实世界建立对象模型

把程序看作不同对象的相互调用

 

Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。下面我们将详细介绍Python的面向对象编程。

如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。

接下来我们先来简单的了解下面向对象的一些基本特征。

面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
    定义类并创建实例
    
    在Python中,类通过 class 关键字定义。以 Person 为例,定义一个Person类如下:
    
    class Person():
        pass
    
    按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。类的继承将在后面的章节讲解,现在我们只需要简单地从object类继承。
    
    有了Person类的定义,就可以创建出具体的xiaoming、xiaohong等实例。创建实例使用 类名+(),类似函数调用的形式创建:
    
    xiaoming = Person()
    xiaohong = Person()
    

     注:python 2 创建类与python 3 不同

py 2.2 后继承 object 的目的是使这个类成为 new style class, 
没有继承 object 的为传统 classic class,
在py 2.7.11进行了测试 

>>> class A(object):
...     pass
... 
>>> print(type(A))
<type 'type'>
>>> class B():
...  pass
... 
>>> print(type(B))
<type 'classobj'>
# 可见2个type是不同的

>>> print dir(A)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> print dir(B)
['__doc__', '__module__']
# 属性也是不一样的

而py 3.5.2:
class A(object):
    pass
print(type(A))
print(dir(A))

class B():
    pass
print(type(B))
print(dir(B))

<class 'type'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
<class 'type'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']


说明 py 3.5   object 已经作为默认基类被继承了(跟 java 一样). 
  • 字段字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同普通字段属于对象,静态字段属于.
    class Province:
        # 静态字段
        country = '中国'
        def __init__(self, name):
            # 普通字段
            self.name = name
    # 直接访问普通字段
    obj = Province('河北省')
    print(obj.name)
    # 直接访问静态字段
    print(Province.country)
    

     静态字段在内存中只保存一份,普通字段在每个对象中都要保存一份

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

                   普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
          类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
          静态方法:由类调用;无默认参数;

#!/usr/bin/env python
# Version = 3.5.2
# __auth__ = '无名小妖'

class Foo:

    def __init__(self, name):
        self.name = name

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

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

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

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

# 调用类方法
Foo.class_func()

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

 尽量不要用对象执行静态方法和类方法。

 

   属性:Python中的属性其实是普通方法的变种。  

 

class Foo:
    def func(self):
        pass
    # 定义属性
    @property
    def prop(self):
        print('xxx')
# ############### 调用 ###############
foo_obj = Foo()

foo_obj.func()
foo_obj.prop   #调用属性

由属性的定义和调用要注意一下几点:

    • 定义时,在普通方法的基础上添加 @property 装饰器;
    • 定义时,属性仅有一个self参数
    • 调用时,无需括号
                 方法:foo_obj.func()
                 属性:foo_obj.prop

注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象

属性的定义有两种方式:

  • 装饰器 即:在方法上应用装饰器
  • 静态字段 即:在类中定义值为property对象的静态字段

装饰器方式:在类的普通方法上应用@property装饰器

 

#!/usr/bin/env python
# Version = 3.5.2
# __auth__ = '无名小妖'

class Pager():

    def __init__(self,all_count):
        self.all_count = all_count
    @property
    def all_pager(self):
        a1,a2 = divmod(self.all_count,10)
        if a2 == 0:
            x = a1
        else:
            x = a1 + 1
        return x

    @all_pager.setter
    def all_pager(self,value):
        self.all_count = value * 10

    @all_pager.deleter
    def all_pager(self):
        print('deleter')

p = Pager(101)
print(p.all_pager)
p.all_pager = 123
print(p.all_pager)
del p.all_pager

 

 输出结果:

 

11
123
deleter

 静态字段方式,创建值为property对象的静态字段

  • 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
  • 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
  • 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
class Foo:

    def get_bar(self):
        return 'xiaoyao1'

    # *必须两个参数
    def set_bar(self, value):
        print('set value is ' + value)

    def del_bar(self):
        print('xiaoyao2')

    BAR = property(fget=get_bar, fset=set_bar, fdel=del_bar)

obj = Foo()

obj.BAR              # 自动调用第一个参数中定义的方法:get_bar
x = obj.BAR
print(x)
obj.BAR = "alex"     # 自动调用第二个参数中定义的方法:set_bar方法,并将“alex”当作参数传入
del obj.BAR          # 自动调用第三个参数中定义的方法:del_bar方法


xiaoyao1
set value is alex
xiaoyao2

 

Python 三大特性:

封装

封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

__init__ 是封装必不可少的,看列子:

class Init():

    def __init__(self,name,age,gender):
        self.Name = name
        self.Age = age
        self.Gender = gender

obj1 = Init('xiao',15,'男')
obj2 = Init('yao',16,'女')

print(obj1.Name)
print(obj2.Name)

 这样实现了数据封装

xiao
yao

 继承

继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

通过继承创建的新类称为“子类”或“派生类”。

被继承的类称为“基类”、“父类”或“超类”。

继承的过程,就是从一般到特殊的过程。

要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。

在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

class C1():
    def c1(self):
        print('C1')
class C2(C1):
    def c2(self):
        print('C2')
class C3():
    def c3(self):
        print('C3')
    def c1(self):
        print('C3')
class C4(C2,C3):
    def c4(self):
        print('C4')
obj = C4()
obj.c1()
obj1 = C3()
obj1.c1()

 输出结果:

C1
C3

 可见,C4继承C2,C3,C2又继承C1,所以obj会有c1方法。

  类的继承可以总结为:

  1.左侧优先

class C4(C2,C3)  这里C2比C3优先

  2.深度优先

   上面例子C1和C3都有c1方法,但是最后C4继承的是C1的c1

  3.有共同的父类,最后找父类

 

看图红色箭头表示继承关系,黑色箭头表示查找关系

图一:                                                                                                       图二:

       

3.多态

多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代 码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调 用。
 
Pyhon不支持多态并且也用不到多态,多态的概念是应用于Java和C#这一类强类型语言中