a23_Python面向对象---学习笔记

Python从第一天开始就是面向对象的语言。正因为如此,创建和使用类和对象是非常地容易。本章将帮助您在使用Python面向对象编程的技术方面所有提高。

如果没有任何以往面向对象(OO)的编程的经验,那么可能要了解一些基本的入门课程就可以了,或者至少某种形式的教程,让你有了解基本概念。

但是,这里会比较少地介绍面向对象编程(OOP):

OOP术语概述:

类:用户定义的原型对象,它定义了一套描述类的任何对象的属性,属性是数据成员(类变量和实例变量)和方法,通过点符号访问。

类变量:这是一个类的所有实例共享的变量,类变量在类,但外面的任何类的方法定义,类变量不被用作经常作为实例比变量。

数据成员:保存于类和对象关联的数据类变量或实例变量。

函数重载:一个以上的行为特定功能的分配,执行的操作所涉及的对象(自变量)的类型不同而不同。

实例变量:所定义的方法内,只属于一个类的当前实例的变量。

继承:类的特点,即都是由它派生其他类的转移。

实例:某一类的一个单独对象。属于类Circle一个obj对象,例如,是类Circle的一个实例。

实例化:创建一个类的实例。

Method:一种特殊的函数,函数在类定义中的定义。

对象:这是由它的类中定义的数据结构的唯一实例。一个对象包括两个数据成员(类变量和实例变量)和方法。

运算符重载:一个以上的函数功能,特定的操作符分配。

创建类:

类语句将创建一个新的类定义,类的名称紧跟在关键字class后跟一个冒号,如下所示:

class ClassName:
    'Optional class documentation string'
    class_suite

类有一个文档字符串,它可以通过类名.__ doc__访问。

class_suite由所有定义的类成员,数据属性与函数组件的语句。

例子:

下面是一个简单的 Python类的例子:

class Employee:
    'Common base class for all employees'
    empCount = 0
    def __index__(self,name,salary):
        self.name = name
        self.salary = salary
        Employee.empCount += 1
    def displayCount(self):
        print ("Total Employee %d " % Employee.empCount)
    def displayEmployee(self):
        print ("Name: ",self.name,",Salary: ",self.salary)
  • empCount是一个类变量,其值将是这个类的所有实例共享。这可以从类中或外部进行访问,访问形式为 Employee.empCount。

  • 第一个方法__init__()是一种特殊的方法,这就是所谓的类构造函数或当创建该类的一个新实例Python调用的初始化方法。

  • 声明就像正常函数中一样,不同的是第一个参数到每个方法是类的方法。 Python增加了self参数列表;不需要把调用的方法都它列入。

创建实例对象:

要创建一个类的实例,调用类名并传递任何参数给__init__方法接收。

"This would create first object of Employee class"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class"
emp2 = Employee("Manni", 5000)

现在,把所有的概念放在一起:

#第一部分
class Employee:
    'Common base class for all employee所有员工的基类'
    empCount = 0 #员工 计数
    def __init__(self,name,salary): #定义姓名,工资
        self.name = name
        self.salary = salary
        Employee.empCount += 1 #员工的.员工计数器自增
    def displayCount(self): #展示计数器
        print ("11Total Employee %d " % Employee.empCount) #员工总数,调用员工的员工计数器
    def displayEmployee(self):#展示雇员
        print ("Name1: ",self.name,",Salary: ",self.salary)#展示姓名,工资
 #第二部分创建实例
"This would create first object of Employee class,创建Employee类的第一个对象"
emp1 = Employee("Zara", 2000)
"This would create second object of Employee class,创建Employee类的第二个对象"
emp2 = Employee("Manni", 5000)
#第三部分类变量使用类名来访问
emp1.displayEmployee()
emp2.displayEmployee()
print ("22Total Employee %d" % Employee.empCount) #员工总数,调用员工计数器

当执行上面的代码,产生以下结果:

