python面向对象学习_Python学习之面向对象

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:

. . .

ContractedBlock.gif

ExpandedBlockStart.gif

在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为属性值

1429451-20180802140303174-1472602857.png

特殊的类属性

1429451-20180802140355044-2125492795.png

1429451-20180802140329361-684357170.png

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__

ContractedBlock.gif

ExpandedBlockStart.gif

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

类属性增删改查

ContractedBlock.gif

ExpandedBlockStart.gif

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'}

实例属性的增删改查

对象与实例属性的三个例子:

1429451-20180803090049832-1134755463.png

1429451-20180803090108085-1166233414.png

.调用要么是类,要么是实例,不加点的调用跟类和实例无关

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可以把一个实例方法变成其同名属性,以支持.号访问,它亦可标记设置限制,加以规范

ContractedBlock.gif

ExpandedBlockStart.gif

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'了),能够通过实例对象和类对象去访问。

ContractedBlock.gif

ExpandedBlockStart.gif

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

ContractedBlock.gif

ExpandedBlockStart.gif

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来进行修饰,静态方法不需要多定义参数

ContractedBlock.gif

ExpandedBlockStart.gif

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

ContractedBlock.gif

ExpandedBlockStart.gif

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 是类的工具包,不跟类绑定也不跟实例绑定,只是名义上的归属类管理,不能使用类变量和实例变量,既不能访问类属性也不能访问实例属性

组合: 做关联 ,小的组成大的

ContractedBlock.gif

ExpandedBlockStart.gif

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__)

组合

ContractedBlock.gif

ExpandedBlockStart.gif

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))

选课系统示例

ContractedBlock.gif

ExpandedBlockStart.gif

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序列化保存到文件里

ContractedBlock.gif

ExpandedBlockStart.gif

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()

示例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值