Python day 17 初始面向对象
楔子
1 def person(name,age,sex,job): 2 data = { 3 'name':name, 4 'age':age, 5 'sex':sex, 6 'job':job 7 } 8 9 return data 10 11 def dog(name,dog_type): 12 data = { 13 'name':name, 14 'type':dog_type 15 } 16 return data 17 18 人和狗的角色定制1
上面两个方法相当于造了两个模子,游戏里的每个人和每条狗都拥有相同里的属性。游戏开始,你根据一个人或一只狗传入的具体信息来塑造一个具体的人或者狗,怎么生成呢?
1 d1 = dog("李磊","京巴") 2 p1 = person("严帅",36,"F","运维") 3 p2 = person("egon",27,"F","Teacher")
两个角色对象生成了,狗和人还有不同的功能呀,狗会咬人,人会打狗,对不对? 怎么实现呢,。。想到了, 可以每个功能再写一个函数,想执行哪个功能,直接 调用 就可以了,对不?
1 def bark(d): 2 print("dog %s:wang.wang..wang..."%d['name']) 3 4 5 def walk(p): 6 print("person %s is walking..." %p['name'])<br><br>
1 walk(p1) 2 bark(d1)
上面的功能实现的简直是完美!
但是仔细玩耍一会,你就不小心干了下面这件事
1 p1 = person("严帅",36,"F","运维") 2 bark(p1) #把人的对象传给了狗的方法
事实 上,从你写的代码上来看,这并没出错。很显然,人是不能调用狗的功能的,但在你的程序例没有做限制,如何在代码级别实现这个限制呢?
1 def person(name,age,sex,job): 2 def walk(p): 3 print("person %s is walking..." % p['name']) 4 5 data = { 6 'name':name, 7 'age':age, 8 'sex':sex, 9 'job':job, 10 'walk':walk 11 } 12 13 return data 14 15 def dog(name,dog_type): 16 17 18 def bark(d): 19 print("dog %s:wang.wang..wang..."%d['name']) 20 data = { 21 'name':name, 22 'type':dog_type, 23 'bark':bark 24 } 25 26 return data
1 d1 = dog("李磊","京巴") 2 p1 = person("严帅",36,"F","运维") 3 p2 = person("egon",27,"F","Teacher")
1 d1['bark'](p1) #把人传给了狗的方法
你是如此的机智,这样就实现了限制人只能用人自己的功能啦。
刚刚你用的这种编程思想其实就是简单的面向对象编程,我们创造了两个模子表示游戏里所有的人和狗之后,剩下的狗叫或者人走对于这两个模子来说就不重要了。具体人he狗之间的交互就等着你去使用了。假如你和狗打起来了,这时候你是走路还是拿棍子打狗就由你自己决定了。那你的每一个决定可能都影响着你这场游戏的输赢。这也是不确定的。和我们之前写代码按部就班的走,最终都会实现我们要完成的事情不太一样了。
尽管如此,我们也只完成了这个游戏非常小的一部分。还有很多功能都没有实现。
刚才你只是阻止了两个完全 不同的角色 之前的功能混用, 但有没有可能 ,同一个种角色,但有些属性是不同的呢? 比如 ,大家都打过cs吧,cs里有警察和恐怖份子,但因为都 是人, 所以你写一个角色叫 person(), 警察和恐怖份子都 可以 互相射击,但警察不可以杀人质,恐怖分子可以,这怎么实现呢? 你想了说想,说,简单,只需要在杀人质的功能里加个判断,如果是警察,就不让杀不就ok了么。 没错, 这虽然 解决了杀人质的问题,但其实你会发现,警察和恐怖分子的区别还有很多,同时又有很多共性,如果 在每个区别处都 单独做判断,那得累死。
你想了想说, 那就直接写2个角色吧, 反正 这么多区别, 我的哥, 不能写两个角色呀,因为他们还有很多共性 , 写两个不同的角色,就代表 相同的功能 也要重写了,是不是我的哥? 。。。
好了, 话题就给你点到这, 再多说你的智商也理解不了了!
面向过程VS面向对象
面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的属性和方法),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙互相缠斗着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取。
面向对象的程序设计的
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。
在python 中面向对象的程序设计并不是全部。
面向对象编程可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
了解一些名词:类、对象、实例、实例化
类:具有相同特征的一类事物(人、狗、老虎)
对象/实例:具体的某一个事物(隔壁阿花、楼下旺财)
实例化:类——>对象的过程(这在生活中表现的不明显,我们在后面再慢慢解释)
初始类和对象
python中一切皆为对象,类型的本质就是类,所以,不管你信不信,你已经使用了很长时间的类了
1 >>> dict #类型dict就是类dict 2 <class 'dict'> 3 >>> d=dict(name='eva') #实例化 4 >>> d.pop('name') #向d发一条消息,执行d的方法pop 5 'eva'
从上面的例子来看,字典就是一类数据结构,我一说字典你就知道是那个用{}表示,里面由k-v键值对的东西,它还具有一些增删改查的方法。但是我一说字典你能知道字典里具体存了哪些内容么?不能,所以我们说对于一个类来说,它具有相同的特征属性和方法。
而具体的{'name':'eva'}这个字典,它是一个字典,可以使用字典的所有方法,并且里面有了具体的值,它就是字典的一个对象。对象就是已经实实在在存在的某一个具体的个体。
再举一个其他的例子,通俗一点,比如你现在有一个动物园,你想描述这个动物园,那么动物园里的每一种动物就是一个类,老虎、天鹅、鳄鱼、熊。他们都有相同的属性,比如身高体重出生时间和品种,还有各种动作,比如鳄鱼会游泳,天鹅会飞,老虎会跑,熊会吃。
但是这些老虎熊啥的都不是具体的某一只,而是一类动物。虽然他们都有身高体重,但是你却没有办法确定这个值是多少。如果这个时候给你一只具体的老虎,而你还没死,那你就能给他量量身高称称体重,这些数值是不是就变成具体的了?那么具体的这一只老虎就是一个具体的实例,也是一个对象。不止这一只,其实每一只具体的老虎都有自己的身高体重,那么每一只老虎都是老虎类的一个对象。
在python中,用变量表示特征,用函数表示技能,因而具有相同特征和技能的一类事物就是‘类’,对象是则是这一类事物中具体的一个。
类的相关知识
初始类
声明
1 def functionName(args): 2 '函数文档字符串' 3 函数体
1 class Person: #定义一个人类 2 role = 'person' #人的角色属性都是人 3 def walk(self): #人都可以走路,也就是有一个走路方法,也叫动态属性 4 print("person is walking...")
类有两种作用:属性引用和实例化
属性引用(类名.属性)
1 class Person: #定义一个人类 2 role = 'person' #人的角色属性都是人 3 def walk(self): #人都可以走路,也就是有一个走路方法 4 print("person is walking...") 5 6 7 print(Person.role) #查看人的role属性 8 print(Person.walk) #引用人的走路方法,注意,这里不是在调用
实例化:类名加括号就是实例化,会自动触发__init__函数的运行,可以用它来为每个实例定制自己的特征
1 class Person: #定义一个人类 2 role = 'person' #人的角色属性都是人 3 def walk(self): #人都可以走路,也就是有一个走路方法 4 print("person is walking...") 5 6 7 print(Person.role) #查看人的role属性 8 print(Person.walk) #引用人的走路方法,注意,这里不是在调用
实例化的过程就是类——>对象的过程
原本我们只有一个Person类,在这个过程中,产生了一个egg对象,有自己具体的名字、攻击力和生命值。
语法:对象名 = 类名(参数)
1 egg = Person('egon') #类名()就等于在执行Person.__init__() 2 #执行完__init__()就会返回一个对象。这个对象类似一个字典,存着属于这个人本身的一些属性和方法。 3 #你可以偷偷的理解:egg = {'name':'egon','walk':walk}
查看属性&调用方法
1 print(egg.name) #查看属性直接 对象名.属性名 2 print(egg.walk()) #调用方法,对象名.方法名()
关于self
self:在实例化时自动将对象/实例本身传给__init__的第一个参数,你也可以给他起个别的名字,但是正常人都不会这么做。
因为你瞎改别人就不认识
类属性的补充
1 一:我们定义的类的属性到底存到哪里了?有两种方式查看 2 dir(类名):查出的是一个名字列表 3 类名.__dict__:查出的是一个字典,key为属性名,value为属性值 4 5 二:特殊的类属性 6 类名.__name__# 类的名字(字符串) 7 类名.__doc__# 类的文档字符串 8 类名.__base__# 类的第一个父类(在讲继承时会讲) 9 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 10 类名.__dict__# 类的字典属性 11 类名.__module__# 类定义所在的模块 12 类名.__class__# 实例对应的类(仅新式类中) 13 14 类属性的补充
1 # 参加工作 2 # 游戏公司 3 # 人狗大战 4 # 角色 的属性固定下来 5 # 人 :昵称、性别、血、攻击力 6 # 狗 :名字、品种、血、攻击力 7 def Person(name,sex,hp,ad): 8 # 人模子 9 self = {'name': name, 'sex':sex, 'hp': hp, 'ad': ad} 10 def attack(dog): # 闭包 11 # 人攻击狗 12 print('%s攻击%s' % (self['name'], dog['name'])) 13 # 狗掉血,狗的血量-人的攻击力 14 dog['hp'] -= self['ad'] 15 self['attack'] = attack 16 return self 17 18 def Dog(name,kind,hp,ad): 19 # 狗模子 20 self = {'name': name, 'kind':kind, 'hp': hp, 'ad': ad} 21 def bite(person): 22 print('%s咬了%s' % (self['name'], person['name'])) 23 # 人掉血,人的血量-狗的攻击力 24 person['hp'] -= self['ad'] 25 if person['hp'] <= 0: print('game over,%s win' % self['name']) 26 def bite2():pass 27 self['bite'] = bite 28 self['bite2'] = bite2 29 return self 30 31 # 人 规范了属性的个数 简化了创造任务的代码 32 alex = Person('a_sb','不详',1,5) 33 boss_jin =Person('金老板','女',2,50) 34 35 # 狗 36 chen = Dog('旺财','teddy',50,20) 37 alex['attack'](chen) 38 print(chen['hp']) 39 40 # 面向对象编程 41 # 类的概念 : 具有相同属性和技能的一类事物 42 # 人类 抽象 43 # 对象 : 就是对一个类的具体的描述 44 # 具体的人 具体 45 46 # 使用面向对象的好处: 47 # 使得代码之间的角色关系更加明确 48 # 增强了代码的可扩展性 49 # 规范了对象的属性和技能 50 # 面向对象的特点:结局的不确定性 51 52 # 人类 53 # 狗类 54 55 # 购物 56 # 商品 :名字 类别 价格 产地 保质期 编号 57 # 苹果 生鲜类 5块钱 --- 对象 58 # 人 :
1 # class Person: 2 # role = 'person' # 静态属性 3 # def f1(self): # 动态属性 方法(函数) 默认带一个参数self 4 # print(1234567) 5 # 查看静态变量的第一种方式 6 # print(Person.__dict__) # 内置的双下方法 7 # print(Person.__dict__['静态变量']) 8 # Person.__dict__['静态变量'] = 456 # 报错 9 # print(Person.__dict__['静态变量']) 10 11 # 查看静态变量的第二种方式 12 # print(Person.静态变量) # 123 值 13 # print(Person.role) 14 # Person.静态变量 = 456 15 # print(Person.静态变量) 16 # del Person.静态变量 17 # print(Person.__dict__) 18 # 类名 19 # 引用静态变量 20 # 1.类名.__dict__['静态变量名'] 可以查看,但是不能删改 21 # 2.类名.静态变量名 直接就可以访问,可以删改 22 # 删除一个静态变量 del 类名.静态变量名 23 # 引用动态变量 24 # 1.类名.方法名 查看这个方法的内存地址 25 # 1.类名.方法名(实参) 调用了这个方法,必须传一个实参,这个实参传给了self 26 # 创造一个对象 - 实例化 27 # 产生一个实例(对象)的过程 28 # 对象 = 类名() 29 # alex = Person() # 创造一个对象 30 # alex 是对象、实例 31 # Person是类 32 # 对象 = 类名() 33 34 class Person: 35 role = 'person' # 静态属性 36 def __init__(self,name,sex,hp,ad): 37 self.name = name # 对象属性 属性 38 self.sex = sex 39 self.hp = hp 40 self.ad = ad 41 def attack(self): 42 print('%s发起了一次攻击'%self.name) 43 44 alex = Person('a_sb','不详',1,5) 45 boss_jin = Person('金老板','女',20,50) 46 47 alex.attack() # Person.attack(alex) 48 boss_jin.attack() # Person.attack(boss_jin) 49 50 51 52 53 54 # alex = Person('a_sb','不详',1,5) 55 # alex.__dict__['name'] = 'alex' 56 # print(alex.name) 57 # alex.name = 'a_sb' 58 # print(alex.name) 59 # boss_jin = Person('金老板','女',20,50) 60 # print(boss_jin.name) 61 # 实例化的过程: 62 # 1.创造一个实例,将会作为一个实际参数 # python 63 # 2.自动触发一个__init__的方法,并且把实例以参数的形式传递给__init__方法中的self形参 64 # 3.执行完__init__方法之后,会将self自动返回给alex 65 # __init__方法 :初始化方法,给一个对象添加一些基础属性的方法,一般情况下是针对self的赋值 66 # 对象 67 # 在类的内部 self是本类的一个对象 68 # 在类的外部,每一个对象都对应着一个名字,这个对象指向一个对象的内存空间 69 # 属性的调用: 70 # 对象名.属性名 第一种调用方法 71 # 对象名.__dict__['属性名'] 第二种调用方法 72 # 方法的调用 : 73 # 类名.方法名(对象名) # 那么方法中的self参数就指向这个对象 74 # 对象名.方法名() # 这样写 相当于 方法中的self参数直接指向这个对象

浙公网安备 33010602011771号