Name1:  Zara ,Salary:  2000
Name1:  Manni ,Salary:  5000
22Total Employee 2

在任何时候可以添加,删除或修改类的对象的属性:

#第二部分创建实例
"This would create first object of Employee class,创建Employee类的第一个对象"
emp1 = Employee("Zara", 2000,18)
emp1.age =7 #添加对象属性
emp1.age =17#更改对象属性

"This would create second object of Employee class,创建Employee类的第二个对象"
emp2 = Employee("Manni", 5000,20)
emp2.age = 8 #添加对象属性,如果不添加这段就会报错提示缺少字段
del emp2.age  #已经被删除
emp2.age = 18#二次被添加
emp2.sex ="male"
emp2.marriage = "unmarried"
"This would creat third object of Employee class,创建Employee类的第三个对象"
emp3 = Employee("kenken",1500,25)

除了使用正常的语句来访问属性,可以使用一下函数:

getattr(obj,name[,default]):访问对象属性

hasattr(obj,name):检查一个属性是否存在

setattr(obj,name,value):设置一个属性,如果属性不存在,那么他将被创建。

delattr(obj,name):要删除一个属性

#第一部分
class Employee:
    'Common base class for all employee所有员工的基类'
    empCount = 0 #员工 计数
    def __init__(self,name,salary,age): #定义姓名,工资
        self.name = name
        self.salary = salary
        self.age = age
        Employee.empCount += 1 #员工的.员工计数器自增
    def displayCount(self): #展示计数器
        print ("11Total Employee %d " % Employee.empCount) #员工总数,调用员工的员工计数器
    def displayEmployee(self):#展示雇员
        print ("Name1: ",self.name,",Salary: ",self.salary,",age:",self.age)#展示姓名,工资,新增加的年龄字段,不增加不显示
 #第二部分创建实例
"This would create first object of Employee class,创建Employee类的第一个对象"
emp1 = Employee("Zara", 2000,18)
emp1.age =7 #添加对象属性
emp1.age =17#更改对象属性

"This would create second object of Employee class,创建Employee类的第二个对象"
emp2 = Employee("Manni", 5000,20)
emp2.age = 8 #添加对象属性,如果不添加这段就会报错提示缺少字段
del emp2.age  #已经被删除
emp2.age = 18#二次被添加
emp2.sex ="male"
emp2.marriage = "unmarried"
"This would creat third object of Employee class,创建Employee类的第三个对象"
emp3 = Employee("kenken",1500,25)
#第三部分类变量使用类名来访问
emp1.displayEmployee()
emp2.displayEmployee()
emp3.displayEmployee()
print ("22Total Employee %d" % Employee.empCount) #员工总数,调用员工计数器
print (emp2.displayEmployee())
print (hasattr(emp2,'sex')) # Returns true if 'sex' attribute exists 如果存在'sex'属性,则返回true
print (getattr(emp2,'sex'))#返回‘sex’属性的值,returns value of 'sex' attribute
print (setattr(emp2,'sex','Female'))#Set attribute 'sex' at 'Female' 将属性‘sex’设置为“Female”
print (getattr(emp2,'sex'))#返回‘sex’属性的值,returns value of 'sex' attribute
print (delattr(emp2,'marriage')) #删除属性“age”,Delete attribute 'age'

当执行上面的代码,产生以下结果:

Name1:  Zara ,Salary:  2000 ,age: 17
Name1:  Manni ,Salary:  5000 ,age: 18
Name1:  kenken ,Salary:  1500 ,age: 25
22Total Employee 3
Name1:  Manni ,Salary:  5000 ,age: 18
None
True
male
None
Female
None

内置的类属性:

每个Python类会继续并带有内置属性,他们可以使用点运算符像任何其他属性一样来访问:

__dict__:字典包含类的命名空间

__doc__:类的文档字符串,或None如果没有定义。

__name__:类名称

__module__:在类中定义的模块名称,此属性是在交互模式值为“__main__”。

