在Python中,可以通过class关键字定义自己的类,然后通过自定义的类对象类创建实例对象。如下,创建一个people类,并定义了一个初始化__init__函数。
class people(object):
‘‘‘This is a people class‘‘‘
address=[]
code=‘0590‘
def __init__(self,name,age):
self.name=name
self.age=age
属性
借助这个例子我们来看看Python中类的相关内容。
在上面的people类中,”address””code””name”和”age”都被称为类的数据属性,但是它们又分为类数据属性和实例数据属性。我们通过一个例子来演示,如下:
people.address.extend([‘China‘,‘Fujian‘,‘Fuzhou‘])
print ‘Address is %s‘ %people.address
people.food=[‘foutiaoqiao‘,‘yuwan‘,‘rouyan‘]
print ‘Food is %s‘ %people.food
print dir(people)
John=people(‘John‘,29)
print ‘%s is %s year old‘ %(John.name,John.age)
John.gender=‘Man‘
print ‘%s is %s‘ %(John.name,John.gender)
print dir(John)
John.address.append(‘hudonglu‘)
print John.address
Wiki=people(‘Wiki‘,22)
print dir(Wiki)
print Wiki.address
运行结果:
Address is [‘China‘, ‘Fujian‘, ‘Fuzhou‘]
Food is [‘foutiaoqiao‘, ‘yuwan‘, ‘rouyan‘]
[‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__hash__‘, ‘__init__‘, ‘__module__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘address‘, ‘code‘, ‘food‘]
John is 29 year old
John is Man
[‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__hash__‘, ‘__init__‘, ‘__module__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘address‘, ‘age‘, ‘code‘, ‘food‘, ‘gender‘, ‘name‘]
[‘China‘, ‘Fujian‘, ‘Fuzhou‘, ‘hudonglu‘]
[‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__hash__‘, ‘__init__‘, ‘__module__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘address‘, ‘age‘, ‘code‘, ‘food‘, ‘name‘]
[‘China‘, ‘Fujian‘, ‘Fuzhou‘, ‘hudonglu‘]
注:通过内建函数dir(),或者访问类的字典属性__dict__可以查看类有哪些属性。如上例子dir(people)
通过如上例子我们可以归纳几点有关类的特性:
(1)类数据属性属于类本身,可以通过类名进行访问或修改;如people.address
(2)类数据属性也可以被类的所有实例访问或修改;如Wiki.address=‘hudonglu‘
(3)在类定义之后,可以通过类名动态添加类数据属性,新增的类属性也被类和所有实例共有;如
people.address.extend([‘China‘,‘Fujian‘,‘Fuzhou‘])
(4)实例数据属性只能通过实例访问;如John.gender
(5)在实例生成后,还可以动态添加实例数据属性,但是这些实例数据属性只属于该实例;如John.gender
对于所有的类,都有一组特殊的属性:
__name__ | 类的名字(字符串) |
__doc__ | 类的文档字符串 |
__bases__ | 类的所有父类组成的元组 |
__dict__ | 类的属性组成的字典 |
__module__ | 类所属的模块 |
__class__ | 类对象的类型 |
通过这些属性,可以得到 people类的一些信息
print people.__name__
print people.__doc__
print people.__bases__
print people.__dict__
print people.__module__
运行结果:
people
This is a people class
(<type ‘object‘>,)
{‘__module__‘: ‘__main__‘, ‘code‘: ‘0590‘, ‘food‘: [‘foutiaoqiao‘, ‘yuwan‘, ‘rouyan‘], ‘address‘: [‘China‘, ‘Fujian‘, ‘Fuzhou‘, ‘hudonglu‘], ‘__dict__‘: <attribute ‘__dict__‘ of ‘people‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘people‘ objects>, ‘__doc__‘: ‘This is a people class‘, ‘__init__‘: <function __init__ at 0x0000000005A27B38>}
__main__
<type ‘type‘>
从上面的介绍了解到,类数据属性属于类本身,被所有该类的实例共享;并且,通过实例可以去访问或修改类属性。但是,在通过实例中访问类属性的时候一定要谨慎,因为可能出现属性”隐藏”的情况。那什么情况下有隐藏呢,下面举例说明:
print people.code
print people.__dict__
John.code=‘0722‘
print John.code
print John.__dict__
del John.code
运行结果:
0590
{‘__module__‘: ‘__main__‘, ‘code‘: ‘0590‘, ‘food‘: [‘foutiaoqiao‘, ‘yuwan‘, ‘rouyan‘], ‘address‘: [‘China‘, ‘Fujian‘, ‘Fuzhou‘, ‘hudonglu‘], ‘__dict__‘: <attribute ‘__dict__‘ of ‘people‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘people‘ objects>, ‘__doc__‘: ‘This is a people class‘, ‘__init__‘: <function __init__ at 0x0000000005A27B38>}
0722
{‘gender‘: ‘Man‘, ‘age‘: 29, ‘code‘: ‘0722‘, ‘name‘: ‘John‘}
0590
从上述例子中分析得出如下结论:
(1)对于类属性people.code,可以通过实例John进行访问,切John.code等同于people.code;
(2)当通过实例赋值code属性的时候,都将为实例John新建一个code实例属性,这时John.code不等同于people.code;
(3)当通过”del John.code”语句删除实例的code属性后,John.code又等同于people.code;
(4)当通过实例修改code属性的时候,将修改John.code指向的内存地址(即people.code),此时John.code又等同于people.code;
注意,虽然通过实例可以访问类属性,但是,不建议这么做,最好还是通过类名来访问类属性,从而避免属性隐藏带来的不必要麻烦。
方法
在一个类中,可能出现三种方法,实例方法、静态方法和类方法,下面来看看三种方法的不同。
实例方法的第一个参数必须是“self”,实例方法只能通过类实例进行调用,这时候“self”就代表这个类实例本身。通过“self”可以直接访问实例的属性。如下例子:
class people(object):
‘‘‘This is a people class‘‘‘
address=[]
code=‘0590‘
def __init__(self,name,age):
self.name=name
self.age=age
def info(self):
print ‘%s is %s‘ %(self.name,self.age)
John=people(‘John‘,29)
John.info()
运行结果:
John is 29
类方法以cls作为第一个参数,cls表示类本身,定义时使用@classmethod装饰器。通过cls可以访问类的相关属性。
class people(object):
‘‘‘This is a people class‘‘‘
address=[]
code=‘0590‘
def __init__(self,name,age):
self.name=name
self.age=age
@classmethod
def classinfo(cls):
print cls.__name__
print dir(cls)
people.classinfo()
John=people(‘John‘,29)
John.classinfo()
运行结果:
people
[‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__doc__‘, ‘__format__‘, ‘__getattribute__‘, ‘__hash__‘, ‘__init__‘, ‘__module__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘address‘, ‘classinfo‘, ‘code‘, ‘food‘, ‘info‘]
静态方法没有参数限制,既不需要实例参数,也不需要类参数,定义的时候使用@staticmethod装饰器。
class people(object):
‘‘‘This is a people class‘‘‘
address=[]
code=‘0590‘
def __init__(self,name,age):
self.name=name
self.age=age
@staticmethod
def static():
print people.code
print people.address
people.satic()
John=people(‘John‘,29)
John.static()
运行结果:
0590
[‘China‘, ‘Fujian‘, ‘Fuzhou‘, ‘hudonglu‘]
三种方法的主要区别在于参数,实例方法被绑定到一个实例,只能通过实例进行调用;但是对于静态方法和类方法,可以通过类名和实例两种方式进行调用。
在Python中,同时支持单继承与多继承,基础语法如下:
class SubClassName(ParentClass1 [, ParentClass2, ...]):
class_suite
实现继承之后,子类将继承父类的属性,也可以使用内建函数insubclass()来判断一个类是不是另一个类的子孙类。如下例子:
class parent():
‘‘‘This is a parent class‘‘‘
num=[]
def plus(self,a,b):
return a+b
class child(parent):
‘‘‘This is a child class‘‘‘
child.num.extend(xrange(5))
print child.num
print ‘10 + 20 = ‘,child().plus(10,20)
print issubclass(child,parent)
print issubclass(child,object)
print child.__bases__
print parent.__doc__
print child.__doc__
运行结果:
[0, 1, 2, 3, 4]
10 + 20 = 30
True
False
(<class __main__.parent at 0x0000000004E59828>,)
This is a parent class
This is a child class
注:注意例子中的文档字符串。文档字符串对于类,函数/方法,以及模块来说是唯一的,也就是说__doc__属性是不能从父类中继承来的。
当在Python中出现继承的情况时,一定要注意初始化函数__init__的行为。有以下几点需要注意:
(1)如果子类没有定义自己的初始化函数,父类的初始化函数会被默认调用;但是如果要实例化子类的对象,则只能传入父类的初始化函数对应的参数,否则会出错。如下例子:
class Parent(object):
def __init__(self, name):
self.name = name
print self.name
class Child(Parent):
‘‘‘This is a child class‘‘‘
c = Child(‘John Test‘)
print c
Child()
运行结果:
Traceback (most recent call last):
John Test
File "C:/Users/YangQing/PycharmProjects/Test/class.py", line 81, in <module>
Child()
TypeError: __init__() takes exactly 2 arguments (1 given)
(2)如果子类定义了自己的初始化函数,而没有显示调用父类的初始化函数,则父类的属性不会被初始化
class Parent(object):
def __init__(self, name):
self.name = name
print self.name
class Child(Parent):
‘‘‘This is a child class‘‘‘
def __init__(self):
print ‘This is a self test‘
c = Child()
print c.name
运行结果:
This is a self test
Traceback (most recent call last):
File "C:/Users/YangQing/PycharmProjects/Test/class.py", line 83, in <module>
print c.name
AttributeError: ‘Child‘ object has no attribute ‘name‘
(3)如果子类定义了自己的初始化函数,显示调用父类,子类和父类的属性都会被初始化
class Parent(object):
def __init__(self, name):
self.name = name
print self.name
class Child(Parent):
‘‘‘This is a child class‘‘‘
def __init__(self):
print ‘This is a self test‘
super(Child,self).__init__(‘Data from Child class‘)
c = Child()
运行结果:
This is a self test
Data from Child class
从上面的例子中我们通过super()函数调用了父类__init__方法,下面就介绍下super():
在子类中,一般会定义与父类相同的属性(数据属性,方法),从而来实现子类特有的行为。也就是说,子类会继承父类的所有的属性和方法,子类也可以覆盖父类同名的属性和方法。
class Parent(object):
name = "This is a parent class"
def data(self):
print "This is data from Parent"
class Child(Parent):
name = "This is a child class"
def data(self):
print "This is data from child"
c = Child()
c.data()
print Child.name
运行结果:
This is data from child
This is a child class
在上述例子中子类的属性”name”和”data”覆盖了父类的属性,所以子类有了自己的行为。但是,有时候可能需要在子类中访问父类的一些属性,这时候,可以通过父类名直接访问父类的属性,当调用父类的方法是,需要将”self”显示的传递进去的方式。
class Parent(object):
name = "This is a parent class"
def data(self):
print "This is data from Parent"
class Child(Parent):
name = "This is a child class"
def data(self):
print "This is data from child"
print Parent.name
Parent.data(self)
c = Child()
c.data()
运行结果:
This is data from child
This is a parent class
This is data from Parent
这种方式有一个不好的地方就是,需要经父类名硬编码到子类中,为了解决这个问题,可以使用Python中的super关键字:
class Parent(object):
name = "This is a parent class"
def data(self):
print "This is data from Parent"
class Child(Parent):
name = "This is a child class"
def data(self):
print "This is data from child"
print super(Child, self).name
super(Child, self).data()
c = Child()
c.data()
运行结果:
This is data from child
This is a parent class
This is data from Parent
对于”super(Child, self).data()”可以理解为,首先找到Child的父类Parent,然后调用父类的data方法,同时将Child的实例self传递给data方法。
本文出自 “DreamScape” 博客,请务必保留此出处http://dyqd2011.blog.51cto.com/3201444/1979215
原文地址:http://dyqd2011.blog.51cto.com/3201444/1979215