类(class)
我们定义一种东西为一个类, 它有一些属性, 有些方法可以执行.
比如说, 可以把长方形定义成一个类,有长和宽两个属性. 可以定义一个方法,叫做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属性.
几个注意点:
- 语法 class Teacher(Person), Teacher继承自Person
- __init__中, super(Teacher, self).__init__(name, age, gender). 需要显式的调用父类方法.
- 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'