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):那些无须特定的对象实例就能够工作的从属于类的函数。

类定义

语法格式如下:

class ClassName:
  <statement-1>
  . . .
   <statement-N>
在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 class Chinese:
 3     country='China'
 4     def __init__(self,name):
 5         self.name=name
 6 
 7     def play_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 del Chinese.dang
27 del Chinese.country
28 
29 print(Chinese.__dict__)
30 print(Chinese.country)
31 
32 
33 def eat_food(self,food):
34     print('%s 正在吃%s' %(self.name,food))
35 
36 Chinese.eat=eat_food
37 
38 print(Chinese.__dict__)
39 p1.eat('')          #alex 正在吃饭
40 
41 
42 def test(self):
43     print('test')
44 
45 Chinese.play_ball=test
46 p1.play_ball()  # 相当于Chinese.play_ball(p1):test
类属性增删改查
 1 class Chinese:
 2     country='China'
 3     def __init__(self,name):
 4         self.name=name
 5 
 6     def play_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)  #<bound method Chinese.play_ball of <__main__.Chinese object at 0x0000006475C11EB8>>
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 del p1.age
32 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 class Room:
 2     tag=1
 3     def __init__(self,name,owner,width,length,heigh):
 4         self.name=name
 5         self.owner=owner
 6         self.width=width
 7         self.length=length
 8         self.heigh=heigh
 9     @property
10     def cal_area(self):
11         # print('%s 住的 %s 总面积是%s' % (self.owner,self.name, self.width * self.length))
12         return  self.width * self.length
13     def test(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_area
20 r2.cal_area
21 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 class Room:
 2     tag=1
 3     def __init__(self,name,owner,width,length,heigh):
 4         self.name=name
 5         self.owner=owner
 6         self.width=width
 7         self.length=length
 8         self.heigh=heigh
 9     @property
10     def cal_area(self):
11         # print('%s 住的 %s 总面积是%s' % (self.owner,self.name, self.width * self.length))
12         return  self.width * self.length
13     def test(self):
14         print('from test',self.name)
15 
16     @classmethod           #专门供类使用的方法,类调用自己的方法
17     def tell_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()      --》<class '__main__.Room'>
25                            --》 1
@classmethod
 1 class people:
 2     country = "china"
 3 
 4     @classmethod
 5     def getCountry(cls):
 6         return cls.country
 7 
 8 
 9 p = people()
10 print(p.getCountry())  # 实例对象调用类方法   china
11 print(people.getCountry())  # 类对象调用类方法  china
12 #类方法还有一个用途就是可以对类属性进行修改:
13 class people:
14     country = "china"
15     @classmethod
16     def getCountry(cls):
17         return cls.country
18     @classmethod
19     def setCountry(cls, country):
20         cls.country = country
21 
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 class Room:
 2     tag=1
 3     def __init__(self,name,owner,width,length,heigh):
 4         self.name=name
 5         self.owner=owner
 6         self.width=width
 7         self.length=length
 8         self.heigh=heigh
 9     @property
10     def cal_area(self):
11         # print('%s 住的 %s 总面积是%s' % (self.owner,self.name, self.width * self.length))
12         return  self.width * self.length
13     @classmethod
14     def tell_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     def wash_body(a,b,c):
21         print('%s %s %s正在洗澡' %(a,b,c))
22     def test(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 class people3:
2     country="china"
3  
4     @staticmethod
5     def getCountry():
6         return people3.country
7 p=people3()
8 print(p.getCountry())   #实例对象调用类方法     china
9 print(people3.getCountry())  #类对象调用类方法   china
静态方法举例

总结:

@property跟实例绑定 (注:有self的都是跟实例绑定),既能访问类属性又能访问实例属性
@classmethod跟类绑定,能访问类属性不能访问实例属性
@staticmethod 是类的工具包,不跟类绑定也不跟实例绑定,只是名义上的归属类管理,不能使用类变量和实例变量,既不能访问类属性也不能访问实例属性

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

 1 class Hand:
 2     pass
 3 class Foot:
 4     pass
 5 class Trunk:
 6     pass
 7 class Head:
 8     pass
 9 
10 class Person:
11     def __init__(self,id_num,name):
12         self.id_num=id_num
13         self.name=name
14         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 class School:
 2     def __init__(self,name,addr):
 3         self.name=name
 4         self.addr=addr
 5 
 6 
 7     def zhao_sheng(self):
 8         print('%s 正在招生' %self.name)
 9 
10 class Course:
11     def __init__(self,name,price,period,school):
12         self.name=name
13         self.price=price
14         self.period=period
15         self.school=school
16 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 while True:
29     print(msg)
30     menu={
31         '1':s1,
32         '2':s2,
33         '3':s3
34     }
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 class School:
 2     def __init__(self,name,addr):
 3         self.name=name
 4         self.addr=addr
 5         self.course_list=[]
 6     def zhao_sheng(self):
 7         print('%s 正在招生' %self.name)
 8 class Course:
 9     def __init__(self,name,price,period):
10         self.name=name
11         self.price=price
12         self.period=period
13 
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 in s1.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 import pickle
 2 import hashlib
 3 import time
 4 def create_md5():
 5     m = hashlib.md5()
 6     m.update(str(time.time()).encode('utf-8'))
 7     return  m.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 class Base:
18     def save(self):
19         with open('school.db','wb') as f:
20             pickle.dump(self,f)
21 #利用id关联学校,课程
22 class School(Base):
23     def __init__(self,name,addr):
24         self.id=create_md5()
25         self.name=name
26         self.addr=addr
27 
28 class Course(Base):
29     def __init__(self,name,price,period,school):
30         self.id=create_md5()
31         self.name=name
32         self.price=price
33         self.period=period
34         self.school=school
35 
36 school_obj = pickle.load(open('school.db', 'rb'))
37 print(school_obj.name,school_obj.addr)
38 s1=School('oldboy','北京')
39 s1.save()
示例

 

 

 

 

 

  

posted @ 2018-08-02 09:58  一只小妖  阅读(123)  评论(0)    收藏  举报