__bases__:一个可能是空的元组包含了基类,其在基类列表出现的顺序。

对于上面的类,尝试访问这些属性:

#!/usr/bin/python
#访问类属性
class Employee:
    "Common base class for all employees"
    empCount = 0
    def __init__(self,name,salary):
        self.name = name
        self.salary = salary
        Employee.empCount += 1
    def displayCount(self):
        print ("Total Employee %d " % Employee.empCount)
    def displayEmployee(self):
        print ("Name: ",self.name,",Salary: " ,self.salary)
print ("Employee.__doc__:",Employee.__doc__)  #类的文档字符串
print ("Employee.__name__:",Employee.__name__)#类的名字
print ("Employee.__module__:",Employee.__module__)#类中定义的模块名称
print ("Employee.__bases__:",Employee.__bases__)#一个可能是空的元组包含了基类,其在基类列表出现的顺序
print ("Employee.__dict__:",Employee.__dict__)#字典包含的命名空间

当执行上面的代码,产生以下结果:

Employee.__doc__: Common base class for all employees
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (,)
Employee.__dict__: {'__module__': '__main__', '__doc__': 'Common base class for all employees', 'empCount': 0, '__init__': , 'displayCount': , 'displayEmployee': , '__dict__': , '__weakref__': }

销毁对象(垃圾回收):

Python的删除不需要的对象(内建类型或类的实例),自动释放内存空间,由Python定期回收的内存不再使用的过程被称为垃圾收集

Python的垃圾回收器在程序执行过程中运行,当一个对象的引用计数为零时触发,一个对象的引用计数改变为指向他改变的数量。

当它分配一个新的名字或放置在容器(列表,元组或字典)的对象的引用计数增加,当对象的引用计数减少使用del删除,其基准被重新分配,或者它的引用超出范围,当一个对象的引用计数变为零,Python会自动地收集它。

a = 40      # Create object <40> 创建对象<40>
b = a       # Increase ref. count of <40> 增加参考
c = [b]     # Increase ref. count of <40> 增加参考

del a       # Decrease ref. count of <40>减少参考
b = 100     # Decrease ref. count of <40> 减少参考
c[0] = -1   # Decrease ref. count of <40> 减少参考

当垃圾回收器销毁孤立的实例,并回收其空间一般不会注意到,但是,一个类可以实现特殊方法__del__(),称为析构函数被调用时,该实例将被摧毁。这个方法可以用于清理所有的一个实例的任何非内存资源。

例子:

__del__()析构函数打印实例,它即将被销毁的类名:

#!/usr/bin/python
class Point:
    def __init__(self,x =0,y=0):
        self.x = x
        self.y = y
    def __del__(self):
        class_name = self.__class__.__name__
        print (class_name,"destroyed")
pt1 = Point()
pt2 = pt1
pt3 = pt1
print (id(pt1),id(pt2),id(pt3)) #prints the ids of the obejcts
del pt1
del pt2
del pt3

当执行上面的代码,它产生以下结果:

2580065876848 2580065876848 2580065876848
Point destroyed

注意:理想情况下,应该定义类的单独的文件,那么应该使用import语句将其导入主程序文件,详细请查看Python- 模块章节,导入模块和类的更多细节。

类继承:

不用从头开始,可以通过上面列出的括号父类的新类名后,从一个已经存在的类派生它创建的一个类。

子类继承父类的属性,可以使用父类的这些属性,就好像他们是在子类中定义的一样,子类也可以覆盖父类的数据成员和方法。

语法:

派生的声明很像他们的父类:从基类的列表后给出类名继承:

class SubClassName (ParentCLASS1[,ParentClass2,...]):
    'Optional class documentation string'
    class_suite

例子:

#!/usr/bin/python

class Parent: #父类、定义一个父类、define parent class
    '''调用父类函数'''
    parentAttr = 100
    def __init__(self):
        print ("Calling parent constructor") #打印调用父类构造函数
    def parentMethod(self):
        print ('Calling parent method') #打印调用父类方法
    def setAttr(self, attr):
        Parent.parentAttr = attr #属性-继承父类属性,父类属性
    def getAttr(self):
        print ("Parent attribute : ",Parent.parentAttr) #打印父类属性
