python是一门面向对象的语言
类是对象的抽象集合,对象是类的具体表现
一、面向对象关键要素:
类:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象类的实例
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用
数据成员:类的不同属性数据
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖,也称为方法的重写
实例变量:定义在方法中的变量,只作用于当前实例的类
继承:即一个派生类继承基类的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待
方法:类中定义的函数
对象:通过类的定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法
二、面向对象编程
简称OOP(Object Oriented Programming),是一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数方法
面向对象的设计思想是从自然界来的,因为在自然界中,类(class)和实例的概念是很自然的。class是一种抽象的概念。
三大特性
封装
继承
多态
三、python类与对象
1、定义类:
class Student(object) :
类体
class是类的定义的关键词,class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的。通常如果没有明确的继承类,就是用object类,括号内一般为空默认就是继承Object类。这是所有类最终都会继承的类,也就是基类
2、案例1:
在班级要求两名新同学jack和harry分别介绍自己的名字和来自哪座城市,然后在喊一句口号:hello word,最终在控制台打印效果 (可以用最基础的方式打印出来)
问题:如果老师要求全班50个同学一次以以上的形式自我介绍,来自的城市,顺便介绍自己的年龄?怎么写更为方便?
第一步:属性初始化,定义类
由于类可以起到模板的作用,因此,可以在创建实例对象的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的_init_方法,如:在创建Student实例的时候,就把name,city等属性绑上去;
class Student() :
def __init__(self,name,city):
self.name = name
self.city = city
print("my name is %s and come from %s " % (name,city))
(1)第一种方法:__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法
(2)self代表类的实例,self在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。__init__方法的第一个参数永远都是self,表示创建实例的本身。因此,在__init__方法内部,就可以把各种属性绑定到self
第二步:定义方法:
类的方法除了第一个参数是self外,其它的和普通的函数一样。要调用一个方法,只需要在实例变量上直接调用
def talk(self):
print("hello word")
第三步:生成实例对象
stu1 = Student('jack',beijing)
stu1.talk()
stu2 = Student('marry','shanghai')
stu2.talk()
案例2:
员工基类,姓名,薪资
class Employee:
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)
emp1 = Employee("Zara", 2000)
emp2 = Employee("Manni", 5000)
emp1.displayEmployee()
emp2.displayEmployee()
print("Total Employee %d" % Employee.empCount)
输出结果
Name : Zara , Salary: 2000
Name : Manni , Salary: 5000
Total Employee 2
方法分类:
实例方法,类方法,静态方法
四、python内置类属性
__dict__:类的属性(包含一个字典,由类的数据属性组成)
__doc__:类的文档字符串
__name__:类名
__module__:类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__等于mymod)
__bases__:类的所有父类构成元素(包含了一个由所有父类组成的元组)
class Employee:
'所有员工的基类'
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__: 所有员工的基类
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: (<class 'object'>,)
Employee.__dict__: {'__weakref__': <attribute '__weakref__' of 'Employee' objects>, '__module__': '__main__', '__doc__': '所有员工的基类', '__init__': <function Employee.__init__ at 0x0000000001058378>, 'empCount': 0, '__dict__': <attribute '__dict__' of 'Employee' objects>, 'displayCount': <function Employee.displayCount at 0x0000000001058400>, 'displayEmployee': <function Employee.displayEmployee at 0x0000000001058488>}
五、python对象销毁(垃圾回收)
python使用了引用计数这一简单技术来跟踪和回收垃圾
在python内部记录着所有使用中的对象各有多少引用
一个内部跟踪变量,称为一个引用计数器
当对象被创建时,就创建了一个引用计数,当这个对象不再需要时,这个对象的引用计数变为0,它被垃圾回收。但是回收不是“立即”的。由解释器在适当的时机,将垃圾对象占用的内存空间回收
a = 40 # 创建对象 <40> b = a # 增加引用, <40> 的计数 c = [b] # 增加引用. <40> 的计数 del a # 减少引用 <40> 的计数 b = 100 # 减少引用 <40> 的计数 c[0] = -1 # 减少引用 <40> 的计数
垃圾回收机制不仅针对引用计数为0的对象,同样也可以处理循环引用的情况。循环引用指的是,两个对象相互引用,但是没有其他变量引用它们。这种情况下,仅使用引用计数是不够的。python的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。作为引用计数的补充,垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)对象。在这种情况下,解释器会暂停下来,试图清理所有未引用的循环。
六、类的继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。
通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类
继承语法:
class 派生类名(基类名)
......
在python中继承的一些特点:
1、如果在子类中需要父类的构造方法就需要显示的调用父类的构造方法,或者不重写父类的构造方法
2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别在于类中调用普通函数时并不需要带上self参数
3、python总是首先查找对应类型的方法,如果他不能在派生类中找到对应的方法,他才开始到基类中逐个查找(现在本类中查找调用的方法,找不到才去基类中找)
如果在继承元组中列出了一个以上的类,那么他就被称作“多重继承”
语法:
派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后
class SubClassName (ParentClass1 [,ParentClass2,...]) :
......
案例1:
class Parent: # 定义父类
parentAttr = 100
def __init__(self):
print( "调用父类构造函数")
def parentMethod(self):
print( '调用父类方法')
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print("父类属性 :", Parent.parentAttr)
class Child(Parent): # 定义子类
def __init__(self):
print("调用子类构造方法")
def childMethod(self):
print( '调用子类方法')
c = Child() # 实例化子类
c.childMethod() # 调用子类的方法
c.parentMethod() # 调用父类方法
c.setAttr(200) # 再次调用父类的方法 - 设置属性值
c.getAttr() # 再次调用父类的方法 - 获取属性值
运行结果:
调用子类构造方法
调用子类方法
调用父类方法
父类属性 : 200
继承多个类:
class A: #定义类A
........
class B : #定义类B
.......
class C(A,B): #定义类A和B
...........
可以使用issubclass()或者isinstance()方法来检测
issubclass() -布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
isinstance(obj,Class)布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true
七、方法重写
如果父类方法的功能不能满足你的需求,你可以在子类重写父类的方法:
举例:
class Parent: # 定义父类
def myMethod(self):
print( '调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
运行结果:
调用子类方法
八、基础重载方法
下表列出了一些通用的功能,可以在自己的类重写:
序号 | 方法, 描述 & 简单的调用 |
__init__ ( self [,args...] ) | 构造函数 简单的调用方法: obj = className(args) |
__del__( self ) | 析构方法, 删除一个对象 简单的调用方法 : del obj |
__repr__( self ) | 转化为供解释器读取的形式 简单的调用方法 : repr(obj) |
__str__( self ) | 用于将值转化为适于人阅读的形式 简单的调用方法 : str(obj) |
__cmp__ ( self, x ) | 对象比较 简单的调用方法 : cmp(obj, x) |
九、运算符重载
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)
九、类属性与方法
1、类的私有属性
__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时self.__private_attrs
2、类的方法
在类的内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数
类的私有方法:
__private_method:两个下划线开头,申明该方法为私有方法,不能在类的外部调用。在类的内部调用self.__private_methods
十、单下划线、双下划线、头尾双下滑线说明:
__foo__:定义的是特殊方法,一般是系统定义名字,类似__init__()之类的
_foo:以单下划线开头的表示的是protected类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于from module import *
__foo:双下划线的表示的是私有类型(private)的变量,只能是允许这个类本身进行访问了