8.1 面向对象
python将所有事物都看作是对象
面向对象的三大特性:封装、继承、多态。
类和对象:
类: 相同事物的组成。如汽车类、房子类。它具有属性和方法
类变量: 类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。
方法重写: 如果从父类继承的方法不能满足子类的需求,可以对其进行改写。
实例变量: 定义在类里面函数中的变量,只作用于当前实例的类。
继承: 原本的类叫基类,继承原本类的这个类叫派生类。
实例化: 创建一个类的实例,类的具体对象。
方法: 类中定义的函数。
对象: 具体的目标事物。如具体的某一辆车。它符合该类的属性和方法,是对象的实例
`类和对象的关系:
某类的某个对象调用某种方法实现目标任务 #例如:人类叫张三的说一句话
8.2 类和对象
定义类:
使用class关键字定义一个类,且类名的首字母要大写
主要目的: 所表达的信息复杂,无法用简单变量实现时,就需要用类表示
类把需要的变量和函数组合在一起。这种包含也称为“封装”
定义类的实现方式:
class 类名:
“类的帮助信息” #可以使用:“类名.__doc__”查看
成员变量
成员函数(至少有一个形参) #形参可以不需要传值。因为接收的是这个类本身
定义对象:
创建对象的过程称之为实例化。因为类是模糊的描述。
#以人类和张三为例
对象包含三方面特性:句柄、属性、方法
句柄用于区分不同对象 #对象名就是句柄
属性要和类中的成员变量对应 #类中的变量就是属性
方法要和类中的成员函数对应 #类中的函数就是方法
定义对象的实现方式:
对象名 = 类名() #实例化类
对象名.属性/方法名 #方法名必须是类中定义过的。可以是变量、函数等等
操作类属性:方法-指类中的函数,属性-指类中的变量
getattr(类名,属性名) #访问对象的属性。
hasattr(类名,属性名) #检查是否存在一个属性。
setattr(类名,属性名,值) #设置一个属性。如果属性不存在,会创建一个新属性。
delattr(类名,属性名) #删除属性。
对象销毁-垃圾回收:
使用计数来跟踪和回收。在python内部记录着对象的引用次数,当对象不再需要时(即引用次数为0),在某个恰当的时刻,解释器会回收占用的内存空间。
`语法:
__del__ : 析构函数。该函数在对象销毁时被调用。
代码实例:
#coding=utf-8
class test(object): #所有的class都是object的派生类
a = 1 #此处a是test类的属性
def func_1(self): #此处func_1是test类的方法(函数)
return self.arg1,self.arg2 #下方已转化为全局变量,此处虽不是同一函数下但可以调用
def __init__(self,arg1,arg2): #此处添加几个参数,实例化时就引入几个具体数
#构造函数。init函数主要是用来接收实例化时传入的初始值,之后再对其值进行处理,例如转化为全局值,使之可以被类内的其它函数所使用
self.arg1 = arg1 #通过self将其转化为class内部的全局变量
self.arg2 = arg2
def __del__(self): #析构函数。主要是起销毁作用
del self.arg1 #删除掉全局变量。一般不需要操作,python会将其自动销毁
del self.arg2
t = test(1,4) #先实例化类,之后才能将类中的函数及变量拿到外部去使用。注意实例化并传值,该值首先传给init函数
print t.a #在类外面使用内部变量。注意点号。输出:1
print t.func_1() #在类外面使用内部函数。输出:(1,4)
代码实例:
# -*- coding:utf-8 -*-
a=[1,2,3,4,5,6]
#定义类。object是所有类之母,如果该类没有继承任何父类,则object将作为默认的父类。
class ceshi(object):
def name(self,a=None):
#函数中至少有一个形参。注意self是默认参数,在类里面定义函数第一个参数必须是self。
#self代表了这个对象本身。即这个类。
#self在该类内部是可以被全局调用的。
return self.var1 #已被self声明为类内全局变量
def __init__(self,var1): #init接收实例化时传入的初始值
self.var1=var1 #将传入的初始值声明为类内全局变量
#类的实例化
s=ceshi(u"这是一个测试字符串")
print s.name(a) #调用ceshi类的内置函数。先实例化再传参
#对比外置函数的使用
def ceshi2(s):
return s
t=ceshi2(a)
print t
print ceshi2(a) #也可以直接输出
代码实例:
# -*- coding: UTF-8 -*-
class Lei: #定义类。注意类名首字母大写
u'所有员工的基类' #类的帮助文档
empCount = 0 #定义类内的变量
hs=123
def __init__(self, name, salary): #定义类内的初始__init__函数,用于接收传参
self.name = name #将函数参数转换为类内全局变量
self.salary = salary
Lei.empCount += 1
def displayCount(self):
print "Total Lei %d" % Lei.empCount
def displayLei(self):
print "Name : ", self.name, ", Salary: ", self.salary
emp1 = Lei("Zara", 2000) #创建 Lei 类的第一个对象。即实例化
emp2 = Lei("Manni", 5000) #创建 Lei 类的第二个对象。
emp1.displayCount() #间接调用类内函数displayCount
emp2.displayLei() #间接调用类内函数displayLei
print "Total Lei %d" % Lei.empCount #输出类中的变量
print Lei.__doc__ #查看类的帮助文档
print hasattr(Lei, 'hs') #如果存在 'hs' 属性返回 True。
print getattr(Lei, 'hs') #返回 'hs' 属性的值
print setattr(Lei, 'hs', 8) #添加属性 'hs' 值为 8
print delattr(Lei, 'hs') #删除属性 'hs'
8.3 内置类属性
内置类:注意是前后双下划线
__dict__ #查看该类的属性(变量),这些属性以字典形式输出。
__doc__ #主要用来查看类的帮助文档
__name__ #如果是对应模块就显示模块名字,如果是对应类就显示类的名字
__module__ #查看该类/函数是在哪个模块下定义的,然后返回该模块的名称。
__bases__ #查看该类的父类,这些父类以元组形式输出。
代码实例:
# -*- coding: UTF-8 -*-
class Yuangong: #无继承普通类
'所有员工的基类' #类的帮助文档
empCount = 0
def __init__(self, name, salary): #初始化函数__init__
pass
print "Yuangong.__doc__:", Yuangong.__doc__ #帮助文档
print "Yuangong.__name__:", Yuangong.__name__ #类名
print "Yuangong.__module__:", Yuangong.__module__ #模块名:__main__
print "Yuangong.__bases__:", Yuangong.__bases__ #父类。此处为空
print "Yuangong.__dict__:", Yuangong.__dict__ #类属性
------------------------------------------------------------------------------------
类属性返回结果:
Yuangong.__dict__: {'__module__': '__main__', 'empCount': 0, '__doc__': u'所有员工的基类', '__init__': <function __init__ at 0x0000000002DF2C18>}
8.4 继承
主要用来实现代码重用,继承了某个类就相当于又写了一遍该类的代码
语法:
class 类名(基类名): #父类类写在括号里,外面的类又叫派生类
特点:
1、在继承中基类的构造(即__init__函数)不会被自动调用,它需要在派生类中亲自调用。即:(__init__再写一遍)。
2、调用基类函数时,需要加上基类的类名前缀,且需要带上self参数变量。而调用自身函数时,不需要带上self参数
3、先在本类中查找调用的函数,找不到时再到基类中查找。
多重继承
class 类名(基类名1、基类名2、基类名3):
代码实例:
# -*- coding: UTF-8 -*-
class Parent: # 定义父类
_parentAttr = 1 #父类属性(变量)。受保护变量
def __init__(self): #如果直接执行父类,它将先行执行。此处它不执行,是因为我们只是调用了它,并没有直接执行它。
print u"调用父类构造函数"
def parentMethod(self):
print u'调用父类方法'
def _setAttr(self, attr): #注意是受保护方法。前缀单下划线
Parent._parentAttr = attr #调用类内全局(受保护)变量,并被传入新值
def getAttr(self):
print u"父类属性 :", Parent._parentAttr #输出传入的新值(受保护)
class Child(Parent): #定义子类,该子类继承父类
def __init__(self): #构造函数,先行执行(虽然在该函数中没有任何作用)。先行执行是因为我们直接执行的是这个类。而每个类中都应该定义自己的init函数,而不是去继承。
print u"调用子类构造方法"
def childMethod(self): #子类中的子函数
print u'调用子类方法'
c = Child() #实例化子类
c.childMethod() #调用子类的方法
c.parentMethod() #调用父类方法
c._setAttr(200) #子类再次调用父类的(受保护)方法并设置属性值。
c.getAttr() #再次调用父类的方法,获取属性值
8.5 方法重写
当父类的函数不能满足要求时,可以在子类中重写父类方法。
注意!重写后的方法只适用于该子类。其它类调用父类时还是使用父类中的方法。
代码实例:
# -*- coding: UTF-8 -*-
class Parent: #定义父类
def myMethod(self): #定义父类中的方法
print u'调用父类方法'
class Child(Parent): #定义子类,该子类继承父类
def myMethod(self): #定义子类中的方法。和父类方法相同,但父类方法不能满足子类需求,因此此处重写父类方法
print u'调用子类方法'
c = Child() #子类实例化
c.myMethod() #调用子类重写后的方法
8.6 私有化
前双下划线说明:
类的私有属性(变量)
#私有属性不能被外部函数访问,也不能被继承
__变量名 #前面以两个下划线开头即可
self.__变量名 #调用私有变量
类的私有方法(函数) #私有方法不能被外部访问,也不能被继承
__函数名 #前面以两个下划线开头即可
self.__函数名 #调用私有函数
注意:不允许实例化的类访问私有数据(外部访问)。即类外部实例化时不能对私有数据实例化。
前单下划线说明:
类的受保护属性/方法 #受保护属性可以被继承,但不能被外部访问(即父类和子类可访问)
_变量名 #注意是单下划线
_函数名 #调用受保护的数据。注意是单下划线
前后双下划线说明:
特例函数(方法)。如:__init__()
代码实例:
# -*- coding: UTF-8 -*-
class JustCounter:
__secretCount = 0 #私有变量。前缀双下划线
publicCount = 0 #公有变量
def count(self):
self.__secretCount += 1 #私有变量做运算
self.publicCount += 1 #公有变量做运算
print self.__secretCount #输出私有变量。成功
counter = JustCounter() #实例化
counter.count() #调用函数。输出0+1=1
counter.count() #再次调用函数。输出1+1=2
print counter.publicCount #调用输出公有变量。此时为2
print counter.__secretCount #调用输出私有变量。报错!外部不能访问私有变量
print counter._JustCounter__secretCount #外部可访问私有属性方法了。用法在此:实例化名._类名__私有变量名
#注意下划线数量