Python 类与对象

# coding:UTF-8

"""
***此实例是为了尽可能简单地介绍面向对象设计***
1. 类是什么
类是一个或多个(有着共同的目标)的方法(类中的函数叫方法)所组成的对象。
可以把类看成是一个公司,方法就是其中一个个的部门。
[NOTICE]这里的公司是一个泛指和统称,或者可以看做一个抽象,本身并不能做任何事情
        但是可以创办一个公司(实例化),创办公司时需要注入资金人力物力等(传参数),规定好做事的步骤(语句)。
        当一切准备妥当,按照创办公司标准(类)成立了公司(实例),那么这个公司的每个部门
        就可以运作了,不同的部门(方法)做的事情不同,但又相互关联,都是为了公司(类)共同的目标。
2. 为什么要用类?
类的体现了面向对象的三个特性:继承、封装和多态。所以这个问题就是为什么要用面向对象方式,
也就是继承、封装和多态的优势,比如复用性、解耦性、可读性(语义)等等,关于这一点限于水平我说不了那么多,
大家可以去查这方面的资料,但是最重要的是,在编程的过程中去理解。
还是通过上面公司的例子来说明:
* A公司继承自B公司,那么A就是B的子公司(子类),B是A的父公司(父类,实际中习惯叫母公司)。比如母公司有财务部(X方法).
* 但是子公司可能财务并不独立,没有财务部门(没有X方法),
所以财务方面的事情就由母公司(父类)的财务部门(X方法)来处理,也就是默认会继承母公司的财务部门。
* 子公司也可以对母公司的财务部门进行更改,如增加若干流程并加入自己的人员(继承并改写),或者干脆直接成立一个财务部门
(重写并覆盖)。
* 这种继承但是改变了原有类或方法的行为是多态的一种表现形式。
* [NOTICE]即使是多态的,在子类或子方法中尽量也要保持形式上的一致,比如父公司的财务部中要求加入钱和人力(参数),
你不能把子公司的财务部定义为接收一些文件书籍,并且财务部们的产出一定都是报表,不能是制造的产品。
也就是说功能职责要明确且一致。
* 封装就是将多个步骤动作(这多个步骤是完成某件独立的事情,其功能性完整,可复用性强),组合成一个独立的部门
(某函数或类等),当某个部门需要做这件事的时候,就去交给(调用)这个独立的部门去做,自己只需要知道或拿到结果。
封装的水平很大程度上决定了代码的可读性、复用性和扩展性,在面向对象设计时要考虑好封装的功能点。

3. 如何使用类?
下面的实例简单地介绍了类的一些使用方法。
"""


class Parent(object):

    def __init__(self):
        # 定义了一个类对象的变量(全局)
        self.foo = 'foo'

    def test(self, a, b=True, **kwargs):
        # **kwargs表示接收所有剩下的关键词参数(这里除了b=True以外)
        # 如果这个test方法传入了关键词参数x=10,那么不会报任何错误,会被接收,但并没有被使用
        print 'a is %s' % a
        print 'b is %s' % b

    @property
    # property装饰器将方法(的结果)变为了类的属性
    # 如可以使用Parent().bar接收到了bar函数的返回值
    def bar(self):
        return 'bar'


class C1(Parent):

    def __init__(self):
        # 仅使用super继承了父类的构造函数__init__
        # 继承到了父类__init__方法中所有的语句
        # 也就是继承到了self.foo这个变量
        # C1().foo便有了定义--字符串'foo'
        super(C1, self).__init__()

    def test(self, a, b=False, **kwargs):
        # 此函数固定接收两个参数,其中a为普通参数(顺序固定)
        # b为关键词参数,并给定了默认值False,在不传值的情况下使用默认值
        super(C1, self).test(a, b=b, **kwargs)
        # 在父类test执行之后继续执行一句print,并打印了由父类继承来的对象变量
        print self.foo


class C2(Parent):

    # C2子类没有__init__方法,那么就是完全继承父类,并没有任何改动,
    # 和C1的__init__效果完全一样

    def test(self, a, b=True, c=123):
        # 重写父类的方法test,在参数中a和b是必要的参数,但是可以修改关键词参数b的默认值
        # c为子方法中新定义的参数,默认值为123

        # assert是一个判断(断言),如果不符合条件,那么会抛出AssertionError异常
        # 作用是保证参数的合法性
        assert type(c) == int

        # 显而易见,继承前后都可以增加代码,对父类方法进行修改
        print 'before super'
        super(C2, self).test(a, b=True)
        print 'after super'


class C3(Parent):

    class C31(object):
        # C31类为C3的内部类,继承自object(所有类的父类)
        # 注意这里也有个变量self,这个self和它的外部类的self不冲突,分别代表它们自己的对象实例
        # 也就是说C31().foo和C3().C31().foo是不同的,并没什么联系
        def __init__(self):
            # 定义了C31自己对象的一个变量foo
            self.foo = 'C31 foo'

        def print_foo(self):
            # 同样是self.foo,C31这里的self指的是自己实例化后的对象
            # 也就和C3的self.foo完全不同了
            print self.foo

        @staticmethod
        # staticmethod装饰器将类的方法变为静态方法,此方法不能传入self参数
        # 因为静态方法在实例化前(只要类存在内存中时)就可以被调用,传入self肯定会出错
        def test_31():
            print('c31 test')

    def test(self, a, b=True, c=10, d=5):
        # 新增加了两个参数c和b,super中的参数只需要传入a和b(因为父类只需要这两个参数)
        super(C3, self).test(a, b)
        print('c3 test')
        print(c * d)

# 大家可以试着改变参数以及调用方法,理解类是如何运作的
if __name__ == '__main__':
    C1().test('c1')
    print C1().foo
    print '----'
    C2().test('c2')
    print '----'
    C3().test('c3', b=False, c=20)
    print '----'
    C3().C31().test_31()
    print '----'
    print C3().foo
    C3().C31().print_foo()

 

posted @ 2018-12-21 15:26  SilentKiller  阅读(258)  评论(0编辑  收藏  举报