面向对象基础
目录:
基本概念
概要:
类和对象本质是名称空间 1. 什么是面向对象编程 核心是对象二字,对象是特征与技能的结合体,基于该思想编写程序就好比在 创造一个世界,世界是由一个个具体存在的对象组成的,你就是这个世界的上帝 这一种上帝式的思维方式 优点: 扩展性强 缺点: 编程的复杂度要高于面向过程 2. 类 对象是特征与技能的结合体,类则是一系列对象相同的特征与技能的结合体 在现实世界中,先有一个个具体存在的对象,然后随着人类文明的发展总结出的类 在程序中一定先定义类,后调用类来产生对象 3. 老男孩选课系统: 在现实世界中具体存在的对象 对象1: 特征 学校='Oldboy' 姓名='周铁蛋' 年龄=36 性别='男' 技能 选课 对象2: 特征 学校='Oldboy' 姓名='张铜蛋' 年龄=38 性别='女' 技能 选课 对象3: 特征 学校='Oldboy' 姓名='Egon' 年龄=18 性别='男' 等级=10 技能 打分 在现实世界中老男孩学生类 相似的特征 学校='Oldboy' 相似的技能 选课
4.类的用途:
类的用途一: 类本质就是一个名称空间,可以对该名称空间进行增删改查
print(OldboyStudent.__dict__)
print(OldboyStudent.__dict__['school'])#查看school属性
OldboyStudent.school #OldboyStudent.__dict__['school']
OldboyStudent.xxx=111 #OldboyStudent.__dict__['xxx']=111,添加属性
print(OldboyStudent.__dict__)
类的用途二: 调用类来产生对象
1. 会产生一个空对象obj
2. 会触发类中__init__方法,OldboyStudent.__init__(obj,)
5.一切皆为对象,在python3中统一了类与类型的概念(类型即为类)
class Foo:
pass
obj=Foo()
print(type(obj))#<class '__main__.Foo'>
l = [1,2,3]
print(type(list))#<class 'list'>
6.当拿到一个对象的时候,不仅拿到了对象的特有属性,还有类的属性以及类的功能函数
基本概念:
面向过程:
是一种编程思想,就是前辈程序员发现的一种比较号的编程方法 过程指的是 先干什么 再干什么,完成一个事情所有的具体步骤 优点:把复杂的问题流程化,简单化,降低开发难度 缺点:扩展差, 再当前这种情况下 用户需求千变万化 对扩展性要求非常高 使用场景:不需要扩展,或是对扩展性要求不高,例如linux内核,shell 脚本 案例: 把大象装进冰箱 需要几步 1.打开冰箱 2.装进大象 3.关闭冰箱 面向过程中我们关注的点是,完成这个任务,具体的步骤 一步一步去完成
面向对象:
一种编程思想 核心是对象 什么是对象:在现实生活中实实在在存在的,具备自己的特征和行为的事物 反过来说 对象就是 特征和行为(技能)的结合体 如何来区分:如果能够准确的找到一个事物,它就是一个对象 例如:某人的女朋友 面向对象编程:我们关注的点是.使用什么样的对象可以完成我的任务 例如:把大象装进冰箱,什么样的对象可以帮我完成这个任务,只要找到这个对象,命令它来做事情即可 你从一个操作者 变成了指挥者, 例如:西游记中的如来,他要完成一个传经,要把经书传到东土大唐取, 本来要自己去,但是太麻烦,所以找了唐僧师徒五个对象,来帮他完成这个任务 优势: 1.对于指挥者(程序员)来说,不需要再关心具体步骤 2.扩展性,一个单独的个体的特征或行为发生变化时 不会影响到别人 缺点: 1.程序的复杂度变高,你得需要设计这个些对象,注意要避免过度设计得问题 2.程序得执行结果可控性低
类与对象:
类就是分类 类型的意思
定义:一堆具备相同特征和行为的事物的抽象概念,不实际存在
先有类还是先有对象:
生活中:
生活中类怎么来的,是通过对象的特征和行为抽取而来,
所以是先有对象才有了类
编程中:
必须是先有类 才能有对象,因为你必须先告诉程序,你这个对象有什么样的特征和行为
类的作用:用于描述该类的对象具备什么样的特征和行为
定义类:
语法:class关键字 类名
类名规范:大写开头,驼峰命名法
class SHOldboyStudent: # 描述该类对象的特征 school = "上海Oldboy" name = "矮根" age = 68 gender = "unknown" # 在定义阶段 # 只要包含该类的py被执行 就会做两件事情 # 1.就会创建类的名称空间 # 2.执行代码 将产生的名称放入名称空间 print("========================")#可以执行 # 描述该类对象的行为 通过函数 def say_hi(abc): print(abc) print("hello oldBoy")
使用类中的属性:
print(SHOldboyStudent.__dict__)#查看名称空间 print(SHOldboyStudent.__dict__["name"])#矮根 print(SHOldboyStudent.name)#矮根
使用类中的函数:
print(SHOldboyStudent.__dict__["say_hi"]) #<function SHOldboyStudent.say_hi at 0x00000000021989D8> print(SHOldboyStudent.say_hi) #<function SHOldboyStudent.say_hi at 0x00000000021989D8> # 使用类直接调用类中函数时 与普通函数没有任何区别 位self仅仅是一个置参数 SHOldboyStudent.say_hi(10)# 10、hello oldboy
面向对象的使用:
定义类:
class OldboyStudent: # 如果每个对象的这个属性都相同 才应该定义到类中 比如所有人的学校都是上海Oldboy school = "上海Oldboy"
创建对象:
#语法: 在类名后加括号 与调用函数写法相同 stu = OldboyStudent() # 访问对象的属性 print(stu.school)#上海Oldboy print(OldboyStudent.school)#上海Oldboy
修改属性的值:
stu.school = "北京Oldboy" print(stu.school)#北京Oldboy
增加属性:
stu.room_num = "1008" print(stu.room_num)#1008
删除属性:
print(stu.__dict__)#{'school': '北京Oldboy', 'room_num': '1008'} del stu.room_num print(stu.__dict__)#{'school': '北京Oldboy'} # print(stu.room_num)报错,这个是对象的属性,删除之后就不能打印了
对象与类的名称空间是独立的:
stu.school = "深圳oldboy" # 为对象的属性赋予新的值 print(OldboyStudent.school) # 类中的属性不会变化 stu.room_num = "1008" # 为对象增加属性 # print(OldboyStudent.room_num) #报错,类中也不会出现新的属性 print(stu.__dict__) print(OldboyStudent.__dict__)
对象的属性查找顺序:
# 对象自己的名称空间 -> 类的名称空间 stu1 = OldboyStudent() stu1.school = "newSchool" print(stu1.school)#newSchool print(stu1)#<__main__.OldboyStudent object at 0x00000000021E7C50>
__init__函数:
__init__称之为初始化函数,它会在创建对象的时候自动执行
1.使用场景 需要为每个对象定制不同的属性值
2.__init__在创建对象后自动执行
3.第一个self参数 指的是这个对象本身 不需要手动传值
创建对象时
1.创建一个空对象
2.执行__init__函数 并且自动传入了这个对象
__init__函数演变过程:
1 # 原始代码 2 stu1.name='周铁蛋' 3 stu1.age=36 4 stu1.gender='male' 5 print(stu1.__dict__) 6 7 stu2.name='美男子' 8 stu2.age=18 9 stu2.gender='male' 10 print(stu2.__dict__) 11 12 stu3.name='张铜蛋' 13 stu3.age=18 14 stu3.gender='female' 15 print(stu3.__dict__) 16 17 # 简化代码 18 def init(obj,name,age,gender): 19 obj.name=name 20 obj.age=age 21 obj.gender=gender 22 23 init(stu1,'周铁蛋',36,'male') 24 init(stu2,'美男子',18,'male') 25 init(stu3,'张铜蛋',18,'female') 26 print(stu1.__dict__) 27 print(stu2.__dict__) 28 print(stu3.__dict__)
__init__函数作用:减少代码冗余
class Dog: # 作为一只狗 应该有 昵称 age color gender # 但是不能写到类中因为每个狗不一样 # name = "二哈" # 该函数的作用,就是为对象的属性赋初始值,不用在每次创建新对象时复杂传值,减少代码冗余 def __init__(self,name,color,age,gender): print("狗__init__执行了") print(self) self.name = name#将传入的name赋值给对象 self.age = age self.color = color self.gender = gender
#dog1 = Dog() #print(dog1) #dog1.name = "二黄" #dog1.age = "2" #dog1.color = "黄色" #dog1.gender = "female" 简化为:dog1 = Dog('大黄','黄色',2,'female')
#dog2 = Dog() #print(dog1) #dog2.name = "二哈" #dog2.age = "1" #dog2.color = "白色" #dog2.gender = "female"
简化为:dog2 = Dog('二哈','白色',3,'male')
绑定方法:
好处:可以拿到对象及类中的属性和功能
绑定方法是什么?
是对象与类中的某个函数的绑定关系,就像生活中,我们都会吃饭,我吃饭你不会饱
那么吃饭就是我自己的绑定方法
为什么要把函数进行绑定?
因为对象的行为,通常都需要访问这个对象的数据或是修改这个对象的数据
如果没有对象,直接调用函数是没有意义的,在函数中访问不到对象的数据
所以将对象和函数进行绑定
特殊之处:
在使用绑定方法时,不需要关心self参数,会自动将这个对象本身传进来
对象调用绑定方法时,最后执行的还是类中的那个函数
强调:绑定到对象的方法的特殊之处在于,绑定给谁就由谁来调用,谁来调用,
就会将‘谁’本身当做第一个参数传给方法,即自动传值(方法__init__也是一样的道理)
注意:绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self。
class Person: country = "China" def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def sleep(self): print("sleeping") print(self)#<__main__.Person object at 0x00000000027BC4A8> def eat(self): print("eating") p1 = Person("矮根",68,"female") p2 = Person("成伟",18,"female") # 类调用类中函数 与 对象调用的区别 p1.sleep() p2.sleep() print(Person.sleep)#函数<function Person.sleep at 0x00000000027B8A60> print(p1.sleep)#绑定方法<bound method Person.sleep of <__main__.Person object at 0x00000000027BC4A8>>
类调用与对象调用的区别:
对于类而言 sleep就是一个普通函数 对对象而言 sleep是一个绑定方法
类调用
Person.sleep(10)#需要严格按照函数进行传值
对象调用
p1.sleep()
面向对象1:
1 # 王者荣耀 对砍游戏 2 # 两个英雄可以对砍 如果血量小于等于0 就GG 3 # 所需的对象 4 # 英雄对象 5 """ 6 亚瑟 7 属性 8 类型 9 血量 10 名称 11 12 技能 13 Q 跳起来给你一刀 伤害50 14 W 给你一脚 30 15 E 大宝剑 100 16 17 妲己 18 属性 19 类型 20 血量 21 名称 22 23 技能 24 Q 给你一颗小心心 伤害10 25 W 给你一尾巴 30 26 E 色诱 100 27 28 """ 29 class Hero: 30 def __init__(self, hero_type, name, blood, q, w, e): 31 self.hero_type = hero_type 32 self.name = name 33 self.blood = blood 34 self.q = q 35 self.e = e 36 self.w = w 37 38 def Q(self, enemy): 39 print("%s 对 %s 释放 Q技能 造成%s伤害 对方血量剩余%s" % 40 (self.name, enemy.name, self.q, enemy.blood - self.q)) 41 # 敌方血减少 42 enemy.blood -= self.q 43 if enemy.blood <= 0: 44 print("hero %s GG" % enemy.name) 45 46 def W(self, enemy): 47 print("%s 对 %s 释放 W技能 造成%s伤害 对方血量剩余%s" % 48 (self.name, enemy.name, self.w, enemy.blood - self.w)) 49 # 敌方血减少 50 enemy.blood -= self.w 51 if enemy.blood <= 0: 52 print("hero %s GG" % enemy.name) 53 54 def E(self, enemy): 55 print("%s 对 %s 释放 E技能 造成%s伤害 对方血量剩余%s" % 56 (self.name, enemy.name, self.e, enemy.blood - self.e)) 57 # 敌方血减少 58 enemy.blood -= self.e 59 if enemy.blood <= 0: 60 print("hero %s GG" % enemy.name) 61 62 63 # 请选择你的英雄 64 yase = Hero("战士", "亚瑟", 200, 50, 30, 100) 65 66 daji = Hero("法师", "妲己", 150, 10, 30, 180) 67 68 # 妲己在草丛发现了路边亚瑟 69 # daji.Q(yase) 70 71 daji.E(yase) 72 yase.W(daji) 73 yase.E(daji) 74 yase.Q(daji) 75 # daji.W(yase)
面向对象2:
如下示例, 请用面向对象的形式优化以下代码在没有学习类这个概念时,数据与功能是分离的,如下 def exc1(host,port,db,charset): conn=connect(host,port,db,charset) conn.execute(sql) return xxx def exc2(host,port,db,charset,proc_name) conn=connect(host,port,db,charset) conn.call_proc(sql) return xxx # 每次调用都需要重复传入一堆参数 exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;') exc2('127.0.0.1',3306,'db1','utf8','存储过程的名字')
面向对象:
1 class Format: 2 def __init__(self,host,port,db,charset): 3 self.host = host 4 self.port = port 5 self.db = db 6 self.charset = charset 7 def exc1(self,sql): 8 conn = connect(self.host,self.port,self.db,self.charset)#得到对象,便得到了对象的属性,类的属性,以及功能函数 9 conn.execute(sql) 10 return XXX 11 12 def exc2(self, proc_name,sql) 13 conn = connect(self.host,self.port,self.db,self.charset)# 14 conn.call_proc(sql) 15 return xxx 16 obj = Format('127.0.0.1',3306,'db1','utf8',) 17 obj.exc1('select * from tb1;') 18 obj.exc2('存储过程的名字')