#什么是对象 面向对象是一种编程思想,是指导程序员如何编写出更好的程序的思想 核心是对象,程序就是一系列对象的集合,咱们程序员只须要调度、控制这些对象来交互完成工做 #案例1,把对象装进冰箱 面向过程: 1.打开冰箱 2.装入冰箱 3.关闭冰箱 面向对象: 找个具有装大象的技能的对象 在面向对象中,程序员的角度发生改变,从具体的操做者变成了指挥者 强调:对象不是凭空产生的,须要咱们本身设计 #案例2,西天取经 面向过程: 如来找5我的,经历九九八十一难来取经,在把经书送回去 面向对象: 如来只须要找5个对象,本身负责调度便可,若是某个对象发生变化,也不会影响其余对象的扩展性 #案例3, 面向过程: 曹操吟诗 喝酒吃肉,人生真爽 后改成 喝酒吃肉,人生几何 后改成 对酒当歌,人生几何 面向对象: 把字拆成一个个对象,用的时候组装 优势: 1.扩展性强 2.灵活性强 3.重用性强 缺点: 1.程序的复杂度提升了 2.没法准确预知结果 #使用场景 1.对扩展性要求较高的程序,一般是直接面向用户的(QQ、微信) #不是全部的程序都要面向对象,要分析具体的需求
#面向过程 面向过程关注的是过程,就是先干什么、后干什么 #优势 逻辑清晰,能够将复杂的问题简单化、流程化 #缺点 扩展性差,可维护性差,重用性低 #使用场景 1.对扩展性要求较低的程序,好比系统内核、git、计算器
#类和对象 类和对象是面向对象编程的最核心的两个概念
#类 类就是类型、类别,类就是一个抽象的概念 类是一系列具有相同特征和相同行为的对象的集合
#对象 对象就是具体存在的某个事物,有本身的特征和行为 #类和对象的关系 类包含一系列对象 一个对象属于某个类 #先有类,仍是先有对象 生活中,是先有对象,而后有类 程序中,先有类,才能有对象,咱们必须先告诉计算机这类对象有什么特征、有什么行为(也就是说要先建立类) 因此说,在使用面向对象编程时,第一步就是考虑须要使用什么对象,再考虑使用什么类,而后,先建立类,再建立对象
#建立类 #语法 class 类的名字: #注释 #类中的内容,描述属性和技能 #描述属性用变量 #描述行为用函数 #类的名字 1.见名知意 2.大驼峰(单词的首字母大写) #建立类 #一个类,使用类名+()能够建立多个不一样的对象 class Student: pass #建立对象(类名加括号) print(Student) #<class类 '__main__.Student'> res = Student() print(res) #<__main__.Student object对象 at 0x000001CBB06AFA90> print(res.__class__.__name__) #Student print(res.__dict__) #{} #类中的属性能够被任何一个对象访问,因此类中存放的应该是对象的公共属性 class Person: name = '张三丰' age = 2000 sex = 'male' res = Person() print(res) print(res.name) print(res.age) print(res.sex) <__main__.Person object at 0x00000138EAA9A940> 张三丰 2000 male #能够为对象单独设置属性 #属性的查找顺序为,先查找对象,再查找类 class Person: eat = '会吃饭' run = '会跑路' zhangsan = Person() zhangsan.eat = '不会吃饭' lisi = Person() lisi.run = '不会跑路' print(zhangsan.eat) print(zhangsan.run) print(lisi.eat) print(lisi.run) 不会吃饭 会跑路 会吃饭 不会跑路 #对象的精髓就在于将数据和处理数据的函数整合到一块儿,这样以来,当拿到一个对象,就同时拿处处理的数据和处理数据的函数 #在类和对象中,属性(数据)用变量表示,方法用函数表示 #属性、方法也能够统一称为属性,分为数据属性、函数属性 class Student: school = '清华' def __init__(self,name,age): self.name = name self.age = age def study(self): print('hello i am a student, my name is:%s'%self.school) t1 = Student('syy',18) print(type(t1.study)) print(type(Student.study)) <class 'method'> #方法 <class 'function'> #函数
#类 #增长类的属性 新建一个类(覆盖) #对象 #增长对象的属性 对象变量名.属性名称 = 属性值 #删除对象的属性 del 对象变量名.属性名称 #修改对象的属性 对象变量名.属性名称 = 新的属性值 #查看对象的属性(专属属性) #不管是查看类的属性仍是查找对象的属性,都是使用__dict__ #查看对象的类,使用__class__ class Person: eat = '会吃饭' run = '会跑路' print(Person.__dict__) #类的属性 res = Person() print(res) #没有专属属性的对象 print(res.__dict__) print(res.__class__) #对象的类信息 zhangsan = Person() zhangsan.eat = '不会吃饭' print(zhangsan.__dict__) #有专属属性的对象 print(zhangsan.__class__) #对象的类信息 {'__module__模块名称': '__main__', 'eat': '会吃饭', 'run': '会跑路', '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>, '__doc__注释': None} <__main__.Person object at 0x000001C11D14A9E8> {} <class '__main__.Person'> {'eat': '不会吃饭'} <class '__main__.Person'>
#使用类产生对象1 class Teacher: school = '清华' t1 = Teacher() t1.name = 'tom' t1.age = 19 t2 = Teacher() t2.name = 'jerry' t2.age = 20 t3 = Teacher() t3.name = 'syy' t3.age = 21 print(t1.name) print(t2.name) print(t3.name) #使用类产生对象2,使用函数封装重复代码 class Teacher: school = '清华' def init(obj,name,age): obj.name = name obj.age = age t1 = Teacher() t2 = Teacher() t3 = Teacher() init(t1,'tom',19) init(t2,'jerry',19) init(t3,'syy',19) print(t1.name) print(t2.name) print(t3.name)
#使用类产生对象3,使用__init__方法 #self就是生成的对应的对象 #使用__init__定义的变量,就是对象的专属属性(__init__的做用就是给对象附初始值) #函数名必须是__init__,__init__函数不能使用return返回值 #调用函数的时候,注意变量的个数要对应类体内的变量的个数(少一个),缘由在于,调用函数的时候会将对象自己做为第一个参数 #当需求是在建立对象时还须要作掉别的事,那就应该想到对象的初始化 class Teacher: school = '清华' def __init__(self): print(self) t1 = Teacher() print(t1) <__main__.Teacher object at 0x000002C04478F908> <__main__.Teacher object at 0x000002C04478F908> class Teacher: school = '清华' def __init__(self,name,age): self.name = name self.age = age t1 = Teacher('tom',19) t2 = Teacher('jerry',20) t3 = Teacher('syy',21) print(t1,t2,t3) print(t1.name,t2.name,t3.name) <__main__.Teacher object at 0x0000022248F15A90> <__main__.Teacher object at 0x0000022248F15BA8> <__main__.Teacher object at 0x0000022248F159B0> tom jerry syy
#使用locals()初始化对象 #locals(),是一个字典,表示当前名称空间中全部的变量名 class Hero: def __init__(self,name,level,blood,attach,q_hurt,w_hurt,e_hurt): # self.name = name # self.level = level # self.blood = blood # self.attach = attach # self.q_hurt = q_hurt # self.w_hurt = w_hurt # self.e_hurt = e_hurt lcs = locals() lcs.pop('self') self.__dict__.update(lcs) s1 = Hero(1,2,3,4,5,6,7) print(s1.__dict__) {'e_hurt': 7, 'w_hurt': 6, 'q_hurt': 5, 'attach': 4, 'blood': 3, 'level': 2, 'name': 1}
#对象绑定方法 #不使用装饰器的前提下,类中的方法(函数),都是对象绑定方法 #使用类生成对象,经过对象能够调用别的方法(函数体代码) #一个类里面能够有多个函数,可是一个类同时只能生成一个对象 #只要一辈子成对象,类中的代码就会运行,可是不会运行除了__init__别的函数体代码 #别的函数体代码只会在调用的时候运行 class Student: school = '清华' def __init__(self,name,age): self.name = name self.age = age print(self) def study(self): print('hello i am a student, my name is:%s'%self.name) t1 = Student('syy',18) t2 = Student('tom',19) print(t1.study()) #不须要传参,自动将该对象当作第一个参数传入 print(t2.study()) <__main__.Student object at 0x000002842EECAA20> <__main__.Student object at 0x000002842EEDE978> hello i am a student, my name is:syy None hello i am a student, my name is:tom None #使用对象调用方法和使用类调用方法的行为不一样 #使用对象调用方法,有几个参数就传几个参数 #使用类名调用方法,该方法就是一个普通函数 class Student: school = '清华' def __init__(self,name,age): self.name = name self.age = age def study(self): print('hello i am a student, my name is:%s'%self.name) t1 = Student('syy',18) t1.study() #使用对象调用方法 Student.study(t1) #使用类名调用方法 hello i am a student, my name is:syy hello i am a student, my name is:syy #练习 #写一个学生类,具有一个打招呼的技能,要能输出本身的名字信息 class Student: def __init__(self,name): self.name = name def say_hi(self): print('my name is %s'%self.name) s1 = Student('syy') s1.say_hi() my name is syy
# class Student: school = '清华' def __init__(self,name,age): self.name = name self.age = age def study(self): print(self.school) t1 = Student('syy',18) print(Student.school) #访问类 print(t1.school) #访问对象 Student.study(t1) #访问类中的函数(须要传入一个对象) t1.study() #类的绑定方法 #使用装饰器@classmethod装饰 #无论是用类仍是对象调用,都会自动传入类自己,做为第一个参数 class Student: school = '清华' def __init__(self,name,age): self.name = name self.age = age @classmethod def study(cls): print(cls.school) t1 = Student('syy',18) print(Student.school) print(t1.school) Student.study() #访问类中的函数(不须要传参数) t1.study() #何时绑定给对象 #当函数逻辑须要访问对象中的数据时 #何时绑定给类 #当函数逻辑须要访问类中的数据时
#非绑定方法或叫作静态方法 #使用装饰器@staticmethod #即类既不绑定对象self,也不绑定类cls #该方法定义函数与类体外定义函数结果相同 class Student: school = '清华' def __init__(self,name,age): self.name = name self.age = age @staticmethod def study(): print('hello') t1 = Student('syy',18) Student.study() #使用类访问方法 t1.study() #使用对象访问方法 #实例 #为学生类添加一个save方法,一个get方法 #save是将对象存储到文件中(对象绑定方法) #get是从你文件中获取对象(非绑定方法) import pickle class Student: def __init__(self,name): self.name = name def save(self): with open(self.name,'wb') as f: pickle.dump(self,f) @staticmethod def get(name): with open(name,'rb') as f: obj = pickle.load(f) return obj s1 = Student('syy') s1.save() obj = Student.get('syy') print(obj.name) #当类中的函数须要使用self或者__init__中定义的变量,那么这个函数就是对象绑定 #当类中的函数须要使用类中定义的变量,那么这个函数就是类绑定方法,可使用装饰器classmethod修饰 #当类中的函数既不须要使用类中定义的变量,又不须要使用__init__中定义的变量,那么这个对象就是非绑定方法
参考网站html
import random import time class Hero: def __init__(self,name,level,blood,att,Q_hurt,W_hurt,E_hurt): lcs = locals() lcs.pop('self') self.__dict__.update(lcs) def attack(self,enemy): enemy.blood -= self.att print('%s对%s释放了普通攻击,形成了%s的伤害,敌人剩余血量%s'%(self.name,enemy.name,self.att,enemy.blood)) if enemy.blood <= 0: print('%s被%s使用普通攻击击杀!'%(enemy.name,self.name)) def Q(self,enemy): enemy.blood -= self.Q_hurt print('%s对%s释放了Q技能,形成了%s的伤害,敌人剩余血量%s'%(self.name,enemy.name,self.Q_hurt,enemy.blood)) if enemy.blood <= 0: print('%s被%s使用Q技能击杀!'%(enemy.name,self.name)) def W(self,enemy): enemy.blood -= self.W_hurt print('%s对%s释放了W技能,形成了%s的伤害,敌人剩余血量%s'%(self.name,enemy.name,self.W_hurt,enemy.blood)) if enemy.blood <= 0: print("%s被%s使用W技能击杀!" % (enemy.name, self.name)) def E(self,enemy): enemy.blood -= self.E_hurt print('%s对%s释放了E技能,形成了%s的伤害,敌人剩余血量%s'%(self.name,enemy.name,self.E_hurt,enemy.blood)) if enemy.blood <= 0: print('%s被%s使用E技能击杀!'%(enemy.name,self.name)) #定义英雄 h1 = Hero('亚索',level=1,blood=50000,att=500,Q_hurt=600,W_hurt=1000,E_hurt=2000) h2 = Hero('妲己',level=2,blood=3000,att=600,Q_hurt=700,W_hurt=1000,E_hurt=2000) h3 = Hero('鲁班',level=3,blood=3000,att=700,Q_hurt=800,W_hurt=1500,E_hurt=2000) h4 = Hero('蔡文姬',level=4,blood=5000,att=100,Q_hurt=200,W_hurt=300,E_hurt=400) # h1.attack(h2) # h2.Q(h1) # h2.W(h1) # h2.E(h1) while True: #把全部的攻击方法装到字典,为了随机取出一个 funcs = {1:Hero.Q,2:Hero.W,3:Hero.E,4:Hero.attack} func_index = random.randint(1,len(funcs)) func = funcs[func_index] #把全部英雄装到字典,为了随机取出一个 heros = {1:h1,2:h2,3:h3,4:h4} hero_index = random.randint(1,len(heros)) hero = heros[hero_index] #剩余的英雄们 other_heros = {} new_index = 1 for k,v in heros.items(): if k != hero_index: other_heros[new_index] = v new_index +=1 #从剩余的英雄中随机跳出一个英雄来挨打 enemy_index = random.randint(1,len(other_heros)) enemy = other_heros[enemy_index] #打他 func(hero,enemy) if enemy.blood <=0: break time.sleep(1)
#什么是继承 继承是一种关系,描述两个类之间的关系 在程序中,继承描述的是类和类之间的关系(父类、基类、子类) 在python中,一个子类能够同时继承多个父类,使用逗号分开 #为何要使用继承 继承的一方能够直接使用被继承一方已经有的东西 继承的做用就是重用已经有的代码,提升重用性 #如何使用继承 #语法 class 类名称(父类的名称): pass #例 class Base: desc = '这是一个基类' def show_info(self): print(self.desc) def make_money(self): print('一天赚它一个亿') class Subclass(Base): pass # def make_money(self): # print('一天赚它一百块') obj = Subclass() obj.make_money() print(obj.desc) 一天赚它一个亿 这是一个基类
#原始代码 class Teacher: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def say_hi(self): print('name:%s,age:%s,gender:%s'%(self.name,self.age,self.gender)) class Student: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def say_hi(self): print('name:%s,age:%s,gender:%s'%(self.name,self.age,self.gender)) t1 = Teacher('syy','male',20) t1.say_hi() stu1 = Student('dog','female',2) stu1.say_hi() #抽象 #生活中,抽象是指不具体、不清晰、很模糊、看不懂,形容词 #程序中,抽象是动词 #将多个不一样的子类中相同的部分进行抽取,造成一个新的类,这个过程叫抽象 #先抽象再继承 #继承一个已经存在的类,能够扩展或是修改原始的功能 class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def say_hi(self): print('name:%s,age:%s,gender:%s'%(self.name,self.age,self.gender)) class Teacher(Person): def teacher(self): print('老师专属...') class Student(Person): pass t1 = Teacher('syy','male',20) t1.say_hi() stu1 = Student('dog','female',2) stu1.say_hi()
#属性查找顺序 对象 > 子类 > 父类 class A: a = 1 class B(A): b = 2 def __init__(self,c): self.c = c class C(B): pass class D(C): pass t = B(3) print(t.b) #2 print(t.a) #1 print(t.c) #3 print(D.mro()) #全部父类名,按继承顺序排列,[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
#派生 当一个子类中出现了与父类中不一样的内容时,这个子类就称之为派生类 一般子类都会写一些新的代码,不可能和父类彻底同样,因此,子类一般都是派生类 #覆盖 覆盖也称之为overwrite 当子类出现了与父类彻底一致(名字一致)的属性和方法时,父类中的属性和方法被子类覆盖 #派生与覆盖 class Person: def say_hi(self): print('hello person') class Student(Person): def say_hi(self): print('hello student') stu = Student() print(stu.say_hi()) #例 实现一个能够限制元素类型的列表 #子类中访问父类的内容使用关键字super class Mylist(list): def __init__(self,element_type): #先继承父类,后自定义子类的初始化 super().__init__() #element_type: 指定的数据类型 self.element_type = element_type def append(self,object): #object: 要存储的元素 if type(object) == self.element_type: #在这里访问父类的append函数 super(Mylist,self).append(object) else: print('sorry,you element type not is %s'%self.element_type) m = Mylist(str) m.append('壹') print(m[0])
参考网站python
#python2中的supper class Parent: test = 'abc' def say_something(self): print('anything') class Sub(Parent): def show_info(self): print(super(Sub,self).test) super(Sub, self).say_something() sub = Sub() sub.show_info() #python3中的supper class Parent: test = 'abc' def say_something(self): print('anything') class Sub(Parent): def show_info(self): print(super().test) super().say_something() sub = Sub() sub.show_info() #使用类名称,与继承无关 class Parent: test = 'abc' def say_something(self): print('anything') class Sub(Parent): def show_info(self): print(Parent.test) Parent.say_something(self) sub = Sub() sub.show_info() #参考 class Animal: # 定义一个父类 def __init__(self): # 父类的初始化 self.name = 'animal' self.role = 'parent' print('I am father') class Dog(Animal): # 定一个继承Animal的子类 def __init__(self): # 子类的初始化函数,此时会覆盖父类Animal类的初始化函数 super(Dog, self).__init__() # 在子类进行初始化时,也想继承父类的__init__()就经过super()实现,此时会定义self.name= 'animal'等 print('I am son') self.name = 'dog' # 定义子类的name属性,而且会把刚才的self.name= 'animal'更新为'dog' animal = Animal() #I am father xbai = Dog() #I am son(没有继承父类的print?) print(xbai.name) #'dog' #使用super继承 #子类在初始化的时候,调用父类的初始化 class Teacher: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender def say_hi(self): print('name: %s,age: %s,gender: %s'%(self.name,self.age,self.gender)) class Student(Teacher): def __init__(self,name,age,gender,number): super(Student, self).__init__(name,age,gender) self.number = number def say_hi(self): super().say_hi() print('number: %s'%self.number) stu = Student('syy',18,'male',2333333) stu.say_hi() name: syy,age: 18,gender: male number: 2333333 #继承方法 class Teacher: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender self.aa() def say_hi(self): print('name: %s,age: %s,gender: %s'%(self.name,self.age,self.gender)) def aa(self): print('my name si aa') class Student(Teacher): def __init__(self,name,age,gender,number): super().__init__(name,age,gender) self.number = number def say_hi(self): super().say_hi() print('number: %s'%self.number) stu = Student('syy',18,'male',2333333) stu.say_hi() #当继承一个现有的类,而且覆盖了父类的__init__方法,那么,必须在初始化方法的第一行调用父类的初始化方法,并传入父类所需的参数,再根据状况自定义属性
#组合 组合描述的是对象与对象之间的关系 将一个对象做为另外一个对象的属性 组合也能够理解成继承的一种 组合对比继承,类的耦合度更低 #组合的做用 重用代码,减小代码冗余 #何时使用继承 两个类之间存在父子关系,同类 #何时使用组合 两个类之间毫无关系,异类 #组合的代码实现 #人不是收集,可是人可使用收集的功能 class Phone: def __init__(self,price,kind,color): self.price = price self.kind = kind self.color = color def call(self): print('呼叫...') def send_message(self): print('发短信...') class Student: def __init__(self,name,age,phone): self.name = name self.age = age self.phone = phone def show_info(self): print('name: %s,age: %s'%(self.name,self.age)) phone1 = Phone(10000,'apple','red') stu1 = Student('syy',18,phone1) stu1.phone.call()
#python支持多继承 存在类的继承顺序问题 #通常的继承顺序 #按Sub的书写顺序继承 class A: pass class B: pass class C: pass class Sub(A,B,C): pass print(Sub.mro()) [<class '__main__.Sub'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>] #python3中,任何类都是直接或间接的继承Object class A: pass print(A.mro()) #[<class '__main__.A'>, <class 'object'>] #新式类与经典类 #新式类 任何显示或隐式的继承自Object的类,就叫作新式类 python3中,所有都是新式类 #隐式类 没有继承Object的类,就叫作经典类,python2中才会存在经典类 因此类的建立通常标识继承自object,这样代码既能够兼容python2有能够兼容python3 #菱形继承 当一个类有多个父类,且多个父类有共同的基类,那么这个类的继承就叫作菱形继承 class A: j = 1 pass class B(A): # j = 2 pass class C(A): j = 3 pass class D(B,C): # j =4 pass test = D.j print(test) #3 #菱形继承中新式类与经典类的区别 #新式类 有共同父类就广度(广度没有再深度),没有共同父类就深度找 #经典类 有共同父类是深度(深度没有再广度),没有共同父类是且仅是深度找 class A: num = 1 pass class B(): num = 2 pass class C(A): num = 3 pass class D(A): num = 4 pass class E(B): # num = 5 pass class F(C): num = 6 pass class G(D): num = 7 pass class H(E,F,G): # num = 8 pass print(H.num) #2 print(H.mro()) #[<class '__main__.H'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.F'>, <class '__main__.C'>, <class '__main__.G'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>]
#原始数据 程序员,姓名、性别、年龄、工资、编程技能 项目经理,姓名、性别、年龄、工资、编程技能、奖金、管理技能 #分析关系 初始化变量较多的时候,可使用locals 项目经理来自程序员,可使用super继承,没有必要使用抽象 不管是程序员仍是项目经理,都要使用存和取,单独抽取代码更加简洁,有利于代码扩展 import pickle import os class Baseclass: ''' 将存储数据的操做单独抽取,这样能够下降耦合度,减小代码冗余 ''' def save(self): #判断类名对应的文件夹是否存在 cls_name = self.__class__.__name__ if not os.path.exists(cls_name): os.makedirs(cls_name) path = os.path.join(cls_name,self.name) with open(path,'wb') as f: pickle.dump(self,f) @classmethod def get_obj(cls,name): #拼接路径 path = os.path.join(cls.__name__,name) if os.path.exists(path): with open(path,'rb') as f: return pickle.load(f) class Coder(Baseclass): def __init__(self,name,age,gender,salary): self.name = name self.age = age self.gender = gender self.salary = salary def programming(self): print('程序员正在开发项目...') class Manager(Coder): def __init__(self,name,age,gender,salary,bonus): super().__init__(name,age,gender,salary) self.bonus = bonus def manage(self): print('经理正在殴打程序员...') if __name__ == '__main__': # cod1 = Coder('syy',18,'男神',10000) # cod1.programming() # cod1.save() # man1 = Manager('ji',88,'糟老头子',100,1) # man1.programming() # man1.save() cod1 = Coder.get_obj('syy') #type: Coder cod1.programming() man1 = Manager.get_obj('ji') #type: Manager man1.manage() 程序员正在开发项目... 经理正在殴打程序员...
#什么是封装 封装就是将复杂的细节隐藏到内部,对外提供简单的使用接口 #为何要使用封装 为了保证关键数据的安全性 对外隐藏细节,隔离复杂度 #何时使用封装 当有一些数据不但愿外界直接修改 当有一些数据不但愿外界使用时 #怎么使用封装 class Person: def __init__(self,id_number,name,age): self.id_number = id_number self.name =name self.age = age def show_id(self): print(self.id_number) p = Person('111','syy',18) p.id_number = '222' p.show_id() #222 print(p.id_number) #222 class Person: def __init__(self,id_number,name,age): self.__id_number = id_number self.name =name self.age = age def show_id(self): print(self.__id_number) p = Person('111','syy',18) p.__id_number = '222' p.show_id() #111 print(p.__id_number) #222 class Person: def __init__(self,id_number,name,age): self.__id_number = id_number self.name =name self.age = age def show_id(self): print(self.__id_number) p = Person('111','syy',18) p.id_number = '222' p.show_id() #111,此时外界没法修改类体(可使用_Person__id_number修改) print(p.id_number) #222 #例 class PC: def __init__(self,price,kind,color): self.price = price self.kind = kind self.color = color def open(self): print('接通电源') self.__check_device() print('载入内核') print('初始化内核') self.__start_service() print('启动GUI') self.__login() def __check_device(self): print('硬件检测1.') print('硬件检测2..') print('硬件检测3...') def __start_service(self): print('启动服务1.') print('启动服务2..') print('启动服务3...') def __login(self): print('登陆1.') print('登陆2..') print('登陆3...') p = PC(10000,'苹果','白色') p.open() # p.login(),外界没法修改类体,没法使用类体内部的数据 #被封装的函数的特色 1.外界不能直接访问 2.内部依然可使用函数名调用 #学习了封装以后就能够控制属性的权限 1.公开权限,默认全部属性和方法都是公开的 2.私有权限,当前类才能使用的属性和方法 #如何访问被封装的属性或方法 #属性虽然被封装了,可是仍是须要访问或修改的 #经过定义函数,完成对私有属性的访问或修改 #这样以来,能够在外界访问或修改私有属性或方法时,添加额外的逻辑 class Downloader: def __init__(self,filename,url,buffer_size): self.filename = filename self.url = url self.__buffer_size = buffer_size def start_download(self): if self.__buffer_size <= 1024*1024: print('当前缓冲大小为: %s'%self.__buffer_size) print('开始下载...') else: print('内存炸了!!!') #定义接口函数 def set_buffer_size(self,size): #能够在接口函数中添加额外的逻辑 if type(size) == int: print('缓冲大小修改为功,大小为: %s'%size) self.__buffer_size = size else: print('缓冲大小必须是整型!!!') # 经过函数访问内部封装的属性 def get__buffer_size(self): return self.__buffer_size #生成对象 d = Downloader('奥特曼全集','www.aoteman.com',1024*1024) #下载 d.start_download() #修改函数内部封装的属性 d.set_buffer_size(1024*512) #继续下载 d.start_download()
#装饰器是用在函数上的 #property装饰器 该装饰器为了解决封装的属性和方法的'访问'方法的不一样 使用了该装饰器,类中隐藏方法的'访问',直接使用点,再也不使用括号 #key.setter装饰器 该装饰器为了解决封装先后的属性'修改’的不一样 使用了该装饰器,类中隐藏属性的修改,直接使用点,再也不使用括号 #key.deleter装饰器 该装饰器为了解决不能删除封装的属性的问题,相似于触发器 使用了该装饰器,类中隐藏属性的删除,能够直接删除,也能够设置触发条件 #原始代码 class A: def __init__(self,name,key): self.name = name self.__key = key def get_key(self): return self.__key def set_key(self,new_key): self.__key = new_key a = A('syy',123) print(a.name) #访问属性不加括号 print(a.get_key()) #访问方法加括号 #使用了property后的代码 class A: def __init__(self,name,key): self.name = name self.__key = key @property def get_key(self): return self.__key def set_key(self,new_key): self.__key = new_key a = A('syy',123) print(a.name) #访问属性不加括号 print(a.get_key) #访问方法再也不须要加括号,隐藏属性与普通属性访问方式相同 a.set_key(456) #属性的修改须要加括号 print(a.get_key) #使用property、key.setter、key.deleter后的代码 class A: def __init__(self,name,key): self.name = name self.__key = key @property def key(self): return self.__key @key.setter def key(self,new_key): self.__key = new_key @key.deleter def key(self): print('不容许删除该属性...') #del self.__key #能够在这里删除隐藏属性 a = A('syy',123) print(a.key) a.key = 456 #属性的修改不须要再使用括号,直接点,隐藏属性与普通属性修改方式相同 print(a.key) del a.key #隐藏属性不能直接删除,可使用装饰器删除,隐藏属性与普通属性删除方式相同 print(a.key) 123 456 不容许删除该属性... 456 #注意 key是property装饰器装饰的方法的名字,在使用setter和deleter时,装饰器的函数名要保持一致
#封装的原理 #python中,类中的属性的封装很是简单,仅仅是把类体中的属性的'__变量名'改成'_类名__变量名',这样外界将不能直接使用变量名或者__变量名访问隐藏属性(可是外界可使用_类名__变量名访问类的隐藏属性) #字符串的修改,对于python解释器的是很简单的 #这种字符串的修改只会在加载类的时候,在类体中运行(属性隐藏和访问的时候,'添加都会运行') class A: def __init__(self,key): self.__key = key @property def key(self): return self.__key @key.deleter def key(self): del self.__key a = A(123) print(a.key) del a.key print(a.key) #AttributeError: 'A' object has no attribute '_A__key' # class A: def __init__(self,key): self.__key = key @property def key(self): return self.__key @key.deleter def key(self): del self.__key a = A(123) print(a.key) #123 print(a.__dict__) #{'_A__key': 123} print(a._A__key) #123
#使用property装饰器,能够用来实现计算属性 #计算属性指的是:属性的值不能直接获取,必须经过计算才能获取 #这里的property装饰器,仅仅只是为了让方法的调用不加括号,与属性的调用相同而已 #例 求正方形的面积 class Square: def __init__(self,width): self.width = width @property def area(self): return self.width * self.width s = Square(10) print(s.area) #100 s.width = 20 print(s.area) #400 #例2 求BMI,BMI = 体重/身高的平方 class Bmi: def __init__(self,height,weight): self.height = height self.weight = weight @property def bmi(self): return self.weight/self.height/self.height b = Bmi(170,165) print(b.bmi) #0.005709342560553633
#什么是接口 接口是一组功能的集合,可是接口中只包含功能的名字,不包含具体的实现代码 接口本质上是一套协议标准,遵循这个标准的对象就能被调用 #接口的做用 为了提升代码的扩展性 #例 例如电脑上的USB接口协议,只要你遵循该协议,相关的设备就能被电脑使用,不须要关心设备的种类 #PC的代码一旦完成,后期不管什么样的设备,只要遵循了USB接口协议,都能被电脑调用 #接口主要是方便了对象的使用者,下降了使用者的学习难度,由于使用者只要学习了一套使用方法,就能够操做各种USB设备 class USB: def open(self): pass def close(self): pass def read(self): pass def write(self): pass class Mouse(USB): def open(self): print('鼠标开机') def close(self): print('鼠标关机') def read(self): print('获取光标位置') def write(self): print('鼠标不支持写入') class Keyboard(USB): def open(self): print('键盘开机') def close(self): print('键盘关机') def read(self): print('获取键盘字符') def write(self): print('键盘写入灯光颜色') def pc(usb_device): usb_device.open() usb_device.read() usb_device.write() usb_device.close() m = Mouse() k = Keyboard() pc(m) pc(k) 鼠标开机 获取光标位置 鼠标不支持写入 鼠标关机 键盘开机 获取键盘字符 键盘写入灯光颜色 键盘关机 #问题 若是子类没有按照你的协议来进行代码的编写,将致使代码没法运行
#abc模块,是单词absract class的缩写,意为'抽象类' #抽象类 一个类中没有包含函数体(或者通过装饰器装饰的函数体),那么这个类就是抽象类 #做用 能够限制子类必须遵循父类中定义的抽象方法 import abc class USB(metaclass=abc.ABCMeta): @abc.abstractmethod def open(self): pass @abc.abstractmethod def close(self): pass @abc.abstractmethod def read(self): pass @abc.abstractmethod def write(self): pass class Mouse(USB): def open(self): print('鼠标开机') def close(self): print('鼠标关机') def read(self): print('获取光标位置') def write(self): print('鼠标不支持写入') class Keyboard(USB): def open(self): print('键盘开机') def close(self): print('键盘关机') def read(self): print('获取键盘字符') def write(self): print('键盘写入灯光颜色') def pc(usb_device): usb_device.open() usb_device.read() usb_device.write() usb_device.close() m = Mouse() k = Keyboard() pc(m) pc(k)
#python通常不会限制你必须怎么写,做为一个优秀的程序员,就应该遵照相关协议,因此有了鸭子类型的说法 #鸭子类型 若是一个对象长得像鸭子,走路像鸭子,那他就是鸭子 #由此类推,只要保证你的类,按照相关的协议编写,就能够达到提升扩展性的目的 class Mouse: def open(self): print('鼠标开机') def close(self): print('鼠标关机') def read(self): print('获取光标位置') def write(self): print('鼠标不支持写入') class Keyboard: def open(self): print('键盘开机') def close(self): print('键盘关机') def read(self): print('获取键盘字符') def write(self): print('键盘写入灯光颜色') def pc(usb_device): usb_device.open() usb_device.read() usb_device.write() usb_device.close() m = Mouse() k = Keyboard() pc(m) pc(k)
#多态 生活中,一种事物有多种不一样的形态 官网:多个对象能够响应同一个方法,产生不一样的结果 多态不是一种特殊的语法,而是一种状态、特性 接口、抽象类、鸭子类型,均可以写出具有多态的代码,其中最简单的就是鸭子类型 #优势 对于使用者而言,大大的下降了使用难度,例如USB接口程序就有多态性 #例1 class Ji: def bark(self): print('咯咯咯...') def spawn(self): print('下鸡蛋') class Ya: def bark(self): print('嘎嘎嘎...') def spawn(self): print('下鸭蛋') class E: def bark(self): print('eee...') def spawn(self): print('下鹅蛋') j = Ji() y = Ya() e = E() #多个对象使用相同的方法,能够获得不一样的结果 def manage(obj): obj.spawn() manage(j) manage(y) manage(e) 下鸡蛋 下鸭蛋 下鹅蛋 #例2 a = 10 b = '10' c = [10] print(type(a)) #多个变量名使用相同的方法,获得不一样的结果 print(type(b)) print(type(c))
#该内置函数不管在不在类中,都能执行 #代码1 def add_num(a,b): if type(a) == int and type(b) == int: return a+b return None print(add_num(1,2)) print(add_num(1,'2')) #isinstance() 使用isinstance()函数,判断数据类型 isinstance(对象,数据类型) def add_num(a,b): if isinstance(a,int) and isinstance(b,int): return a+b return None print(add_num(1,2)) print(add_num(1,'2')) #issubclass() 使用issubclass()函数,能够判断一个类是否为某个类的子类/子孙类 issubclass(子类,父类) class Animal: def eat(self): print('动物要吃东西...') class Pig(Animal): def eat(self): print('猪要吃猪食') class Tree: def light(self): print('植物进行光和做用') def manage(obj): if issubclass(type(obj),Animal): obj.eat() else: print('不是动物!') p = Pig() t = Tree() manage(p) manage(t)
#__str__ 只要是双下,就会在某个时候自动执行 __str__会在对象被转换为字符串时执行,转换的结果就是这个函数的返回值 #打印对象,获得内存地址 class Person: pass p = Person() print(p) <__main__.Person object at 0x0000028E1471FA20> #打印对象,获得返回值 class Person: def __str__(self): return 'abc' p = Person() print(p) #abc #python解释器中的内置变量、内置函数、内置类,在程序运行结束会自动清理,可是python解释器不会清理不属于解释器的资源,例如打开的文件等,这个时候就须要手动close关闭代码 #__del__,吸构函数,删除对象/类,获得返回值 #__del__函数只会执行一次 #执行时机: 手动删除对象时执行 程序运行结束,就会执行类中的__del__函数 #使用场景 当你的对象在使用过程当中,打开了不属于python解释器的资源,例如文件、网络端口,在程序运行结束以后,就须要使用__del__函数来完成资源的释放工做 import time class Person: def __del__(self): print('del run') p = Person() print(p) # del p time.sleep(2) print('end') <__main__.Person object at 0x0000025385DEF400> end del run class Filetool: '''该类用于文件的读取操做''' def __init__(self,path): self.file = open(path,'rt',encoding='utf-8') def read(self): return self.file.read() #在这里能够肯定生成的对象再也不使用了,因此能够放心的关闭文件了 def __del__(self): tool.file.close() tool = Filetool(r'E:\python_test\a.txt') print(tool.read()) #a.txt #__init__,初始化函数、构造函数 class Person: def __init__(self,name,age): self.name = name self.age = age p = Person('syy',18) print(p.name) #__call__函数,在调用对象的时候执行(对象加括号) class A: def __call__(self, *args, **kwargs): print('call run') print(args) print(kwargs) a = A() a(1,'壹',z=233) #python是一门动态的语言,能够在代码运行期间动态的修改对象的属性所占用的空间 #若是代码运行内存不足,那么python解释器就会开启更大的内存区域,将原始的属性迁移过去 #这里存在一个问题,若是python解释器开启内存太大,那么将会形成内存的浪费 #解决方法是,在建立对象时,告诉python解释器要开启多大的内存,而不是让python解释器被动的开启内存 #__slots__函数,该属性是一个类属性,用于优化对象内存,将本来不固定的属性数量变得固定,这样python解释器就不会为这个对象建立名称空间,因此也没了__dict__方法 #使用了该函数,对象将不能再添加、删除属性 #代码1 import sys class Person: def __init__(self,name): self.name = name p = Person('syy') print(sys.getsizeof(p)) #56 #代码2 import sys class Person: __slots__ = ['name'] def __init__(self,name): self.name = name p = Person('syy') print(sys.getsizeof(p)) #48 # p.age = 18 #AttributeError: 'Person' object has no attribute 'age' # print(p.__dict__) #AttributeError: 'Person' object has no attribute 'age'
#这几个函数体现了python解释器如何使用点来设置、访问、删除属性的 #使用点设置属性的时候,执行__setattr__函数 #使用点访问属性(属性不存在)的时候,执行___getattr__函数 class A: def __setattr__(self, key, value): print('__setattr__') def __getattr__(self, item): print('__getattr__') def __delattr__(self, item): print('__delattr__') a = A() a.name = 'syy' print(a.name) __setattr__ __getattr__ None class A: def __setattr__(self, key, value): super().__setattr__(key,value) print('__setattr__') def __getattr__(self, item): print('__getattr__') def __delattr__(self, item): print('__delattr__') a = A() a.name = 'syy' #经过点语法操做对象的属性(原理是使用__dict__) print(a.name) #syy,变量设置成功,因此能够打印出syy __setattr__ syy a = A() a.__dict__['name'] = 'syy' #经过__dict__设置属性 print(a.name) #syy class A: def __setattr__(self, key, value): self.__dict__[key] = value print('__setattr__') def __getattr__(self, item): print('__getattr__') def __delattr__(self, item): print('__delattr__') a = A() print(a.xxx) #__getattr__ #删除属性的时候,执行__delattr__函数 class A: def __setattr__(self, key, value): self.__dict__[key] = value print('__setattr__') def __getattr__(self, item): print('__getattr__') def __delattr__(self, item): print('__delattr__') a = A() a.name = 'syy' del a.name print(a.name) #删除不掉,缘由是由于__delattr__对应的函数没有删除的操做 __setattr__ __delattr__ syy class A: def __setattr__(self, key, value): self.__dict__[key] = value print('__setattr__') def __getattr__(self, item): print('__getattr__') def __delattr__(self, item): self.__dict__.pop(item) print('__delattr__') a = A() a.name = 'syy' del a.name print(a.name) #删除成功 __setattr__ __delattr__ __getattr__ None #访问属性的时候,不管有没有该属性都会执行__getattribute__函数, class A: def __getattr__(self, item): print('__getattr__') def __getattribute__(self, item): print('__getattribute__') a = A() a.name = 'syy' print(a.name) print(a.xxx) __getattribute__ None __getattribute__ None #__dict__方法的原理就是使用了__getattribute__函数 class A: def __getattr__(self, item): print('__getattr__') def __getattribute__(self, item): print('__getattribute__') return self.__dict__[item] a = A() a.name = 'syy' print(a.name) print(a.xxx) #RecursionError: maximum recursion depth #实际上python内部是先使用__getattribute__取值,若是取不到,再使用__getattr__ class A: def __getattr__(self, item): print('__getattr__') def __getattribute__(self, item): print('__getattribute__') return super(A, self).__getattribute__(item) a = A() a.name = 'syy' print(a.name) print(a.xxx) __getattribute__ syy __getattribute__ __getattr__ None
#这几个函数体现了python解释器如何使用[]来设置、访问、删除属性的 #设置属性的时候执行__setitem__ class A: def __setitem__(self, key, value): print('__setitem__') def __getitem__(self, item): print('__getitem__') def __delitem__(self, key): print('__delitem__') a = A() a['name'] = 'syy' #__setitem__ print(a.name) #AttributeError: 属性不存在 #访问属性的时候执行__getitem__ class A: def __setitem__(self, key, value): print('__setitem__') self.__dict__[key] = value def __getitem__(self, item): print('__getitem__') return self.__dict__[item] def __delitem__(self, key): print('__delitem__') del self.__dict__[key] a = A() a['name'] = 'syy' print(a['name']) __setitem__ __getitem__ syy #删除属性的时候执行__delitem__ class A: def __setitem__(self, key, value): print('__setitem__') self.__dict__[key] = value def __getitem__(self, item): print('__getitem__') return self.__dict__[item] def __delitem__(self, key): print('__delitem__') del self.__dict__[key] a = A() a['name'] = 'syy' print(a['name']) del a['name'] print(a['name']) #KeyError: 'name' __setitem__ __getitem__ syy __delitem__ __getitem__ #例 如何让一个对象既支持点语法取值,也支持括号取值 #对象自己就支持括号[]设置、访问、删除值,因此只须要添加点语法便可 class Mydict(dict): def __setattr__(self, key, value): self[key] = value def __getattr__(self, key): return self.get(key) def __delattr__(self, item): del self[item] m = Mydict() m['name'] = 'syy' print(m['name']) #syy del m['name'] # print(m['name']) m.name = 'zyy' print(m.name) #zyy del m.name # print(m.name)
#当咱们在使用某个符号时,python会为这个符号定义一个含义,同时调用对应的处理函数,当咱们须要自定义对象的比较规则时,就能够在子类中覆盖 >、<、=、!=等方法 #self和other指的是两个对象 #相似于大于、小于,咱们只须要实现一个便可,若是符号不一样,python解释器会自动交换两个对象的位置 class Student: def __init__(self,name,age,height): self.name = name self.age = age self.height = height def __gt__(self, other): if self.height > other.height: return True else: return False def __lt__(self, other): if self.height < other.height: return True else: return False def __eq__(self, other): if self.name == other.name and self.age == other.age and self.height == other.height: return True else: return False def __ne__(self, other): if self.name == other.name or self.age == other.age or self.height == other.height: return True else: return False s1 = Student('syy',18,180) s2 = Student('zyy',80,140) print(s1 > s2) print(s1 < s2) print(s1 == s2) print(s1 != s2) True False False True #代码简写 class Student: def __init__(self,name,age,height): self.name = name self.age = age self.height = height def __gt__(self, other): return self.height > other.height def __lt__(self, other): return self.height < other.height def __eq__(self, other): return self.name == other.name and self.age == other.age and self.height == other.height def __ne__(self, other): return self.name != other.name or self.age != other.age or self.height != other.height s1 = Student('syy',18,180) s2 = Student('zyy',80,140) print(s1 > s2) print(s1 < s2) print(s1 == s2) print(s1 != s2) True False False True
#迭代器的断定方法 1.内置有__iter__方法 2.内置有__next__方法 #迭代器的做用 迭代器就是一种取值的工具 节省空间 #迭代器原理 class Myiter: def __init__(self,num): self.num = num self.count = 0 def __iter__(self): return self def __next__(self): self.count += 1 if self.count <= self.num: return '哈哈' else: raise StopIteration for i in Myiter(10): print(i) #生成器 class Myrange: def __init__(self,start,end,step): self.start = start self.end = end self.step = step def __iter__(self): return self def __next__(self): a = self.start self.start += self.step if a < self.end: return a else: raise StopIteration for i in Myrange(1,10,2): print(i)
#上下文comtext 指的是一段话的意义,要参考当前的场景,即参考上下文 在python中,上下文能够理解为是一个代码区间、一个范围,例如with open,打开的文件尽在这个上下文中有效 涉及到的两个方法: enter: 表示进入上下文,进入某个场景 exit: 表示退出上下文,退出某个场景 #使用open类的with,先执行__enter__函数,open内代码运行结束,最后执行__exit__函数 class Myopen: def __enter__(self): print('__enter__') def __exit__(self, exc_type, exc_val, exc_tb): print('__exit__') print(exc_type, exc_val, exc_tb) with Myopen() as m: print('start') # '1' + 1 #open内代码执行的过程当中,若是中途代码异常,则以后的代码再也不执行,可是当即__exit__函数仍会执行,包含错误的类型、错误的信息、错误的追踪信息 print('over') __enter__ start over __exit__ None None None class Myopen: def __init__(self,path): self.path = path def __enter__(self): self.file = open(self.path) return self def __exit__(self,exc_type, exc_val, exc_tb): self.file.close() return False #经过返回的状态码判断代码运行的过程当中,有诶有错误或者错误有没有被处理 with Myopen('a.txt') as m: print(m.file.read())
#反射reflect #什么是反射 其实reflect的意思是检讨、自省的意思 反射指的是一个对象应该具有能够检测、修改、增长自身属性的能力 反射就是经过字符串操做属性 反射涉及到的四个内置函数(python解释器自带的),hasattr、getattr、setattr、delattr 这几个函数都是针对于对象的,对应于对象属性是否存在、获取、设置、删除 这几个函数实际上就是封装了__dict__等方法而已 #hasattr()函数 #判断一个属性属不属于某个对象 class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender p = Person('syy',18,'male') print(hasattr(p,'name')) #True print(hasattr(p,'names')) #False #getattr()函数 #获取对象的属性,能够设置默认返回值(属性不存在的时候返回) class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender p = Person('syy',18,'male') if hasattr(p,'name'): print(getattr(p,'name',None)) #setattr()函数 #为对象添加新的属性 class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender p = Person('syy',18,'male') setattr(p,'id','123') print(p.id) #123 #delattr()函数 #删除对象的属性 class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender p = Person('syy',18,'male') delattr(p,'name') print(p.name) #AttributeError:
反射实际上就是对属性的增删改查,可是若是直接使用内置的__dict__来操做的话,会显得语法繁琐,很差理解,因此python封装了4个函数 封装的另外一个缘由就是,若是对象不是我本身写的而是另外一方提供的,那我就必须判断这个对象是否具有我须要的属性和方法 反射是框架的基石,由于框架的设计者,不可能提早知道你的对象究竟是怎么设计的,因此你提供给框架的对象,必须经过判断验证以后,才能正常的使用,而判断验证就是反射要作的事情,因此说反射就是对__dict__的操做进行封装 #需求 要实现一个用于处理用户的终端指令的小框架 所谓的框架,就是已经实现了最基础的构架,就是全部的项目都同样的部分