作业讲解
""" 1.定义一个汽车类Vehicle, 要求: 1.属性包括:汽车品牌brand、颜色color和速度speed, 其中速度的起始值是0。 2.为属性提供访问的方法。注意:汽车品牌一旦初始化之后不能修改。 3.方法有加速、减速。 """ class Vehicle(object): def __init__(self,brand,color): #私有化 self.__brand = brand self.color = color #速度的起始值是0 self.speed = 0 def add_speed(self,speed): self.speed += speed print("当前的车速为:%d" % (self.speed)) def cut_speed(self,speed): if speed > self.speed: #print("抱歉,无法完成减速") self.speed = 0 else: self.speed -= speed print("当前的车速为:%d" % (self.speed)) #之提供获取的方法,不提供修改的方法 # def get_brand(self): # return self.__brand @property def brand(self): return self.__brand v = Vehicle("兰博基尼","紫色") v.add_speed(49) v.cut_speed(20) #print(v.get_brand()) print(v.brand)
""" 3.宠物店类 PetShop 属性:店名,店中的宠物 【使用列表存储宠物】 方法:展示所有宠物的信息 宠物狗类 PetDog 属性:昵称,性别,年龄,品种 方法:叫,拆家,吃饭 宠物猫类 PetCat 属性:昵称,性别,年龄,品种,眼睛的颜色 方法:叫,撒娇,吃饭 注意:狗的叫声是汪汪 猫的叫声是喵喵 狗吃的是⻣头 猫吃的是⻥ """ #父类 class Pet(object): #公共的属性 def __init__(self,name,gender,age,kind): self.name = name self.age = age self.gender = gender self.kind = kind #公共的方法 def cry(self): print("crying") def eat(self): print("eating") def myprint(self): print(self.name,self.gender,self.age,self.kind) #子类 class PetDog(Pet): #特有的方法 def des_home(self): print(self.name + "拆家") #重写父类中的函数 def cry(self): print("汪汪") def eat(self): print(self.name + "eating骨头") class PetCat(Pet): def __init__(self, name, gender, age, kind,eye_color): super().__init__(name,gender,age,kind) self.eye_color = eye_color # 特有的方法 def play(self): print(self.name + "撒娇") # 重写父类中的函数 def cry(self): print("喵喵") def eat(self): print(self.name + "eating鱼") def myprint(self): print(self.name,self.gender,self.age,self.kind,self.eye_color) class PetShop(object): def __init__(self,name,pet_list): self.name = name self.pet_list = pet_list def show(self): if self.pet_list: for pet in self.pet_list: #print(pet) pet.myprint() #多态,根据类型自动匹配调用哪个函数 pet.eat() pet.cry() #调用子类特有的函数,直接调用会报错 if isinstance(pet,PetDog): pet.des_home() elif isinstance(pet,PetCat): pet.play() else: print("还没有宠物,无法展示") p1 = PetCat("aaa",0,3,"英短","棕色") p2 = PetCat("bbb",0,3,"英短","棕色") p3 = PetCat("ccc",0,3,"英短","棕色") p4 = PetDog("aaa",0,3,"二哈") p5 = PetDog("aaa",0,3,"泰迪") p6 = PetDog("aaa",0,3,"二哈") ps = PetShop("阳阳阳宠物店",[p1,p2,p3,p4,p5,p6]) ps.show()
一、面向对象
1.对象的内置函数
import types #1.type():获取一个对象的类型,返回的结果:<class "类型"> print(type(10)) print(type("aaa")) print(type(True)) #注意1:type可以进行比较== print(type(10) == int) #注意2:type()返回值的类型为type类型 print(type(type(10))) #<class 'type'> #注意3:判断一个对象是否是函数,使用types模块 print(type(lambda x:x) == types.LambdaType) print(type((x for x in range(5))) == types.GeneratorType) print(type(abs) == types.BuiltinFunctionType) #2.isinstance():判断一个对象是否是指定的数据类型 print(type(10) == int) print(isinstance(10,int)) #注意:可以判断一个对象是否是某些类型中的一种,只要符合一种,则返回True print(isinstance([1,2,3],(list,tuple,dict))) print(isinstance((1,2,3),(list,tuple,dict))) print(isinstance("123",(list,tuple,dict))) #3.dir(),获取一个对象的所有属性和方法,返回一个列表 ******* print(dir("fahf")) print(dir([3,5])) #4.issubclass(子类,父类):用来判断两个类之间的继承关系 class Person(object): pass class Student(Person): pass class Dog(object): pass print(issubclass(Student,Person)) #True print(issubclass(Person,Student)) #False print(issubclass(Person,Dog)) #False
2.魔术方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ouxriQcw-1586254871686)(1.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bwL8F5ox-1586254871686)(2.png)]
#1.__str__和__repr__:返回对象的字符串描述信息,默认返回的是对象的地址 #a. class Person(object): def __init__(self,name,age,hobby): self.name = name self.age = age self.hobby = hobby p1 = Person("张三",10,"吹牛逼") print(p1) #<__main__.Person object at 0x1026bb160> print(p1.__str__()) #<__main__.Person object at 0x1026bb160> #b class Person(object): def __init__(self,name,age,hobby): self.name = name self.age = age self.hobby = hobby #注意1:如果输出对象的时候不需要地址,需要对象的信息,则可以在类中重写__str__ def __str__(self): #print("hello") #TypeError: __str__ returned non-string (type NoneType) #注意2:__str__必须设置返回值,而且必须返回一个字符串,该字符串一般和对象的属性相关 return "%s-%d-%s" % (self.name,self.age,self.hobby) p1 = Person("张三",10,"吹牛逼") print(p1) #print(p1.__str__()) print('=' * 30) #c。 """ repr和str的功能类似,都是用来修改一个对象的默认打印内容,在打印一个对象时, 如果在类中没有重写str,他会自动查找repr,如果这两个方法都没有,则直接打印该对象的地址 常用__str__ """ class Person(object): def __init__(self,name,age,hobby): self.name = name self.age = age self.hobby = hobby def __str__(self): return "%s-%d-%s" % (self.name,self.age,self.hobby) # def __repr__(self): # return "%s-%d-%s" % (self.name,self.age,self.hobby) #__repr__ = __str__ #函数是一个变量 p1 = Person("张三",10,"吹牛逼") print(p1)
#2.__add__:但凡涉及到+号的运算,都是调用了该函数 #a print(2 + 6) print("abc" + "123") print([2,3,4] + [4,5,6]) print((2,3,4) + (4,5,6)) #print("abc" + 6) #TypeError: can only concatenate str (not "int") to str #print(6 + "abc") #TypeError: unsupported operand type(s) for +: 'int' and 'str' #注意:对于不同的类型,+有不同的解释,所以支持+运算的数据类型,系统提供了__add__函数 # print(dir("abc")) # print("abc".__add__("123")) # print(dir([1,2,3])) # print([1,2,3].__add__([4,5,6])) # print(dir(10)) #b class Person(object): def __init__(self,age,name): self.age = age self.name = name def __add__(self, other): #参与求和的对象:self和other #Person(self.age + other.age)表示创建对象,会调用init,注意参数的匹配 return Person(self.age + other.age,self.name) def __str__(self): return "%s-%d" % (self.name,self.age) def show(self): print("show") p1 = Person(18,"张三") p2 = Person(8,"aaa") #Person + Person = int ---->Person + Person = Person print(p1 + p2) #TypeError: unsupported operand type(s) for +: 'Person' and 'Person' print(p1.__add__(p2)) print(p1) #工作原理 print((p1.__add__(p2).__str__())) p3 = Person(10,"bbb") print(p1 + p2 + p3) #p1 + p2返回Person,然后再和p3相加 """ p1.__add__(p2)---->temp:Person(26) temp.__add__(p3) --->sub:Person(36) sub.__str__() """ p1.show() print(p1.name,p1.age)
#问题补充说明:__str__\__repr__\__add__ #1. class Person(object): def __init__(self,name,height): self.name = name self.height = height def __str__(self): #注意1:只需要返回一个字符串,字符串的格式由需求而定,拼接几个属性由需求而定 return "姓名:%s,身高:%.2f" % (self.name,self.height) # def __repr__(self): # return "姓名:%s,身高:%.2f" % (self.name,self.height) __repr__ = __str__ p1 = Person("jack",175.0) p2 = Person("李四",185.5) #注意2:一般情况下,魔术方法都不需要手动调用,根据具体的使用场景会自动调用 print(p1) print(p2) #工作原理:p1.__str__() p2.__str__() list1 = [p1,p2] for per in list1: print(per) print(list1) #2 class Student(object): def __init__(self,name,age,score): self.name = name self.age = age self.score = score def __add__(self, other): #注意:根据需求,自定义相加的内容【同种类型】 return Student("aaa",5,self.score + other.score) def __str__(self): return str(self.score) stu1 = Student("小花",10,100) stu2 = Student("小王",9,66) #需求:实现两个学生对象的相加,结果为成绩之和 print(stu1 + stu2) #stu1.__add__(stu2) print(type(stu1 + stu2)) print(stu1) print(stu2)
#3.比较运算符 """ >:__gt__ , greater than <:__lt__ ,less than >=:__ge__ ,greater equal <=:__le__ ,less equal ==:__eq__ ,equal !=:__ne__ ,not equal """ class Student(object): def __init__(self,name,age,score): self.name = name self.age = age self.score = score #重新实现系统函数,自定义比较的规则 def __gt__(self, other): #参与比较的对象:self和other if self.score > other.score: return True elif self.score < other.score: return False else: return "相等" stu1 = Student("小花",10,50) stu2 = Student("小王",9,66) #需求:比较两个学生的成绩高低 print(stu1 > stu2) #True print(stu1.__gt__(stu2))
3.类属性和实例属性【面试题】
类属性:类的字段 实例属性/对象属性:对象的字段
实例属性和类属性的区别:
a.定义的位置不同,类属性是直接定义在类中的属性,对象属性是定义在构造函数中的属性
b.对象属性使用对象访问,类属性使用类名访问
c.在内存中出现的时机不同【类属性随着类的加载而出现,对象属性随着对象的创建而出现】
d.优先级不同,对象属性的优先级高于类属性
e.使用场景不同:如果是对象特有的数据,则定义为对象属性,如果是多个对象共有的数据,则定义为类属性
class NZ2002(object): #1.定义位置不同 #类属性:定义在类中 num = 10 name = "abc" teacher = "Disen老师" def __init__(self,name): #对象属性/实例属性:定义在构造函数中 self.name = name #2.在内存中出现的时机不同,类属性优先于对象属性出现在内存中 print(NZ2002.num) #10 #print(NZ2002.name) #AttributeError: type object 'NZ2002' has no attribute 'name' #3.调用方式不同 #类属性: 类名.类属性 或者 对象.类属性 print(NZ2002.num) n = NZ2002("王猛") print(n.num) #对象属性: 对象.对象属性 print(n.name) #4.优先级不同:当类属性和对象属性重名时,使用对象访问的时候对象属性的优先级高 print(n.name) del n.name print(n.name) #5.使用场景不同:如果是对象特有的数据,则定义为对象属性,如果是多个对象共有的数据,则定义为类属性 dingxing = NZ2002("定兴") daineng = NZ2002("代能") dingxing.name = "吴帅哥" print(dingxing.name) print(daineng.name) print(dingxing.teacher) print(daineng.teacher)
4.类方法和静态方法
类方法:在方法前面有 @classmethod 装饰器的方法叫做类方法,类方法可以通过类名调用,也可以通过对象名调用,但是一般都通过类名调用
类方法必须有一个参数,这个参数我们一般写为 cls , cls代表就是当前类
a.类方法是属于整个类的,不是属于某个对象的,所以在类方法中禁止出现self
b.在类方法中,可以直接通过cls调用这个类的类属性和类方法
c.在类方法中,可以直接通过cls来创建对象,并且封装一层,最终通过类方法给外部提供简介的接口静态方法:在方法前面有 @staticmethod 装饰器 的方法叫做静态方法,静态方法可以通过类名调用,也可以通过对象名调用,但是一般都通过类名调用
class Person(object): #构造方法 def __init__(self,name): self.name = name #实例方法 #特点:参数列表的第一个参数是self,self表示当前实例【对象】 def show(self): print("showing",self) def check(self): print("check") self.show() #类方法 #特点:参数列表的第一个参数是cls,cls代表当前类 #注意:在类方法中调用实例方法,则可以通过cls先创建一个对象,然后调用 @classmethod def func1(cls): print("类方法~~~~func1",cls) # 可以通过cls创建对象 c = cls("jack") #对象.实例方法 c.show() #静态方法 #说明:形参没有特殊之处 @staticmethod def func2(): print("func2222222") per = Person("张三") #实例方法:对象.函数(实参列表),self不需要传参 per.show() #Person.show(per) #类方法:对象.函数(实参列表) 或者 类名.函数(实参列表) per.func1() Person.func1() #静态方法:对象.函数(实参列表) 或者 类名.函数(实参列表) per.func2() Person.func2() """ 总结: a.类方法一般和类属性配合使用 b.如果封装工具类,类中的函数可以定义为类方法或者静态方法,直接使用类名调用 c.如果在函数内部需要创建当前类的对象,则该函数定义为类函数【cls】 """ #注意事项:在类中定义的函数不管是实例方法,还是静态方法或者是类方法, # 只要重名,不管使用对象调用还是类名调用,调用的是最后定义的方法 class Dog(object): @classmethod def demo(cls): print("类方法") def demo(self): print("实例方法") @staticmethod def demo(): print("静态方法") d = Dog() d.demo() Dog.demo()
5.单例设计模式
5.1概念
什么是设计模式?
设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案
设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言
23种设计模式,其中比较常用的是单例设计模式,工厂设计模式,代理模式,装饰者模式等等
什么是单例设计模式?
程序运行过程中,确保某一个类只有一个实例【对象】,不管在哪个模块获取这个类的对象,获取到的都是同一个对象。该类有一个静态方法,向整个工程提供这个实例,例如:一个国家只有一个主席,不管他在哪
单例设计模式的核心:一个类有且仅有一个实例,并且这个实例需要应用于整个程序中,该类被称为单例类
5.2应用场景
应用程序中描述当前使用用户对应的类 ———> 当前用户对于该应用程序的操作而言是唯一的——> 所以一般将该对象设计为单例
实际应用:数据库连接池操作 ——> 应用程序中多处地方连接到数据库 ———> 连接数据库时的连接池只需一个就行,没有必要在每个地方都创建一个新的连接池,这种也是浪费资源 ————> 解决方案也是单例
5.3实现
方式一
#1.方式一:__new__ class Person(object): #定义一个类属性,而且将其私有化,表示当前类可以创建的唯一的实例 __instance = None def __new__(cls, *args, **kwargs): print("new~~~~") #思路:判断__instance的值是否为None,如果为None,则创建当前类的对象并赋值给__instance #如果__instance不为None,则直接返回结果 if not cls.__instance: #创建当前类的对象 cls.__instance = object.__new__(cls) return cls.__instance def __init__(self,name,age): print("init~~~~") self.name = name self.age = age p1 = Person("张三",19) p2 = Person("李四",33) print(p1) print(p2) print(p1 is p2) print(id(p1) == id(p2)) print(p1.name) print(p2.name)
方式二:
#方式二:装饰器 #说明:装饰器不但可以修饰函数,而且可以修饰类 #装饰器实现方式一 def singleton(cls): #定义一个变量,表示当前类可以创建的唯一的实例 instance = None def getinstance(*args,**kwargs): # 思路:判断instance的值是否为None,如果为None,则创建当前类的对象并赋值给instance # 如果instance不为None,则直接返回结果 nonlocal instance if not instance: instance = cls(*args,**kwargs) return instance return getinstance @singleton #执行装饰器的外部函数,并且将Person类名传值给外部函数的形参 class Person(object): def __init__(self,name,age): print("init被调用了") self.name = name self.age = age p1 = Person("aaa",10) p2 = Person("bbb",20) print(p1 is p2) print(id(p1) == id(p2)) print(p1.name) print(p2.name) @singleton class Cat(object): pass c1 = Cat() c2 = Cat() print(c1 is c2)
方式三:
#装饰器实现方式二 def singleton(cls): #定义一个字典变量,key是类,value是当前类唯一的实例 instance_dict = {} def getinstance(*args,**kwargs): # 思路:判断instance_dict是否为空,如果为空,则向其中添加键值对, #如果不为空,则直接返回字典中的value if not instance_dict: instance_dict[cls] = cls(*args,**kwargs) return instance_dict[cls] return getinstance @singleton #执行装饰器的外部函数,并且将Person类名传值给外部函数的形参 class Person(object): def __init__(self,name,age): self.name = name self.age = age p1 = Person("aaa",10) p2 = Person("bbb",20) print(p1 is p2) print(id(p1) == id(p2)) print(p1.name) print(p2.name)