Python中所有的数据都是对象,它提供了许多高级的内建数据类型,功能强大,使用方便,是Python的优点之一。那么什么时候使用自定义类呢?比如设计一个Person类,如果不使用自定义类,可以这样做:
person=['mike', 23, 'male'] #0-姓名, 1-年纪, 2-性别
print(person[0], person[1], person[2])
可以看到,使用内建类型list,需要用下标来引用成员数据,不直观。可以改用dic类型来做:
person1={'name':'mike', 'age': 23, 'sex':'male'}
person2={'name':'hellen', 'age': 20, 'sex':'female'}
print(person1['name'], person1['age'],person1['sex'])
这样不用记忆下标,直观多了。但是字典的语法仍然有些麻烦,如果能够像这样引用:person.name,person.age等,就更好。这就是自定义类存在的好处了:
class Person:
def __init__(self, name, age,sex):
self.name =name
self.age = age
self.sex = sex
def __str__(self): #重载该函数便于测试
sep = ','
returnself.name+sep+str(self.age)+sep+self.sex
person1 = Person('mike', 23, 'male')
person2 = Person('hellen', 20, 'female')
print(person1)
print(person2.name, person2.age,person2.sex)
可以看到,只要定义好这个类的构造函数,就可以很方便的生成这个类的实例,并且引用数据成员也很方便,比直接使用内建类型方便多了。其实Python就是用内建类型dic来实现自定义类的成员的存储和引用的,从这个角度来看,自定义类是内建类的简化使用方式,内建类型是自定义类型内部必要的组成部分。同时,由于自定义类可以定义自己的成员函数或者重载预定义的方法,所以自定义类扩展了内建类的功能,可以提供对现实事物更好的模拟,这正是面向对象编程的优点。编程的时候,先对所要模拟的事物形成概念,然后尽量使用类来抓住概念,这是面向对象设计的关键。如果需要产生多个同类的对象,应该尽可能地设计一个自定义类去抽象它们。
对自定义类的使用也别过分,有些功能只需要定义一个函数就可以做到了,这个时候就没有必要设计一个自定义类。
相关概念:
自己先创建一个类,根据类创建一个子类。这个子类有点不同。如下面范例mycat是父类,而tcat是子类。
Mycat是个对象,而tt是mycat的实例。
Mycat中leg和head是静态的属性,而def定义的方法就是从静态的属性中动态得到另外的数据。比如mycat中的weight就是从head中得到的。而hh是从子类中实例化的。Hh的weight就跟mycat不同。
class mycat(object):
leg='short'
head='big'
def __init__(self):
self.weight=len(self.head)
class tcat(mycat):
head = 'smell'
tt=mycat()
print tt.leg
print tt.weight
hh=tcat()
print hh.head
print hh.leg
print hh.weight
子类super()调用父类方法,并做出自己独特更改
super()是一个特殊函数, 帮助Python将父类和子类关联起来。 这行代码让Python调用ElectricCar 的父类的方法__init__() , 让ElectricCar 实例包含父类的所有属性。 父类也称为超类 ( superclass) ,名称super因此而得名。
class Person():
def __init__(self, name):
self.name = name
class email(Person):
def __init__(self, name, email):
super().__init__(name)
self.email = email
a = email('me', '[email protected]')
>>> a.name
... 'me'
>>> a.email
... '[email protected]'
#在Python 2.7中, 继承语法稍有不同, ElectricCar 类的定义类似于下面这样:
class Car(object):
def __init__(self, make, model, year):
--snip--
class ElectricCar(Car):
def __init__(self, make, model, year):
super(ElectricCar, self).__init__(make, model, year)
--snip
实例方法就是类的实例能够使用的方法;
静态方法是一种普通函数,就位于类定义的命名空间中,它不会对任何实例类型进行操作。使用装饰器@staticmethod定义静态方法。类对象和实例都可以调用静态方法。
类对象(python中定义的类本身也是对象)
类方法是将类本身作为对象进行操作的方法。类方法使用@classmethod装饰器定义,其第一个参数是类,约定写为cls。类对象和实例都可以调用类方法。
class Foo(object):
val1 = 'aa' #类变量
def __init__(self):
self.val2 = 'bb' #实例变量
val3= 'cc' #顺便设置的变量不知道属于什么变量
print self.__class__.val1 #实例对象访问类变量的另一种方法
if __name__ == '__main__':
foo = Foo()
print foo.val1 #实例变量输出为1
print '#'*80
print foo.val2
print '#'*80
print Foo.val1
print '#'*80
print Foo.val2 #输出出错
print Foo.val3 #输出出错
类变量定义在类的定义之后,实例变量则是以为self.开头。例如:
从上述的例子可以得到实例对象可以访问类变量和实例变量
但是类对象却只能访问类变量,在实例方法中的变量都不能访问。
而我随便设置的变量则是实例和类对象都不能访问。
备注:self是当前,类的实例的变量,self.__class__用于获得对应的类的本身的变量。
静态方法:声明和调用时,都没有隐含参数。
实例方法:声明时,要定义一个隐含参数:self。调用时,实例本身被隐含地传递给这个参数。(这样是否可以说明实例方法中的不同变量可以互相调用?)不可以必须通过函数传递。
类方法:声明时,要定义一个隐含参数:cls。调用时,类本身的变量被隐含地传递给这个参数。
总结以下几点:
一、类对象能使用本身的类变量和调用类方法和静态方法;但是特殊的是类可以调用类中的普通函数,而实例不能调用。
二、实例对象的等级较高,能使用类变量,实例变量,而且能调用实例方法,类方法和静态方法。不能调用类中的普通函数。只能用静态方法来声明普通函数实例才能调用。
三、普通函数无法访问实例变量和类变量。
还有几点总结如下:
实例方法:
特点是有个self作为第一个参数;
这样用__init__调用的时候的参数就会传入实例方法;
print (self.fname)
但是类不能调用实例变量,也不能使用实例方法。只有当类实例化成为实例对象才能使用以上的变量和方法
一个实例方法不能调用另一个实例方法;
###########################
实例可以使用类变量但是也可以使用实例变量;
实例可以使用实例方法和类方法
实例中可以使用特殊方法使用类变量self.__class__.middlename
类方法:
特点是有个关键词@classmethod;方法有个关键字func(cls)
不能使用实例变量和实例方法;
print (cls.middlename)
类对象和实例都可以调用这个方法;
######################################
类对象可以使用类变量但不可以使用实例变量
类对象可以调用类方法但是不能调用实例方法
类对象不可以调用实例方法
静态方法:
用特殊关键字@staticmethod可以声明;
类对象和实例都可以调用这个方法;
静态方法不能访问实例变量和类变量
为什么要使用静态方法和类方法呢?或者说这两种东西设计出来是做什么用的呢?
类中最常用的方法是实例方法, 即通过通过实例作为第一个参数的方法。
如果现在我们想写一些仅仅与类交互而不是和实例交互的方法会怎么样呢? 我们可以在类外面写一个简单的方法来做这些,但是这样做就扩散了类代码的关系到类定义的外面. 于是我们@classmethod装饰器来创建类方法,让它在类中运行而不在实例中运行。
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
@classmethod
def get_no_of_instance(cls_obj):
return cls_obj.no_inst
ik1 = Kls()
ik2 = Kls()
print ik1.get_no_of_instance()
print Kls.get_no_of_instance()
经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法. 比如更改环境变量或者修改其他类的属性等能用到静态方法.
IND = 'ON'
class Kls(object):
def __init__(self, data):
self.data = data
@staticmethod
def checkind():
return (IND == 'ON')
def do_reset(self):
if self.checkind():
print('Reset done for:', self.data)
def set_db(self):
if self.checkind():
self.db = 'New db connection'
print('DB connection made for: ', self.data)
ik1 = Kls(12)
ik1.do_reset()
ik1.set_db()
下面我们来看一个既使用了静态方法也用了类方法的例子:
class Kls(object):
def __init__(self, data):
self.data = data
def printd(self):
print(self.data)
@staticmethod
def smethod(*arg):
print('Static:', arg)
@classmethod
def cmethod(*arg):
print('Class:', arg)
>>> ik = Kls(23)
>>> ik.printd()
23
>>> ik.smethod()
Static: ()
>>> ik.cmethod()
Class: (,)
>>> Kls.printd()
TypeError: unbound method printd() must be called with Kls instance as first argument (got nothing instead)
>>> Kls.smethod()
Static: ()
>>> Kls.cmethod()
Class: (,)
下面在再给出一个国外论坛的例子。classmothod和staticmethod是很相似的,不同的地方在于类方法可必须以cls作为第一个参数,而静态方法可以不需要任何参数:
class Date(object):
def __init__(self, day=0, month=0, year=0):
self.day = day
self.month = month
self.year = year
@classmethod
def from_string(cls, date_as_string):
day, month, year = map(int, date_as_string.split('-'))
date1 = cls(day, month, year)
return date1
@staticmethod
def is_date_valid(date_as_string):
day, month, year = map(int, date_as_string.split('-'))
return day <= 31 and month <= 12 and year <= 3999
date2 = Date.from_string('11-09-2012')
is_date = Date.is_date_valid('11-09-2012')
时间仓促。如有错漏希望能指正(留言或者电邮我)。本人邮箱[email protected]