http://www.cnblogs.com/linhaifeng/articles/6182264.html
http://www.runoob.com/python3/python3-class.html
https://blog.csdn.net/dreamhua927/article/details/52461816
https://blog.csdn.net/qq_31780525/article/details/72639491
面向对象技术简介
类(Class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。(把一类事物的相同的特征和动作整合到一起就是类I,类是一个抽象的概念)
方法:类中定义的函数。
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
实例变量:定义在方法中的变量,只作用于当前实例的类。
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
实例化:创建一个类的实例,类的具体对象。
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。(就是基于类而创建的一一个具体的事物(具体存在的),也是特征和动作整合到一起)
和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。
Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
对象可以包含任意数量和类型的数据。
面向对象重要的概念就是类(Class)和实例(Instance),类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
先回顾下 OOP 的常用术语:
类:对具有相同数据和方法的一组对象的描述或定义。
对象:对象是一个类的实例。
实例(instance):一个对象的实例化实现。
实例属性(instance attribute):一个对象就是一组属性的集合。
实例方法(instance method):所有存取或者更新对象某个实例一条或者多条属性的函数的集合。
类属性(classattribute):属于一个类中所有对象的属性,不会只在某个实例上发生变化
类方法(classmethod):那些无须特定的对象实例就能够工作的从属于类的函数。
类定义
语法格式如下:
classClassName:
. . .
在Python中,定义类是通过class关键字,class后面紧接着是类名,类名规范是首字母大写如class Chinese
init方法的第一个参数永远是self,表示创建的实例本身,因此,在init方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
有了init方法,在创建实例的时候,就不能传入空的参数了,必须传入与init方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去,和普通的函数相比,在类中定义的对象函数(还有静态方法,类方法)只有一点不同,就是第一个参数永远是实例变量self,并且,调用时不用传递该参数。***对象属性
Python 中对象的属性包含对象的所有内容:方法和数据,注意方法也是对象的属性。查找对象的属性时,首先在对象的__dict__ 里面查找,然后是对象所属类的dict,再往后是继承体系中父类(MRO解析)的dict,任意一个地方查找到就终止查找,并且调用__getattribute__(也有可能是__getattr__) 方法获得属性值。***方法
在 Python 类中有3种方法,即静态方法(staticmethod),类方法(classmethod)和实例
对于实例方法,在类里每次定义实例方法的时候都需要指定实例(该方法的第一个参数,名字约定成俗为self)。这是因为实例方法的调用离不开实例,我们必须给函数传递一个实例。假设对象a具有实例方法 foo(self,*args, **kwargs),那么调用的时候可以用 a.foo(*args, **kwargs),或者 A.foo(a, *args, **kwargs),在解释器看来它们是完全一样的。
类方法每次定义的时候需要指定类(该方法的第一个参数,名字约定成俗为cls),调用时和实例方法类似需要指定一个类。
静态方法其实和普通的方法一样,只不过在调用的时候需要使用类或者实例。之所以需要静态方法,是因为有时候需要将一组逻辑上相关的函数放在一个类里面,便于组织代码结构。一般如果一个方法不需要用到self,那么它就适合用作静态方法。***数据属性:
通过内建函数dir(),或者访问类的字典属性__dict__,这两种方式都可以查看类或者实例有哪些属性。对于类数据属性和实例数据属性,可以总结为:
类数据属性属于类本身,可以通过类名进行访问/修改;
类数据属性也可以被类的所有实例访问/修改;
在类定义之后,可以通过类名动态添加类数据属性,新增的类属性也被类和所有实例共有;
实例数据属性只能通过实例访问;
在实例生成后,还可以动态添加实例数据属性,但是这些实例数据属性只属于该实例;
解释
类有两种属性:数据属性和函数属性
1. 类的数据属性是所有对象共享的
2. 类的函数属性是绑定给对象用的
查看类属性:dir(类名):查出的是一个名字列表
类名.__dict__:查出的是一个字典,key为属性名,value为属性值
特殊的类属性
class Music:
'这是一个音乐人的类'
dang='嘻哈'
def music():
print('good')
def listen(self):
print('nice')
#
# print(Music.dang)
# Chinese.music()
# Chinese.listen('哈哈')
#
# print(dir(Music)) #查出的是一个名字列表
# print(Music.__dict__) #查看属性字典
# print(Music.__dict__['dang']) #取出dang对应的value
# Music.__dict__['music']()
# Music.__dict__['listen'](1)
print(Music.__name__) #类名 : Music
print(Music.__doc__) #类的文档字符串 :这是一个音乐人的类
print(Music.__module__) #类所在的模块:__main__
1 #类属性增删改查
2 classChinese:3 country='China'
4 def __init__(self,name):5 self.name=name6
7 defplay_ball(self,ball):8 print('%s 正在打 %s' %(self.name))9 #查看
10 print(Chinese.country) #China
11
12 #修改
13 Chinese.country='Japan'
14 print(Chinese.country) #Japan
15
16 p1=Chinese('alex')17 print(p1.__dict__) #{'name': 'alex'}
18 print(p1.country) #Japan
19
20 #增加
21 Chinese.dang='党'
22 print(Chinese.dang) #党
23 print(p1.dang) #党
24
25 #删除
26 delChinese.dang27 delChinese.country28
29 print(Chinese.__dict__)30 print(Chinese.country)31
32
33 defeat_food(self,food):34 print('%s 正在吃%s' %(self.name,food))35
36 Chinese.eat=eat_food37
38 print(Chinese.__dict__)39 p1.eat('饭') #alex 正在吃饭
40
41
42 deftest(self):43 print('test')44
45 Chinese.play_ball=test46 p1.play_ball() #相当于Chinese.play_ball(p1):test
类属性增删改查
1 classChinese:2 country='China'
3 def __init__(self,name):4 self.name=name5
6 defplay_ball(self,ball):7 print('%s 正在打 %s' %(self.name,ball))8 p1=Chinese('alex')9 print(p1.__dict__) #{'name':alex}
10
11 #查看
12 print(p1.name) #alex
13 print(p1.play_ball) #>
14
15 #增加
16 p1.age=18
17 print(p1.__dict__) #{'name': 'alex', 'age': 18}
18 print(p1.age) #18
19
20 #不要修改底层的属性字典,虽可执行但不可取
21 #p1.__dict__['sex']='male'
22 #print(p1.__dict__) #{'name': 'alex', 'age': 18, 'sex': 'male'}
23 #print(p1.sex) #19
24
25 #修改
26 p1.age=19
27 print(p1.__dict__) #{'name': 'alex', 'age': 19}
28 print(p1.age) #19
29
30 #删除
31 delp1.age32 print(p1.__dict__) #{'name': 'alex'}
实例属性的增删改查
对象与实例属性的三个例子:
.调用要么是类,要么是实例,不加点的调用跟类和实例无关
init定义的都在实例字典里 class下定义的在类字典里
class Chinese:
country='China'
l=['a','b']
def __init__(self,name):
self.name=name
def play_ball(self,ball):
print('%s 正在打 %s' %(self.name,ball))
p1=Chinese('alex')
print(p1.l) --》['a', 'b']
p1.l=[1,2,3]
print(Chinese.l) --》['a', 'b']
print(p1.__dict__) --》{'name': 'alex', 'l': [1, 2, 3]}
p1.l.append('c') #这种增加值不会赋值到属性里,只是改变类下的变量l
print(p1.__dict__) --》{'name': 'alex'}
print(Chinese.l) --》['a', 'b', 'c']
静态属性@property
直接在__init__中定义公用属性,从封装性来说,它是不好的写法。
属性之访问,它亦有机制,其一便是@propery关键字。用此关键字,其获取、设置函数,须与属性名一致。
@property可以把一个实例方法变成其同名属性,以支持.号访问,它亦可标记设置限制,加以规范
1 classRoom:2 tag=1
3 def __init__(self,name,owner,width,length,heigh):4 self.name=name5 self.owner=owner6 self.width=width7 self.length=length8 self.heigh=heigh9 @property10 defcal_area(self):11 #print('%s 住的 %s 总面积是%s' % (self.owner,self.name, self.width * self.length))
12 return self.width *self.length13 deftest(self):14 print('from test',self.name)15 r1=Room('别墅','alex',100,100,100000)16 r2=Room('厂房','sally',1,1,1)17 ## print('%s 住的 %s 总面积是%s' %(r1.owner,r1.name,r1.width*r1.length))
18 ## print('%s 住的 %s 总面积是%s' %(r2.owner,r2.name,r2.width*r2.length))
19 r1.cal_area20 r2.cal_area21 print(r1.cal_area) #10000
22 print(r2.cal_area) #1
23 print(r1.name) #别墅
24 print(r2.name) #厂房
25
26 #@property好处是:封装逻辑,可以自己定制逻辑 用户调用时感知不到 像在调用一个普通属性一样
静态属性@property
类方法 @classmethod
是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大部分人都习惯以'cls'作为第一个参数的名字,就最好用'cls'了),能够通过实例对象和类对象去访问。
1 classRoom:2 tag=1
3 def __init__(self,name,owner,width,length,heigh):4 self.name=name5 self.owner=owner6 self.width=width7 self.length=length8 self.heigh=heigh9 @property10 defcal_area(self):11 #print('%s 住的 %s 总面积是%s' % (self.owner,self.name, self.width * self.length))
12 return self.width *self.length13 deftest(self):14 print('from test',self.name)15
16 @classmethod #专门供类使用的方法,类调用自己的方法
17 deftell_info(cls):18 print(cls)19 print('--》',cls.tag)20 #def tell_info(self):
21 #print('---->',self.tag)
22
23 r1=Room('别墅','alex',100,100,100000)24 Room.tell_info() --》
25 --》 1
@classmethod
1 classpeople:2 country = "china"
3
4 @classmethod5 defgetCountry(cls):6 returncls.country7
8
9 p =people()10 print(p.getCountry()) #实例对象调用类方法 china
11 print(people.getCountry()) #类对象调用类方法 china
12 #类方法还有一个用途就是可以对类属性进行修改:
13 classpeople:14 country = "china"
15 @classmethod16 defgetCountry(cls):17 returncls.country18 @classmethod19 defsetCountry(cls, country):20 cls.country =country21
22 p =people()23 print(p.getCountry()) #实例对象调用类方法 china
24 print(people.getCountry()) #类对象调用类方法 china
25
26 p.setCountry("Japan")27 print(p.getCountry()) #Japan
28 print(people.getCountry()) #Japan
类方法举例
静态方法@staticmethod
需要通过修饰器@staticmethod来进行修饰,静态方法不需要多定义参数
1 classRoom:2 tag=1
3 def __init__(self,name,owner,width,length,heigh):4 self.name=name5 self.owner=owner6 self.width=width7 self.length=length8 self.heigh=heigh9 @property10 defcal_area(self):11 #print('%s 住的 %s 总面积是%s' % (self.owner,self.name, self.width * self.length))
12 return self.width *self.length13 @classmethod14 deftell_info(cls,x):15 print(cls)16 print('--》',cls.tag,x)#print('--》',Room.tag)
17 #def tell_info(self):
18 #print('---->',self.tag)
19 @staticmethod #类的工具包:不跟类绑定也不跟实例绑定
20 defwash_body(a,b,c):21 print('%s %s %s正在洗澡' %(a,b,c))22 deftest(x,y):23 print(x,y)24 Room.wash_body('alex','yuan','wu') #alex yuan wu正在洗澡
25 #print(Room.__dict__)
26
27 r1=Room('别墅','alex',100,100,100000)28 #print(r1.__dict__)
29 #r1.wash_body('alex','yuanhao','wupeiqi')
30
31 Room.test(1,2) #1 2
32 r1.test(1,2) #无法调用报错
@staticmethod
1 classpeople3:2 country="china"
3
4 @staticmethod5 defgetCountry():6 returnpeople3.country7 p=people3()8 print(p.getCountry()) #实例对象调用类方法 china
9 print(people3.getCountry()) #类对象调用类方法 china
静态方法举例
总结:
@property跟实例绑定 (注:有self的都是跟实例绑定),既能访问类属性又能访问实例属性
@classmethod跟类绑定,能访问类属性不能访问实例属性
@staticmethod 是类的工具包,不跟类绑定也不跟实例绑定,只是名义上的归属类管理,不能使用类变量和实例变量,既不能访问类属性也不能访问实例属性
组合: 做关联 ,小的组成大的
1 classHand:2 pass
3 classFoot:4 pass
5 classTrunk:6 pass
7 classHead:8 pass
9
10 classPerson:11 def __init__(self,id_num,name):12 self.id_num=id_num13 self.name=name14 self.hand=Hand()15 self.foot=Foot()16 self.trunk=Trunk()17 self.head=Head()18 p1=Person('111111','alex')19 print(p1.__dict__)
组合
1 classSchool:2 def __init__(self,name,addr):3 self.name=name4 self.addr=addr5
6
7 defzhao_sheng(self):8 print('%s 正在招生' %self.name)9
10 classCourse:11 def __init__(self,name,price,period,school):12 self.name=name13 self.price=price14 self.period=period15 self.school=school16 s1=School('oldboy','北京')17 s2=School('oldboy','南京')18 s3=School('oldboy','东京')19
20 #c1=Course('linux',10,'1h','oldboy 北京')
21 #c1=Course('linux',10,'1h',s1)
22
23 msg='''
24 1 老男孩 北京校区25 2 老男孩 南京校区26 3 老男孩 东京校区27 '''
28 whileTrue:29 print(msg)30 menu={31 '1':s1,32 '2':s2,33 '3':s334 }35 choice=input('选择学校>>:')36 school_obj=menu[choice]37 name=input('课程名>>:')38 price=input('课程费用>>:')39 period=input('课程周期>>:')40 new_course=Course(name,price,period,school_obj)41 print('课程【%s】属于【%s】学校' %(new_course.name,new_course.school.name))
选课系统示例
1 classSchool:2 def __init__(self,name,addr):3 self.name=name4 self.addr=addr5 self.course_list=[]6 defzhao_sheng(self):7 print('%s 正在招生' %self.name)8 classCourse:9 def __init__(self,name,price,period):10 self.name=name11 self.price=price12 self.period=period13
14 s1=School('oldboy','北京')15 s2=School('oldboy','南京')16 s3=School('oldboy','东京')17
18 c1=Course('linux',10,'1h')19 c2=Course('python',10,'1h')20
21 s1.course_list.append(c1)22 s1.course_list.append(c2)23 print(s1.__dict__)24
25 for course_obj ins1.course_list:26 print(course_obj.name,course_obj.price) #linux 10
27 #python 10
比较low的关联方式
l练习题:角色:学校、学员、课程、讲师
要求:
1. 创建北京、上海2所学校
2. 创建1inux ,python. , go 3个课程, linux\py在北京开,
3. 课程包含周期, 价格
4. 班级关联课程、讲师
5. 创建学员时,选择学校,关联班级
6. 创建讲师角色时要关联学校,
7..上.面的操作产生的数据都通过pickle序列化保存到文件里
1 importpickle2 importhashlib3 importtime4 defcreate_md5():5 m =hashlib.md5()6 m.update(str(time.time()).encode('utf-8'))7 returnm.hexdigest()8 id=create_md5()9 time.sleep(1)10 id1=create_md5()11 time.sleep(1)12 id2=create_md5()13 print(id)14 print(id1)15 print(id2)16
17 classBase:18 defsave(self):19 with open('school.db','wb') as f:20 pickle.dump(self,f)21 #利用id关联学校,课程
22 classSchool(Base):23 def __init__(self,name,addr):24 self.id=create_md5()25 self.name=name26 self.addr=addr27
28 classCourse(Base):29 def __init__(self,name,price,period,school):30 self.id=create_md5()31 self.name=name32 self.price=price33 self.period=period34 self.school=school35
36 school_obj = pickle.load(open('school.db', 'rb'))37 print(school_obj.name,school_obj.addr)38 s1=School('oldboy','北京')39 s1.save()
示例