最简单的类
class Math:#类名首字母大写,以区分函数定义
def declare(self):
print("We are in class Math!!")
F=Math()#实例化,可以认为造出了一个具有Math所有方法的对象
运行结果
We are in class Math!!
区分不同的实例化对象
class Math:
pi=3.141592683#类变量
def __init__(self,name,type='real'):#构造函数
self.name=name#实例变量/静态属性
def declare(self):#类的方法/动态属性
print("We are in class Math %s!!"%self.name)
F=Math("calculator")#实例化一个对象,该对象的一个标签是calculator(给该对象起了一个名字)
F.declare()
F1=Math("counter")#又实例化一个对象,该对象的一个标签是counter(给该对象起了一个名字)
F1.declare()
运行结果
We are in class Math calculator!!
We are in class Math counter!!
对类的理解
F=Math("calculator")
F.declare()#F.declare()等效于Math.declare(F),在class的每个方法中都带有个self,该self特指F;F被称为class Math的实例
1、构造函数—每实例化一个对象时,都会执行该函数,在内存中开辟一块内存空间,把实例化传入的参数(如calculator)存入变量F中(即赋值过程);
2、构造函数中不传参数,就是默认参数;
3、类的中方法还是在类的内存里面,并没有copy到每个对象内存里面,每个对象要调用类的方法,都要到类内存中取用;
4、对于calculator的实例变量与counter的实例变量不能共享,即实例变量的作用域是实例本身
5、类变量被存在的类的内存里面,没有实例化是可以调用类变量的;实例后,也可以通过类调用类变量
class Math:
pi=3.141592653
def __init__(self,name,type="real"):
self.name=name
self.type=type
def declare(self):
print("We are in class Math %s!!"%self.type)
print(Math.pi)#没有实例化任何对象,也可以调用类变量
F=Math("calculator")
print(F.pi,F.name,F.type)#实例后,通过实例对象调用类变量
运行结果
3.141592653
3.141592653 calculator real
6、当类变量和构造函数中有相同的变量名,通过实例对象调用该变量名时,调用的是实例变量(规则:先搜索实例变量,再搜索类变量)
class Math:
pi=3.141592653
type="I'm class variable"
def __init__(self,name,type="real"):
self.name=name
self.type=type
def declare(self):
print("We are in class Math %s!!"%self.type)
F=Math("calculator")
print(F.type)
运行结果
real
7、对实例变量赋值、新增实例变量、删除某个实例变量
class Math:
pi=3.141592653
type="I'm class variable"
def __init__(self,name,type="real"):
self.name=name
self.type=type
def declare(self):
print("We are in class Math %s!!"%self.type)
F=Math("calculator")
F.type="imag" #改实例变量
print(F.type)
F.precision=9 #新增实例变量(等效于在构造函数中给对象实例了self.precision=9)
print(F.precision)
del F.precision #删除对象F的实例变量precision
运行结果
imag
9
8、更改类变量及通过实例对象更改列表类型的类变量
class Math:
pi=3.141592653
type="I'm class variable"
list=[]
def __init__(self,name,type="real"):
self.name=name
self.type=type
def declare(self):
print("We are in class Math %s!!"%self.type)
Math.type="I'm new class variable"
print(Math.type)
print(Math.list,F.list)
F.list.append(1) #通过实例对象改类变量
print(Math.list,F.list)
运行结果
I'm new class variable
[] []
[1] [1]
9、类变量是这个类所有实例对象共同的属性,应该放在类变量的位置,不应该放在构造函数中;因为如果放在构造函数里面作为实例变量,这样每个实例对象都会开辟一块内存,这样会浪费内存
析构函数
析构函数;用于在实例释放释放、销毁的时候执行的;通常用于做一些收尾工作,如关闭一些数据库链接,关闭被打开的临时文件;(在程序退出时执行析构函数,或者在删除对象时执行析构函数)
class Math:
pi=3.141592653
type="I'm class variable"
list=[]
def __init__(self,name,type="real"):
self.name=name
self.type=type
def __del__(self):
print("object %s has been destroyed"%self.name)
def declare(self):
print("We are in class Math %s!!"%self.type)
F1=Math("calculator")
del F1#销毁实例对象F1
F2=Math("counter")
F2.declare()
运行结果
object calculator has been destroyed
We are in class Math real!!
object counter has been destroyed
python的内存回收机制:只要删除变量名,python就认为该变量的要被删除了
私有属性/私有方法
私有属性:只能被自己访问
class Game:
region="China"
def __init__(self,name,role,weapon="handgun",lifevalue=100):
self.name=name
self.role=role
self.weapon=weapon
self.__lifevalue=lifevalue #私有属性,私有属性只能在类内部被访问
def get_weapon(self):
print("I get AWM")
def show_value(self):
print("%s's life value is %s"%(self.name,self.__lifevalue))
def __cut_blood(self): #私有方法
self.__lifevalue -=10 #私有属性只能被class内部访问
def got_shoot(self):
self.__cut_blood() #私有方法只能被类内部被访问
print("%s's blood reduce 10,remain %s"%(self.name,self.__lifevalue))
m=Game('Jack','Police')
m.show_value()
m.got_shoot()
m.got_shoot()
运行结果
Jack's life value is 100
Jack's blood reduce 10,remain 90
Jack's blood reduce 10,remain 80
class的继承特性
子类可以继承父类
class Math:
pi=3.141592653
type="I'm class variable"
list=[]
def __init__(self,name,type="real"):
self.name=name
self.type=type
# def __del__(self):
# print("object %s has been destroyed"%self.name)
def declare(self):
print("We are in class Math %s!!"%self.type)
def add(self,a,b):
return a+b
def subtract(self,a,b):
return a-b
def multipy(self,a,b):
return a*b
def three_multipy(self,a,b,c):
return Math.multipy(self,Math.multipy(self,a,b),c)
def divide(self,a,b):
return a/b
def newton_sqrt(self,c):
e = 0.00000001
x = 1
x1 = (x + c / x) / 2
while abs(x1 - x) >= e:
x = x1
x1 = (x + c / x) / 2
return x1
class Area(Math):
unit="meter^2"
def __init__(self,name,method,type="real"):#该__init__不写,也可以调用父类定义的静态属性
Math.__init__(self,name,type)
#等于super(Area,self).__init__(name,type),该指令的优点后面详细描述
self.method=method#子类Area的属性
def circle_area(self,r):
return Math.pi*Math.multipy(self,r,r)
class Volume(Math):
unit="meter^3"
def __init__(self,name,method,type="real"):
Math.__init__(self,name,type)
self.method=method#子类Volume的属性
def cylinder_volume(self,r,h):
return Math.multipy(self,Math.three_multipy(self,Math.pi,r,r),h)
b=Area("b","Gauss")
print(b.circle_area(3),b.unit)
a=Volume("a","Gauss")
print(a.cylinder_volume(2,5),a.unit)
运行结果
28.274333877 meter^2
62.83185306 meter^3
super(Area,self).init(name,type)的优点一:
class Volume(Math,Physics):
unit="meter^3"
def __init__(self,name,method,type="real"):
super(Volume,self).__init__(name,type)
self.method=method
def cylinder_volume(self,r,h):
return Math.multipy(self,Math.three_multipy(self,Math.pi,r,r),h)
如上代码所示,如果类Volume继承两个或者多个类时,只需要super(Volume,self).init(name,type),就可以搞定,而使用之前的,则需要Math.init(self,name,type)+Physics.init(self,name,type)两条指令;
super(Area,self).init(name,type)的优点二:
如果类里面多次重构父类方法,如果父类类名被改变,则后面的语句都会失效;如果使用super(Area,self).init(name,type)这样的指令,如下,则只需只需要改Area(Math)处的类名Math
class Area(Math):
unit="meter^2"
def __init__(self,name,method,type="real"):
# Math.__init__(self,name,type)
super(Area,self).__init__(name,type)
self.method=method
def circle_area(self,r):
return super(Area,self).pi*super(Area,self).multipy(self,r,r)
经典类与新式类(类似于版本更新)
上面定义类的方式 class Math:是属于经典类的定义法
经典类的定义 是 class Math(object):( Math.init(self,name,type)也属于经典类)
super(Area,self).init(name,type)、super(Area,self).multipy(self,r,r) ------super 也是新式类的定义法
经典类与新式类的区别主要体现在继承上,为此先论述多继承
python的多继承特性
多继承顺序问题
多继承构造函数执行顺序
class People(object):
def __init__(self,name,age):
print("in class People")
self.name=name
self.age=age
def add_compute(self,a,b):
return a+b
class Relation(object):
def __init__(self,education):
self.education=education
print("in class Relation")
def make_friend(self,obj):
print("%s is making friend with %s"%(self.name,obj.name))
class Man(Relation,People):
def __init__(self,name,age,sex,education):
super(Man,self).__init__(education)
self.sex=sex
self.education=education
print("in class Man")
def making_money(self):
print("%s is making money!!!"%self.name)
m1=Man("Jack",22,"male","undergraduate_degree")
1、如果直接调用的类Man中有构造函数,则执行Man中的构造函数。如果该构造函数中有super(Man,self).init(education),则继续执行Man(Relation,People)中第一个父类Relation的构造函数,因此super(Man,self).init(education)中的参数个数要依照第一个父类的构造函数要求来写(第一个父类也没有构造函数,则执行第二个父类的构造函数,以此类推);如果Man的构造函数中没有super(Man,self).init(education),实例化工作也就结束了。
2、如果直接调用的类Man中么有构造函数,这执行第一个父类的构造函数(如果第一个父类也没有构造函数,则执行第二个父类的构造函数,以此类推);因此在类Man中没有构造函数,这实例化Man时,所需要的参数个数要依照有构造函数的第一个父类要求来给予;
class People(object):
def __init__(self,name,age):
self.name=name
self.age=age
self.friends=[]
def add_compute(self,a,b):
return a+b
class Relation(object):
def __init__(self,education):
self.education=education
def make_friend(self,obj):
print("%s is making friend with %s"%(self.name,obj.name))
self.friends.append(obj)
#把obj的内存地址添加到self.friends中去,obj这片地址有任何变动,self.friends都索引到这片地址
obj.friends.append(self)
class Man(People,Relation):
sex="male"
def __init__(self,name,age,education):
super(Man,self).__init__(name,age)
self.education=education
def making_money(self):
print("%s is making money!!!"%self.name)
class Woman(People,Relation):
sex="female"
def __init__(self,name,age,education):
super(Woman,self).__init__(name,age)
self.education = education
m1=Man("Jack",22,"undergraduate_degree")
w1=Woman("Merry","20","graduate_degree")
m1.make_friend(w1)
m1.name="jack"
w1.name="merry"
print(w1.friends[0].name)
#w1.friends是一个地址,这个地址中存的内容是对象m1的所有实例化后产生的
print(m1.friends[0].name)
运行结果
Jack is making friend with Merry
jack
merry
像上面这个程序,在实例化m1或w1时,首先执行Man或Woman的构造函数;而构造函数中第一条指令就是让执行第一个有构造函数的父类的构造函数
多继承方法的执行顺序
class A(object):
...
class B(A):
...
class C(A):
...
class D(B,C)
构造函数执行顺序:首先执行class D中的构造函数;如果class D没有构造函数,则按照B,C顺序执行第一个有构造函数的类的构造函数;
广度优先与深度优先
广度优先即D–>B–>C–>A(python3属于这种)
深度优先即D–>B–>A–>C(python2属于这种)
python2的经典类(即class A:)按深度优先
python2的新式类(即classA(object))按广度优先
python3的经典类与新式类都是按广度优先