前面我们介绍了各种变量,数据结构,函数,今天我们来学习自己建立对象,在python 函数也好列表也好都能看作是对象,我们今天就来学习创建对象,创建类。
面向对象的对象可以看成是数据方法的集合,比方说汽车就是一个对象,所有的汽车都有共有的特征,有车轮,有车厢,有车灯。卡车属于汽车,也有轮子,车厢车灯,但是卡车还有货斗等等。汽车是一个对象,卡车也是。也就是说对象是一一个类别一个抽象,他是一类数据、函数、方法的集合,能够代表某些数据特性的数据。
举个类的例子:
如果我们去购物会要求打印出价格与品名
sucai = {'name':'doujiao','price':8}
baihuo = {'name':'shoes','price':100}
打印品名和价格:
>>> def printjg(chaoshi):
... print('%s:%s'%(chaoshi['name'],chaoshi['price']))
...
>>> printjg(sucai)
doujiao:8
如果我们用面向对象的方法来实现这个问题
>>> class Chaoshi(object):
... def __init__(self,name,price):
... self.name = name
... self.price = price
... def print_price(self):
... print('%s:%s' %(self.name,self.price))
...
>>> shucai = Chaoshi('doujiao',8)
>>> baihuo = Chaoshi('shoes',80)
>>> shucai.print_price()
doujiao:8
>>> baihuo.print_price()
shoes:80
这样的写法是不是比函数要方便得多,并且自身也成为一个对象。
我们归纳一下要定义一个类先用关键字class+类名称组成类名第一个字符通常大写,比方说我们上文建立的类Chaoshi
类的实例就是baihuo shucai这样的承载了类的特征单数其中数据不同。
由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name,price等属性绑上去,__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去.
和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
数据封装
面向对象的特点就是数据封装,我们在前面的例子中可以发现每个实例都有自己的数据baihuo = Chaoshi('shoes',80)但是,既然Chaoshi实例本身就拥有这些数据,要访问这些数据,就没有必要从外面的函数去访问,可以直接在Chaoshi类的内部定义访问数据的函数,这样,就把“数据”给封装起来了。这些封装数据的函数是和Chaoshi类本身是关联起来的,我们称之为类的方法。
要定义一个方法我们除了和普通幻术一样定义外def print_price(self):必有一个参数self.使用起来也很简单只需要在实例化对象后面加上.方法名即可
在类的使用当中隐去了很多计算环节我们不必要关心只要直接使用即可,但是我们还可以随意更改类内部的类型
>>> shucai.name = 90
>>> shucai.print_price()
90:8
外部代码可以很轻松的更改类里面的参数属性,如果不想让外部程序代码来影响类可以设置私有属性,私有属性定义只要在相应的变量前面加上_下划线即可。
>>> class Chaoshi(object):
... def __init__(self,name,price):
... self.__name = name
... self.__price = price
... def printlf(self):
... print('%s,%s'%(self.__name,self,__price))
使用起来没什么不一样
>>> shucai = Chaoshi('tudou',90)
>>> shucai._name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Chaoshi' object has no attribute '_name'
如果直接访问就会出错,意思是类写错误
当然也可以通过函数
def get_name(self):
来实现内部变量访问
需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。
有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量。
继承与多态
当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
举例:
>>> class Zhongguo(object):
... def printadd(self):
... print('Zhongguo')
我们再写一个jiangxi的类继承zhongguo
class Jiangxi(Zhongguo):
... pass
>>> tom = Jiangxi()
将Jiangxi实例化为tom
>>> tom.printadd()
Zhongguo
即使Jiangxi这个类没有定义任何方法任然可以调出基类的方法,说明自雷继承了积累的方法和变量
当然自类可以继续增加方法或者变量
>>> class Guangdong(Zhongguo):
... def printadd(self):
... print('guangdong')
可以继续添加方法