面向对象和面向过程
面向对象的三个主要特征:封装、继承、多态。
面向过程编程:函数式编程,C程序等
面向对象编程:C++,JAVA,Python等
类和对象
类和对象是面向对象中的两个很重要的概念。
类:是对事物的抽象,比如 人类、球类。类还有属性:比如人的眼耳口鼻。还有方法:吃穿住行。静态属性,动态方法。
对象:是对类的一个实例,比如足球、篮球
面向对象的主要思想:封装、继承、多态。这种思想方便解决较为复杂的项目,且维护起来较为容易。
python类的定义:
数字字母下划线组成的,不能以数字开头。定义变量是小写,两个单词则是下划线连接。函数的话则是第二个单词之后是大写字母开头。类的话是每个首字母大写。这样定义根据名称就可以知道是函数还是类。
类把需要的变量和函数组合成一起,这种包含成为”封装“。" class A(object): "
类的结构:
class类名:
成员变量 - 属性
成员函数 - 方法
通过对象访问属性:color是属性,所以后面没有括号
#@File :demo_lei.py class People(object): color = 'yellow' \这也是静态属性 ren = People() print ren print ren.color <__main__.People object at 0x02CC9FD0> \返回值带尖括号的,就是类 yellow \通过对象访问属性的返回值
定义动态方法:方法中至少有一个参数是self。调用方法时,需要加括号。
#@File :demo_lei.py class People(object): color = 'yellow' def think(self): print "I am a thinker" ren = People() ren.think() \方法的调用需要使用括号。 返回值 I am a thinker
实例化:把类赋值给变量,变量的类型就是一个对象。通过对象访问类里面的属性和方法。
类的属性:
首先:对象的创建
创建对象的过程称之为实例化;当一个对象被创建之后,包含三个方面的特性:对象句柄、属性和方法。句柄用于区分不同的对象。对象的属性和方法与类中的成员变量和成员函数对应。
类的属性:类的属性按使用范围分为公有属性和私有属性,类的属性范围取决于属性的名称。
公有属性:在类中和类外都能调用的属性。
私有属性:不能再类外及类意外的函数调用。定义方式:以“__”双下划线开始的成员变量就是私有属性。可以通过instance._classname__attribute方式访问。
内置属性:由系统在定义类到时候默认添加的,由前后双下划线构成,__dict__,__module__。
#@File :demo_lei.py class People(object): color = 'yellow' __age = 20 def think(self): print "I am a thinker" print self.__age ren = People() ren.think() print ren.__age I am a thinker Traceback (most recent call last): 20 File "C:/Users/xiaojingjing/PycharmProjects/untitled1/liziyan/demo_lei.py", line 18, in <module> print ren.__age AttributeError: 'People' object has no attribute '__age'
这里就是私有属性的创建及调用。
!!!测试过程中可以使用这种方法:私有属性就是为了保护仅在内部调用,所以在正常程序中不建议这么使用。
print ren._People__age 可以正常打印出返回值!
当类实例化之后,可以通过实例过后的对象 对类的属性进行修改
#@File :demo_lei.py class People(object): color = 'yellow' __age = 20 def think(self): print "I am a thinker" print self.__age ren = People() ren.think() print ren.__dict__ print People.__dict__ 返回值: I am a thinker 20 {} \这里与预期有出入,至少应该返回:{’color‘: ’yellow‘}的,问题没有找到。 {'__module__': '__main__', 'color': 'yellow', '__doc__': None, '__dict__': <attribute '__dict__' of 'People' objects>, '_People__age': 20, '__weakref__': <attribute '__weakref__' of 'People' objects>, 'think': <function think at 0x034278F0>}
类的方法:
方法的定义和函数一样,但是需要self作为第一个参数。与类的属性类似,类的方法有:公有方法、私有方法、类方法、静态方法。
共有方法:在类中和类外都能调用的方法。
私有方法:不能被类的外部调用,在方法前面加上”__“双下划线就是私有方法。
self参数:用于区分函数和类的方法(必须有一个self),self参数表示执行对象本身。
类方法 -- 动态方法:被classmethod()函数处理过的函数,能被类所调用,也能被对象所调用(是继承的关系)
通过类访问访问其中的方法,称为动态方法:通过类访问方法占用的资源是少的,因为除了调用需要的方法(self以及其他在该方法中定义的属性操作等)外,其他的方法是不会被加载的。
如果需要直接使用类名来调用方法而不借助实例对象,可以使用classmethod函数实现,方法如下: #@File :demo_lei.py class People(object): color = 'yellow' __age = 20 def test(self): print "Testing..." cm = classmethod(test) jack = People() People.cm() People.test() Testing... Traceback (most recent call last): File "C:/Users/xiaojingjing/PycharmProjects/untitled1/liziyan/demo_lei.py", line 24, in <module> People.test() TypeError: unbound method test() must be called with People instance as first argument (got nothing instead)
静态方法:相当于“全局变量“,可以被类直接调用,可以被所有实例化对象共享,通过staticmethod()定义,静态方法没有”self"参数
首先设置静态方法的方式是:定义的时候不需要使用self参数,但是需要staticmethod函数处理。
#@File :demo_lei.py class People(object): color = 'yellow' __age = 20 def test(): print "Testing..." sm = staticmethod(test) jack = People() People.sm() Testing...
通过上述两个例子看出动态方法与静态方法的输出是一样的,但是其中的运行机制却是不同的:
动态方法是需要谁才会加载谁到内存中,所以是省资源但是效率低;静态方法因为没有(self)所以加载时就会加载所有的方法,占资源但是执行效率高。
当静态方法需要调用类中的其他成员:
#@File :demo_lei.py class People(object): color = 'yellow' __age = 20 def static(): print "This is static" print People.color def dongtai(self): print 'this is dongtailei' print self.color cm = classmethod(dongtai) sm = staticmethod(static) jack = People() People.sm() People.cm() This is static yellow this is dongtailei yellow
除了使用以上说的两个函数来处理动态方法静态方法,还可以使用装饰器:
装饰器:
装饰器也可以自己写,这里暂时没有涉及。简单学会使用即可。
@classmethod #装饰器表示这个方法可以被类调用 def classFun(self): print self.name, print "我是类方法" @staticmethod def staticFun(): #静态方法与动态方法不同,定义时不需要使用self print MyClass.name, print "我是静态方法" 使用装饰器使得该方法可以被调用。
python内部类:
内部类就是类的嵌套:在类里面再创建类。
#@File :demo_lei.py class People(object): color = 'yellow' __age = 20 class Chinese(object): print 'I am Chinese' name = 'zhe shi neibulei shuxing' jack = People() \这里也可以直接实例化对象为jack = People.Chinese,之后直接打印jack.name print jack.Chinese.name I am Chinese zhe shi neibulei shuxing
__str__:类似这样的双下划线开头结尾的成为类的内置方法或魔术方法。
#@File :demo_lei.py class People(object): color = 'yellow' __age = 20 # def __str__(self): # return "this is People-class" class Chinese(object): print 'I am Chinese' name = 'zhe shi neibulei shuxing' ren = People() print ren I am Chinese <__main__.People object at 0x037D9030> 可见这里的显示并不友好,可以对代码进行修改:上述代码注释部分打开后重新执行: I am Chinese this is People-class
构造函数和析构函数:
构造函数:用于初始化类的内部状态,python提供的构造函数是:__init__();该方法是可选的,如果不提供,python会给出一个默认的 __init__方法。
析构函数:用于释放对象占用的资源,python提供的析构函数是__del__();该函数也是可选的,如果不提供,则python会在后台提供默认的析构函数。
#@File :demo_lei.py class People(object): color = 'yellow' __age = 20 def __str__(self): return "this is People-class" def __init__(self): self.color = 'black' class Chinese(object): print 'I am Chinese' name = 'zhe shi neibulei shuxing' ren = People() print ren.color print People.color I am Chinese black yellow 这里看出构造函数也是不需要调用自动执行的,触发执行则是通过实例化对象实现的。如果不实例化对象,直接使用类调用,则不会触发初始化。
初始化函数不仅可以放属性,还可以放方法:
#@File :demo_lei.py class People(object): color = 'yellow' __age = 20 def __str__(self): return "this is People-class" def __init__(self, c='white'): self.color = c self.think() def think(self): print ('I am a thinker') class Chinese(object): # print 'I am Chinese' name = 'zhe shi neibulei shuxing' ren = People('green') print ren.color print People.color I am a thinker green yellow
析构函数:脚本结束之后才会执行,主要是释放资源。其实即使没有这个函数,python中还有个垃圾回收机制
#@File :demo_lei.py class People(object): color = 'yellow' __age = 20 def __init__(self, c='white'): self.color = c self.fd = open('C:YouKuAaa.txt') def __del__(self): print 'Del...' self.fd.close() ren = People() print People.color print 'main end' yellow main end Del...
由上面脚本可以看出 __del__ 结束之后才会执行,主要是释放资源。其实即使没有这个函数,python中还有个垃圾回收机制。
python的垃圾回收站机制:
python采用垃圾回收机制来清理不再使用的对象;python提供gc模块释放不再使用的对象
python采用“引用计数”的算法方式来处理回收,即:当某个对象在其作用域中不再被其他对象引用的时候,python就自动清除对象;
gc模块的collect()可以一次性收集所有待处理的对象(gc.collect)
#@File :demo_lei.py import gc class People(object): color = 'yellow' __age = 20 def __init__(self, c='white'): self.color = c self.fd = open('C:YouKuAaa.txt') def __del__(self): print 'Del...' self.fd.close() print gc.collect() ren = People() print People.color print 'main end' 0 yellow main end 0 Del...
该模块方法的返回值为0则为没有需要回收的文件。这个模块在后台做清理工作,所以这部分一般不需要我们再关心了。
类的继承:
继承是面向对象的重要特性之一;
继承关系:是相对两个类而言的父子关系,子类继承了父类的所有共有属性和方法。
继承实现了代码的重用。
继承可以重用已经存在的数据和行为,减少代码的重复编写。python再类名后使用一对括号来表示继承关系,括号中的类即为父类。
#@File :demo_lei.py import gc class People(object): color = 'yellow' def __init__(self, c): print "Init..." self.dwell = 'Earth' def think(self): print "I am a %s" % self.color print "I am a thinker" class Chinese(People): def __init__(self): People.__init__(self, 'red') pass cn = Chinese() Init...
格式:class Myclass(ParentClass)
这里的重点:父类定义了 __init__方法(我理解是父类对__init__方法进行了加工,不是采用__init__默认的格式,不然没必要重新定义所以),子类必须显式调用父类的 __init__方法:ParentClass.__init__(self, [args...])如果子类需要扩展父类的行为,可以添加 __init__方法的参数。注意定义父类时,要使用class Parent(object),new style方式来定义,否则继承会报错。
还可以使用super函数继承父类:这里需要牢记super的语法格式结构!
#@File :demo_lei.py import gc class People(object): color = 'yellow' def __init__(self, c): print "Init..." self.dwell = 'Earth' class Chinese(People): def __init__(self): # People.__init__(self, 'red') super(Chinese, self).__init__('red') pass cn = Chinese() Init...
继承__init__初始化函数更推荐使用super来进行类的集成,因为super有很大的优势:自动识别到父类不需要手动输入父类名称,如果修改父类名称,可以省略很多工作量。
有了父类,子类中可以节省代码重复,还可以增加自己需要的方法
#@File :demo_lei.py import gc class People(object): color = 'yellow' def __init__(self, c): print "Init..." self.dwell = 'Earth' def think(self): print "This is Parent`s think" class Chinese(People): def __init__(self): # People.__init__(self, 'red') super(Chinese, self).__init__('red') def talk(self): print "I like talking" # def think(self): # print "child`s think" cn = Chinese() cn.talk() cn.think() Init... I like talking This is Parent`s think
甚至是修改父类的方法,为己所有。
#@File :demo_lei.py import gc class People(object): color = 'yellow' def __init__(self, c): print "Init..." self.dwell = 'Earth' def think(self): print "This is Parent`s think" class Chinese(People): def __init__(self): # People.__init__(self, 'red') super(Chinese, self).__init__('red') def talk(self): print "I like talking" def think(self): print "child`s think" cn = Chinese() cn.talk() cn.think() Init... I like talking child`s think
多重继承:
python支持多重继承,即一个类可以继承多个父类:语法 class childnam(parent_1,Parent_2,...)
#@File :demo_lei.py class People(object): color = 'yellow' def __init__(self): print "Init..." self.dwell = 'Earth' def think(self): print "I am a %s" % self.color print "My home is %s" % self.dwell class Martian(object): color = 'red' def __init__(self): self.dwell = 'Martian' # class Chinese(People, Martian): class Chinese(Martian, People): def __init__(self): super(Chinese, self).__init__() # People.__init__(self) cn = Chinese() cn.think() I am a red My home is Martian
其中要注意,子类继承父类的__init__方法时,尤其是多重继承需要修改前后位置的情况,如果没有super一定要记得修改父类的名称。实验过程中,就因为忘记而出现问题,得到的结果不正确的情况。所以这种情况,推荐super。
需要注意到是:当父类中出现多个自定义的__init__方法时,多重继承只执行第一个类的__init__方法,其他不执行。但是注意下面这个例子:
#@File :demo_lei.py class People(object): color = 'yellow' def __init__(self): print "Init..." self.dwell = 'Earth' self.color = 'yellow' def think(self): print "I am a %s" % self.color print "My home is %s" % self.dwell class Martian(object): color = 'red' def __init__(self): self.dwell = 'Martian' # class Chinese(People, Martian): class Chinese(Martian, People): def __init__(self): # super(Chinese, self).__init__() People.__init__(self) cn = Chinese() cn.think() Init... I am a yellow My home is Earth
总结:
类的属性-总结:
var5 = '全局变量 var5' class MyClass(object): var1 = '类属性,类的共有属性 var1' __var2 = '类的私有属性 __val2' def func1(self): self.var3 = '对象的公有属性 var3' self.__var4 = '对象的私有属性 __var4' var5 = '函数的局部变量 var5' print self.__var4 print var5 # var6 = print '__var2' def func2(self): print self.var1 print self.__var2 print self.var3 print self.__var4 print var5 mc = MyClass() print mc.var1 print mc._MyClass__var2 mc.func1() print mc.var3 print('##################### 私有属性测试 ############') mc.func2() print('#### 类的内置属性测试,分别通过对象和类调用 ############') print mc.__dict__ print MyClass.__dict__ 类属性,类的共有属性 var1 类的私有属性 __val2 对象的私有属性 __var4 函数的局部变量 var5 对象的公有属性 var3 ##################### 私有属性测试 ############ 类属性,类的共有属性 var1 类的私有属性 __val2 对象的公有属性 var3 对象的私有属性 __var4 全局变量 var5 #### 类的内置属性测试,分别通过对象和类调用 ############ {'_MyClass__var4': 'xe5xafxb9xe8xb1xa1xe7x9ax84xe7xa7x81xe6x9cx89xe5xb1x9exe6x80xa7 __var4', 'var3': 'xe5xafxb9xe8xb1xa1xe7x9ax84xe5x85xacxe6x9cx89xe5xb1x9exe6x80xa7 var3'} {'func2': <function func2 at 0x032778F0>, '__module__': '__main__', 'var1': 'xe7xb1xbbxe5xb1x9exe6x80xa7xefxbcx8cxe7xb1xbbxe7x9ax84xe5x85xb1xe6x9cx89xe5xb1x9exe6x80xa7 var1', '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, 'func1': <function func1 at 0x03277970>, '__dict__': <attribute '__dict__' of 'MyClass' objects>, '_MyClass__var2': 'xe7xb1xbbxe7x9ax84xe7xa7x81xe6x9cx89xe5xb1x9exe6x80xa7 __val2', '__doc__': None}
类的方法-总结:
#@File :demo_lei_fangfa.py class MyClass(object): name = 'Test' def func1(self): print self.name, #这里结尾没有','则会分行显示! print "我是公有方法" self.__func2() def __func2(self): print self.name, print "我是私有方法" @classmethod #装饰器表示这个方法可以被类调用 def classFun(self): print self.name, print "我是类方法" @staticmethod def staticFun(): #静态方法与动态方法不同,定义时不需要使用self print MyClass.name, print "我是静态方法" mc = MyClass() mc.func1() MyClass.classFun() MyClass.staticFun() Test 我是公有方法 Test 我是私有方法 Test 我是类方法 Test 我是静态方法
类的内置方法:
#@File :demo_lei_fangfa.py class MyClass(object): name = 'Test' def __init__(self): #初始化程序。 self.func1() self.__func2() self.classFun() self.staticFun() def func1(self): print self.name, #这里结尾没有','则会分行显示! print "我是公有方法" # self.__func2() def __func2(self): print self.name, print "我是私有方法" @classmethod #装饰器表示这个方法可以被类调用 def classFun(self): print self.name, print "我是类方法" @staticmethod def staticFun(): #静态方法与动态方法不同,定义时不需要使用self print MyClass.name, print "我是静态方法" mc = MyClass() #这里可以算是类的实例化,由于__init__是初始化,所以程序执行时就将__init__下面的程序都执行了。 Test 我是公有方法 Test 我是私有方法 Test 我是类方法 Test 我是静态方法