1、创建类、类的构造函数、类变量 、类方法、创建类的对象,调用类的方法和类变量 :
class Employee: #定义Employee类
empCount=0 #类变量,可以使用Employee.empCount访问
def __init__(self,name,salary): #Employee类的构造函数
self.name=name
self.salary=salary
Employee.empCount+=1
def displayCount(self): #实例方法,实例方法都带有self参数,调用时不用传入
print("Total Employee %d"%Employee.empCount)
def displayEmployee(self):
print("Name:",self.name,",Salary:",self.salary)
emp=Employee('Zara',4000) #创建类的实例对象
emp.displayCount()
emp.displayEmployee()
print ("Total Employee: %d"%Employee.empCount)
运行结果:
Total Employee 1
Name: Zara ,Salary: 4000
Total Employee: 1
class Animal(object):
def __init__(self,age,sex,weight):
# 实例变量
self.age=age
self.sex=sex
self.__weight=weight #私有变量在类中访问没有问题
def eat(self): #实例方法
self.__weight+=0.05
print('eat can add 0,05')
def run(self):#实例方法
self.__weight-=0.05
print('eat can ...')
anim=Animal(2,'femal',23)
print(anim.age,anim.sex,anim._Animal__weight) #私有变量在类外面的访问方法:_类名__私有变量名
anim.eat()
anim.run()
class Account:
#类变量,属于类,在java中叫静态变量,调用:类名.类变量名
interest_rate=0.0668
def __init__(self,owner,amout):
# 实例变量
self.owner=owner
self.amout=amout
#类方法,可以访问其他的类方法和类变量,不能访问实例变量和实例方法
@classmethod #@表示装饰器
def interest_by(cls,amt): #cls表示当前类,类方法不需要和实例绑定,要与当前类绑定,第一个参数是type类型,type是描述数据类型的类
print(type(cls))
return cls.interest_rate *amt #cls.interest_rate和Account.interest_rate
#实例方法
def jisuan(self): #self表示当前实例与该方法绑定在一起了
print('我是实例方法')
#静态方法,不用与类绑定,可以调用类变量,类方法,
@staticmethod
def interest_with(amt):
return Account.interest_by(amt)
account=Account('Navy',1000)
print(account.owner,account.amout)
account.jisuan()
print(account.interest_rate) #先到当前实例中去找,没找到去类中找
print(account.__dict__ ) #查看这个实例中的变量
account.interest_rate=0.00555 #相当于给实例增加了一个实例变量,可以通过这种方法创建实例变量,但是使用的人不知道,写在构造方法中更明白,
account.interest_rate1=0.00555#这样创建的实例变量,重新创建实例是没有的,只有构造方法中的实例变量才能同步到每个实例中
print(account.__dict__ )
print(Account.interest_rate) #类变量还是0.0668
print(account.interest_rate) #增加了一个实例变量0.00555
print(Account.interest_by(2000) ) #调用类方法:类名.类方法
print(Account.interest_with(3000))#掉用静态方法:类名.静态方法
执行结果:
2 femal 23
eat can add 0,05
eat can ...
Navy 1000
我是实例方法
0.0668
{'owner': 'Navy', 'amout': 1000}
{'owner': 'Navy', 'amout': 1000, 'interest_rate': 0.00555, 'interest_rate1': 0.00555}
0.0668
0.00555
<class 'type'>
133.6
<class 'type'>
200.4
2、类的继承:
(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): #Child子类继承Parent父类
def __init__(self):
print("子类构造函数")
def childMethod(self):
print("子类方法")
c = Child() # 实例化子类
c.childMethod() # 调用子类的方法
c.parentMethod() # 调用父类方法
c.setAttr(200) # 再次调用父类的方法 - 设置属性值
c.getAttr() # 再次调用父类的方法 - 获取属性值
运行结果:
子类构造函数
子类方法
父类方法
父类属性: 200
(2)多重继承的执行顺序:
class people:
name=''
age=0
_weight=0 #可以被类及其子类访问
def __init__(self,n,a,w):
self.name=n
self.age=a
self._weight=w
def speak(self):
print('%s 说:我 %d 岁,体重 %d 千克。'%(self.name,self.age,self._weight))
n=people('navy',15,50)
n.speak() #navy 说:我 15 岁,体重 50 千克。
class student(people):
grade=''
def __init__(self,n,a,w,g):
people.__init__(self,n,a,w)
self.grade=g
def speak(self):
print('%s 说:我 %d 岁,,体重 %d 千克,现在上%d年级' % (self.name, self.age,self._weight,self.grade))#,体重 %d 千克
m=student('Luc',15,36,5)
m.speak()#Luc 说:我 15 岁,,体重 36 千克现在上5年级
class speaker():
topic=''
name=''
def __init__(self,n,t):
self.nam=n
self.topic=t
def speak(self):
print("我叫%s,我是一个演说家,我演讲的主题是%s"%(self.name,self.topic))
class smple(speaker,student):
a=''
def __init__(self,n,a,w,g,t):
student.__init__(self,n,a,w,g)
speaker.__init__(self,n,t)
test=smple('Tim',25,45,4,'python')
test.speak() #我叫Tim,我是一个演说家,我演讲的主题是python(调用的是speaker类中的speak()方法)
class smple2(student,speaker):
a=''
def __init__(self,n,a,w,g,t):
student.__init__(self,n,a,w,g)
speaker.__init__(self,n,t)
test2=smple2('Tim',25,45,4,'python')
test2.speak() #Tim 说:我 25 岁,,体重 45 千克现在上4年级(调用的是student类中的speak()方法)
3、python中方法的重写和重载
先来看看概念:
重写:方法的名称和参数都必须相同,存在继承中,子类的构造函数就是对父类的构造函数的重写,还有其它同名同参数的方法
重载:方法名称相同,但是参数列表不相同(类型不同,数量不同,位置不同),python是动态语言,参数不需要申明
python的实现过程中可能存在重载,但是在Python的呈现使用中不存在重载的概念。
原因:python 可以接受任何类型的参数,而对那些缺少的参数设定为缺省参数即可解决问题。即,python中参数传递时候的*arg和**kwargs
4、单双下划下开头方法和变量
__foo__:以双下划线开头和结尾的方法称为魔法方法,魔法方法可以直接访问,如:__init__,__new__等之类的
_foo:以单下划线开头的表示是protected类型的变量,即保护类型只能允许其本身及其子类进行访问,不能用于from module import *
__foo:以双下划线开头的表示是private的变量,只能允许这个类本身进行访问
private变量的例子:
class people:
name=''
age=0
__weight=0
def __init__(self,n,a,w):
self.name=n
self.age=a
self.__weight=w
def speak(self):
print('%s 说:我 %d 岁,体重 %d 千克。'%(self.name,self.age,self.__weight))
n=people('navy',15,50)
n.speak() #navy 说:我 15 岁,体重 50 千克。
class student(people):
grade=''
def __init__(self,n,a,w,g):
people.__init__(self,n,a,w)
self.grade=g
def speak(self):
print('%s 说:我 %d 岁,,体重 %d 千克现在上%d年级' % (self.name, self.age,self.__weight,self.grade))#,体重 %d 千克
m=student('Luc',15,36,5)
m.speak() #报错:AttributeError: 'student' object has no attribute '_student__weight'
面向对象高级编程:
1、__slots__
正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性
class Student(object):
pass
#然后,尝试给实例绑定一个属性:
s=Student()
s.name='Michael'
print(s.name) #Michael
#还可以尝试给实例绑定一个方法:
def set_age(self,age):
self.age=age
from types import MethodType
s.set_age=MethodType(set_age,s)
s.set_age(25)
print(s.age) #25
#但是,给一个实例绑定的方法,对另一个实例是不起作用的:
s2=Student()
s2.set_age(26) #报错:AttributeError: 'Student' object has no attribute 'set_age'
#为了给所有实例都绑定方法,可以给class绑定方法:
class Student(object):
pass
s=Student()
s2=Student()
def set_score(self,score):
self.score=score
Student.set_score=set_score
s.set_score(100)
print(s.score)
s2.set_score(99)
print(s2.score)
如果我们想要限制实例的属性怎么办?比如,只允许对Student实例添加name
和age
属性。
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__
变量,来限制该class实例能添加的属性:
class Student(object):
__slots__ = ('name','age')
s=Student()
s.name='Michael'
s.age=25
#s.score=99 #报错,AttributeError: 'Student' object has no attribute 'score'
print(s.name,s.age)
由于'score'
没有被放到__slots__
中,所以不能绑定score
属性
使用__slots__
要注意,__slots__
定义的属性仅对当前类实例起作用,对继承的子类是不起作用的,除非在子类中也定义__slots__
,这样,子类实例允许定义的属性就是自身的__slots__
加上父类的__slots__
2、
@property
在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改:
class Student():
pass
s=Student()
s.score=9999
这显然不合逻辑。为了限制score的范围,可以通过一个set_score()
方法来设置成绩,再通过一个get_score()
来获取成绩,这样,在set_score()
方法里,就可以检查参数:
class Student(object):
def get_score(self):
return self._score
def set_score(self,value):
if not isinstance(value,int):
raise ValueError('score must be an integer!')
if value<0 or value>100:
raise ValueError('score must between 0~100!')
self._score=value
s=Student()
s.set_score(60)
print(s.get_score()) #60
s.set_score(9999)
print(s.get_score()) # raise ValueError('score must between 0~100!')
ValueError: score must between 0~100!
还记得装饰器(decorator)可以给函数动态加上功能吗?对于类的方法,装饰器一样起作用。Python内置的@property
装饰器就是负责把一个方法变成属性调用的:
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self,value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0~100!')
self._score=value
s=Student()
s.score=60
print(s.score) #60
s.score=7777
print(s.score) #报错:
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性:
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self,value):
self._birth=value
@property
def age(self):
return 2015-self._birth
ss=Student()
ss.birth=2013
print(ss.age) #2
print(ss.birth) #2013
ss.age=2 #报错:AttributeError: can't set attribute