class Child(Parent): # define child class 定义子类
    def __init__(self):
        print ("Calling child constructor")#打印调用结构函数
    def childMethod(self):
        print('Calling child method')#打印调用方法
c = Child() #instance of child /child的实类
c.childMethod() #child calls its method 子调用其方法
c.parentMethod() #calls parent's method 调用父类方法
c.setAttr(200)#agein call parent's method 再次调用父类方法
c.getAttr() #again call parent's method 再次调用弗雷方法

当执行上面的代码,它产生以下结果:

Calling child constructor
Calling child method
Calling parent method
Parent attribute :  200

类似的方式,可以按如下继承多个父类的类:

Class A: #define your class A
...
Class B: #define your class B
...
Class C: #subclass of A and B
...

可以使用issubclass()或isintance()函数来检查两个类和实例的关系:

issubclass(sub,sup)如果给定的子类子确实是超sup的子类布尔函数返回true。

isinstance(obj,Class)如果obj是Class类的实例,或者是类的一个子类的实例布尔函数返回true

重写方法:

可以覆盖父类的方法,原因之一重写父类的方法,因为可能想再子类特殊或实现不同的功能。

例子:

#!/usr/bin/python
class Parent: #define parent class
    def myMethod(self):
        print ('Calling parent method')
class Child(Parent): #define child class
    def myMethod(self):
        print ('Calling child method')
c = Child() # instance of child
c.myMethod() #child calls overridden method

当执行上面的代码,产生以下结果:

Calling child method

基础重载方法:

下表列出了一些通用的功能,可以在类重写中:

SN 方法,说明与调用示例
1 __init__ ( self [,args...] )
构造函数(任何可选参数)
简单调用 : obj = className(args)
2 __del__( self )
析构函数,删除一个对象
简单调用 : del obj
3 __repr__( self )
可求值的字符串表示形式
简单调用 : repr(obj)
4 __str__( self )
可打印字符串表示形式
简单调用 : str(obj)
5 __cmp__ ( self, x )
对象比较
简单调用 : cmp(obj, x)

重载运算符:

 假设要创建一个 Vector类来表示二维向量,当使用加运算符来增加他们发生了什么?最有可能是Python会屌你。

可以,但是定义__add__方法在类中进行矢量相加,再加上操作符的行为会按预期:

例子:

#!/usr/bin/python
class Vector:
    def __init__(self,a,b):
        self.a = a
        self.b = b
    def __str__(self):
        return ('Vector (%d ,%d)' % (self.a,self.b))
    def __add__(self, other):
        return ('Vector(self.a + other.a,self.b+ other.b)')
    
v1 = Vector(2,10)
v2 = Vector(5,-2)
print (v1 + v2)

当执行上面的代码,产生以下结果:

Vector(7,8)

数据隐藏:

对象的属性可以是或可以不再类定义外部可见,对于这些情况,可以命名以双下划綫前缀属性,这些属性将无法直接让外部可视。

例子:

#!/usr/bin/python
class JustCounter:
    __secretCount = 0
    def count(self):
        self.__secretCount += 1
        print (self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print (counter.__secretCount)

当执行上面的代码,产生以下结果:

1
Traceback (most recent call last):
2
  File "F:/pythonDEV/简明python笔记/面向对象/数据隐藏.py", line 10, in 
    print (counter.__secretCount)
AttributeError: 'JustCounter' object has no attribute '__secretCount'

Python的保护成员听过内部更改名称以包含类名,可以访问这些属性通过object._className_attrName。如果想更换最后一行。那么它会工作如下:

...........
print(counter._JustCounter__secretCount)

当执行上面的代码,产生以下结果:

1
2
2

 

你可能感兴趣的:(Python成就未来)