我们定义一种东西为一个类, 它有一些属性, 有些方法可以执行.
比如说, 可以把长方形定义成一个类,有两个属性. 可以定义一个方法,叫做area,返回面积.

类是一种类型, 是一种定义.
我们可以根据类定义一个对象, 或者叫实例 ,对象是一个真正的, 在内存中存在的东西.
比如说int是一种类型, 是整数类型. 5是它的一个对象.

定义

看一下定义类和实例化对象的语法.

#!/usr/bin/env python
# -*- coding: utf-8 -*-


class Person(object):

    """定义一个类:Person. 有名字, 年龄, 性别三个属性.
有个introduce方法, 用来介绍自己"""

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

    def introduce(self):
        print 'my name is %s, %s, %d years old' % (self.name, self.gender, self.age)

p = Person("liujia", 28, u"男")
print p  # <__main__.Person object at 0x1004a7210>
p.introduce()  # my name is liujia, 男, 28 years old

init del

__init__是一个特殊的方法, 起初始化的作用, 当定义一个对象的时候, 会调用到这个方法里, 可以在这里做一些初始化的工作.

__del__, 也是一个特殊的方法, 当销毁一个对象的时候, 会调用到这个方法里, 可以在这里做一些善后~

#!/usr/bin/env python
# -*- coding: utf-8 -*-


class Person(object):

    """定义一个类:Person. 有名字, 年龄, 性别三个属性.
有个introduce方法, 用来介绍自己"""

    def __init__(self, name, age, gender):
        print "now init a object"
        self.name = name
        self.age = age
        self.gender = gender

    def introduce(self):
        print 'my name is %s, %s, %d years old' % (self.name, self.gender, self.age)

    def __del__(self):
        print "now destroy a object"

p = Person("liujia", 28, u"男")
print p  # <__main__.Person object at 0x1004a7210>
p.introduce()  # my name is liujia, 男, 28 years old
del p

运行:

% python cls/initdel.py
now init a object
<__main__.Person object at 0x10049bf90>
my name is liujia, 男, 28 years old
now destroy a object

self

每个方法, 我们都传递了一个self做了第一个参数. 在调用到方法的时候, python会自动把对象本身做为第一个参数传进去.

这个形参可以叫任意名字, 但还是建议用self.

私有变量/方法

想象, 我们定义了一个类, 对外提供一个接口(方法), 这个接口里面代码很长, 我们把很长的代码根据功能封装成几小段, 每一小段放一个方法里, 这样代码看起来就简洁了很多.
这些一个一个小的方法, 其实只是一个个小螺丝钉, 不对外提供完备的功能.
我们就可以把这些小方法定义成私有方法, 一看代码就大概明白, 这些代码是不对外服务的.

属性和方法前面加一个_就代表它是私有的.

下面这个例子, 我们对外的接口叫public_api, 里面又调用了_func1, _func2. 将func1, func2定义成私有方法.

#!/usr/bin/env python
# -*- coding: utf-8 -*-


class Person(object):

    def _func1(self):
        print "func 1"

    def _func2(self):
        print "func 2"

    def public_api(self):
        self._func1()
        self._func2()
        print "done"

p = Person()
p.public_api()

# 私有方法仍然成功调用了...
# 私有方法只是个概念,并不像C++强制不能外部调用.
p._func1()

类属性 类方法

在前一个例子中, name age 等属性都是对象专属的, 不同对象有不同的自己的属性值.

但有时候, 我们需要有个类的属性

举一个不太好的例子, 我们希望有个地方能记录一共创建了多少对象了, 显然这个值不应该属于任意一个特定的对象.

我们可以定义一个全局变量来存储, 也可以用一个类属性来做这件事.

#!/usr/bin/env python
# -*- coding: utf-8 -*-


class Person(object):

    """定义一个类:Person. 有名字, 年龄, 性别三个属性.
有个introduce方法, 用来介绍自己"""

    count = 0  # 定义了一个类属性. 它不在任何方法中定义, 不是self.XXX.

    def __init__(self, name, age, gender):
        print "now init a Person."
        Person.count += 1  # 这样调用类属性
        print "There is %d persons" % Person.count
        self.name = name
        self.age = age
        self.gender = gender

    def introduce(self):
        print 'my name is %s, %s, %d years old' % (self.name, self.gender, self.age)

    def __del__(self):
        print "now destroy a object"
        Person.count -= 1  # 这样调用类属性
        print "There is %d persons" % Person.count

p = Person("liujia", 28, u"男")
p2 = Person("zn", 29, u"男")
p.introduce()  # my name is liujia, 男, 28 years old
p2.introduce()  # my name is liujia, 男, 28 years old
del p
del p2

print
print "now there is %d persons" % Person.count

运行结果:

% python cls/classAttrMethod.py                                                 ✭
now init a Person.
There is 1 persons
now init a Person.
There is 2 persons
my name is liujia, 男, 28 years old
my name is zn, 男, 29 years old
now destroy a object
There is 1 persons
now destroy a object
There is 0 persons

now there is 0 persons

类方法的定义与调用, 代码片断:

    @classmethod
    def howmany_persons(cls):
        return cls.count

...

print "now there is %d persons" % Person.howmany_persons()

承继

前面我们已经定义了Person类.
接下来我们在Person的基础上定义Teacher类. 除了有name age gender属性外, 还有salary属性.

几个注意点:

  1. 语法 class Teacher(Person), Teacher继承自Person
  2. __init__中, super(Teacher, self).__init__(name, age, gender). 需要显式的调用父类方法.
  3. tell_carrer方法, 这个在父类中占位而不实现, 并且通过抛出异常的方式禁止直接调用.
#!/usr/bin/env python
# -*- coding: utf-8 -*-


class Person(object):

    """定义一个类:Person. 有名字, 年龄, 性别三个属性.
有个introduce方法, 用来介绍自己"""

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

    def introduce(self):
        print 'my name is %s, %s, %d years old' % (self.name, self.gender, self.age)

    def tell_carrer(self):
        """先占位一个方法, 意在说明子类中会实现这个方法.
        但不允许从Person实例中调用"""
        raise NotImplemented


class Teacher(Person):

    def __init__(self, name, age, gender, salary):
        super(Teacher, self).__init__(name, age, gender)
        self.salary = salary

    def introduce(self):
        super(Teacher, self).introduce()
        print "and my salary is %d" % self.salary

    def tell_carrer(self):
        print 'i am a teacher'

t = Teacher("Teacher1", 28, u"男", 10000)
print t
t.introduce()

# Teacher是Person的子类
print  issubclass(Teacher, Person)
print  issubclass(type(t), Person)

p = Person("liujia", 28, u"男")
# 下面的调用会招聘异常
p.tell_carrer()

多重继承

#!/usr/bin/env python
# -*- coding: utf-8 -*-


class A(object):

    def __init__(self):
        print "init in A"
        self.a = 2

    def f1(self):
        print "f1 defined in A"

    def f2(self):
        print "f2 defined in A"


class B(A):

    def f1(self):
        print "f1 defined in B"


class C(object):

    def __init__(self):
        print "init in C"
        self.a = 2
        self.b = 3

    def f2(self):
        print "f2 defined in C"


class D(B, C):

    def f1(self):
        print "f1 defined in D"

d = D()
# 自己定义的直接调用,而且不会调用到父类方法
d.f1()

# 自己没有定义的, 深度递归向上寻找
d.f2()
print d.a

# 没有调用到C.__init__, 所居有d没有b这个属性, 会抛异常
print d.b

运行结果:

% python cls/deepsearch.py
init in A
f1 defined in D
f2 defined in A
2
Traceback (most recent call last):
  File "deepsearch.py", line 47, in <module>
    print d.b
AttributeError: 'D' object has no attribute 'b'