传参的方式可以写在初始化函数形参中,也可以self. xx,以定义人类为例,初始化函数中涵盖name,age:
通常习惯会将形参name,age放进__init__中,格式如下:
class Person: #定义了一个名字叫Person的类 def __init__(self,name,age): #下面需要的有2个参数,name和age,放进__init__中备用 self.name = name #self将会传入下面创建的实例luna所需的name值和age值 self.age = age def show(self): print('姓名:'+ self.name +'年龄:',self.age) #show函数的动作 if '__main__'==__name__: luna = Person('Luna',20) #创建实例并传参 luna.show()
上面的例子中,初始化函数中是灵活的,可以通过luna的传参来更改打印的结果
下面的例子中,是在初始化时,就将值赋好,作为默认值
class Person: def __init__(self): self.name = 'Jack' self.age = 50 def show(self): print('姓名:'+ self.name +'年龄:',self.age) if '__main__'==__name__: luna = Person() luna.show() #打印结果为 姓名:Jack年龄: 50 luna并没有给值,所以为默认值jack 50
class Person: def __init__(self): self.name = 'Jack' self.age = 50 def show(self): print('姓名:'+ self.name +'年龄:',self.age) if '__main__'==__name__: luna = Person() luna.name = 'Luna' luna.age = 20 luna.show() #打印结果为 姓名:Luna年龄: 20 luna.name和luna.age重新赋值,会打印出新赋的值
此外,语法也允许在外面赋值,但只能自身调用:
class Person: def __init__(self): self.name = 'Jack' self.age = 50 def show(self): print('姓名:'+ self.name +'年龄:',self.age) if '__main__'==__name__: luna = Person() luna.name = 'Luna' luna.age = 20 luna.gender = 'female' #单独给luna一个gender属性并赋值female luna.show() print('luna.gender;',luna.gender) #打印时正常,自己内部的赋值可以自身调用 candy = Person() candy.name = 'candy' candy.age = 30 candy.show() print('candy gender:',candy.gender) #这样会报错!!!! 不是自己的,也不是类的,不可以调用!
类属性: 属于类的成员,对象共有的
class Person: x = '123' def __init__(self,name,age): pass @classmethod def Clsmth(cls): print('aaa') lili = Person('lili',20) lili.__class__.Clsmth() #打印结果aaa Person.Clsmth() #打印结果aaa
lili.__class__的类就是Person,__class__属性与对象属性的区别是:当需要全局的调用时,就用__class__,(例如:lili.__class__.phone)如果只需要自己赋值自己调用的时候,就用对象属性(例如:lili.phone)
类方法: @classmethod
def class_method(cls):
可以通过类方法调用类属性,也可以通过对象调用类属性
类方法更倾向于工具方法,不需要重复创建对象,不是以对象的形式去调用
静态方法: @staticmethod
不关乎类,也不关乎对象,而是服务于程序
一般情况下,静态方法会单独放在一个模块中
对象不需要new,不是已经存在的对象
class Person: def __init__(self): pass @staticmethod def SayHi(): #无参也可以 print('hi...') Person.SayHi() #打印结果hi...
class Person: def __init__(self): self.CallName = 'coco' @staticmethod def SayHi(name): #有参也可以 print(name+'你好!') luna = Person() Person.SayHi('luna') #打印结果 luna你好!
继承:
子类继承父类,子类可以使用父类的属性和方法,简化代码,当生成子类对象时,先初始化父类对象
所以如果父类有__init__()方法,并且有属性时,要通过子类的构造赋值,一个类可以有多个子类
super().__init__(属性)
或self.属性
或父类.__init__(self,参数)==>父类.__init__(self)-->调用无参
super(子类,self).__init__(参数)
用子类的父类的 __init__
class Pet: def __init__(self): self.name = '' self.love = 0 self.health = 100 def show(self): print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health)) class Dog(Pet): def __init__(self): super().__init__() #子类常使用super().__init__()调用父类的初始化方法 self.strain = '拉布拉多' def eat(self): print('品种;'+ self.strain + '正在吃饭...') #代表程序主入口是从这里进入的 if __name__ == '__main__': dog = Dog() dog.eat() dog.show() #子类dog调用父类的show方法,需要有super().__init__()
class Pet: def __init__(self): self.name = '' self.love = 0 self.health = 100 def show(self): print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health)) class Dog(Pet): def __init__(self): super(Dog, self).__init__() #方法二:super(子类,self).__init__(参数) 子类调用父类的初始化方法 self.strain = '拉布拉多' def eat(self): print('品种;'+ self.strain + '正在吃饭...') #代表程序主入口是从这里进入的 if __name__ == '__main__': dog = Dog() dog.eat() dog.show()
class Pet: def __init__(self,name,love,health): #形参 3-1 self.name = name self.love = love self.health = health def show(self): print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health)) class Dog(Pet): def __init__(self,name,love,health): #形参 3-2 super().__init__(name,love,health) #形参 3-3,不需要加self self.strain = '拉布拉多' def eat(self): print('品种;'+ self.strain + '正在吃饭...') #代表程序主入口是从这里进入的 if __name__ == '__main__': dog = Dog('可乐',33,99) #传参 dog.eat() dog.show()
可以迭代:(下↓)
打印结果:
品种;拉布拉多正在吃饭...
name:可乐亲密度:43健康值:99class Pet: def __init__(self,name,love,health): self.name = name self.love = love self.health = health def show(self): print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health)) class Dog(Pet): def __init__(self,name,love,health): super().__init__(name,love,health) self.strain = '拉布拉多' def eat(self): print('品种;'+ self.strain + '正在吃饭...') #代表程序主入口是从这里进入的 if __name__ == '__main__': dog = Dog('可乐',33,99) dog.eat() dog.love +=10 #执行eat后,love值增加10 dog.show()
当需要打印父类的方法show(),同时也需要子类的方法strain(), 在子类中重新建立一个showInfo()方法,调用父类的show()
class Pet: def __init__(self,name,love,health): self.name = name self.love = love self.health = health def show(self): print('name:'+ self.name + '亲密度:' + str(self.love) + '健康值:' + str(self.health)) class Dog(Pet): def __init__(self,name,love,health): super().__init__(name,love,health) self.strain = '拉布拉多' def eat(self): print('品种;'+ self.strain + '正在吃饭...') def showInfo(self): super().show() print('品种:',self.strain) #代表程序主入口是从这里进入的 if __name__ == '__main__': dog = Dog('可乐',33,99) dog.eat() dog.showInfo()
总结:
当子类继承父类时,子类的构造方法应该包含父类和子类共同的属性,在子类的初始化__init__()方法中,将父类的属性传递给父类,子类的属性赋值给子类
方法重写:子类继承父类时,子类的方法签名和父类一样,此时子类重写了父类的方法,当生成子类对象时,调用的是子类重写的方法小练习:
交通工具类:属性:名称 方法:行驶
子类:卡车,属性:载重,重写行驶的方法
子类:火车,属性:车箱个数,重写行驶的方法
class traffic: def __init__(self,name): self.name = name def run(self): print('交通工具名称:'+ self.name + '正在行驶...' ) class Truck(traffic): def __init__(self,name,weight): super().__init__(name) self.weight = weight def run(self): print('卡车' + self.name + '载重' + str(self.weight)+ '在行驶') class Train(traffic): def __init__(self,name,num): super().__init__(name) self.num = num def run(self): print('卡车' + self.name + '个数' + str(self.num)+ '在行驶') if __name__ == '__main__': dongfeng = Truck('东风',50) dongfeng.run() hexie = Train('和谐001',100) hexie.run()卡车东风载重50在行驶
卡车和谐001载重100在行驶
三代继承:
子类初始化方法需要祖父、父类及自己的属性,可以调用父类的初始化方法传参,可以重写父类的方法
构造的顺序依然先构造祖父类,再构造父类,最后构造自己类根源顶级父类-->继承object
方法重写:
如果子类重写的方法想调用父类的方法时,在子类方法中:
父类.方法(self)或super().父类方法()
私有属性、私有方法:均不能在类外面被调用
多继承:类同时继承多个父类,class C(A,B),
当有AB均有相同方法,而子类又重写时,调用谁的方法,(子类)
如果子类重写没有方法,则调用哪个父类的方法?(左侧,优先继承的类)
类名.mro(),可以看到所有父类,即搜索顺序
这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子
小练习:
----DVD管理系统----:
1.查询所有DVD
2.增加DVD
3.借出DVD
4.归还DVD
5.退出
class DVD: def __init__(self,name,price,state): self.name = name self.price = price self.state = state if __name__ == '__main__': Lily = DVD('Lily',10,0) Candy = DVD('Candy',20,1) Jack = DVD('Jack',30,0) dvds = {Lily.name:Lily,Candy.name:Candy,Jack.name:Jack} while True: print('-----------------') num = int(input('请输入执行编号:')) if num ==5: print('谢谢使用!') break if num == 1: print('名字\t价格\t状态') for key in dvds.keys(): if dvds.get(key).state ==0: print(key + '\t' + str(dvds.get(key).price) + '\t借出') else: print(key + '\t' + str(dvds.get(key).price) + '\t未借出') if num == 2: name = input('请输入DVD的名字:') while name in dvds.keys(): name = input('名字已存在,请重新输入DVD的名字:') price = input('请输入价格:') new_dvd = DVD(name,price,1) dvds[name] = new_dvd print('添加成功!') if num == 3: #借出DVD name = input('请输入DVD名字:') while name not in dvds.keys(): name = input('DVD不存在,请重新输入DVD的名字:') if dvds.get(name).state == 0: print(name + '已借出') else: dvds.get(name).state = 0 print(name + '借出成功!') if num == 4: name = input('请输入要归还的DVD名字:') while name not in dvds.keys(): name = input('DVD不存在,请重新输入;') if dvds.get(name).state == 1: print('DVD 未借出') else: days = int(input('请输入借出天数:')) print('请刷卡:',int(dvds.get(name).price)*days,'元') dvds.get(name).state = 0 print('归还成功!')
单例模式:
该模式的主要目的是确保某一个类只有一个实例存在,避免内存浪费。
(程序如果并发量大的话,内存里就会存在非常多功能上一模一样的对象。存在这些对象肯定会消耗内存,对于这些功能相同的对象可以在内存中仅创建一个,需要时都去调用)
工厂类:
在一个类中生成很多对象, 简单工厂模式(Simple Factory Pattern)
是通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类 并且重写父类方法。
#四则运算的父类,接收用户输入的数值 Operation
OperationAdd OperationSub OperationMul OperationDiv OperationFactory(object)
class Operation: def __init__(self,numA,numB): self.numA = numA self.numB = numB def yunsuan(self): pass class OperationAdd(Operation): def __init__(self,numA,numB): super().__init__(numA,numB) def yunsuan(self): return self.numA + self.numB class OperationSub(Operation): def __init__(self, numA, numB): super().__init__(numA, numB) def yunsuan(self): return self.numA - self.numB class OperationMul(Operation): def __init__(self, numA, numB): super().__init__(numA, numB) def yunsuan(self): return self.numA * self.numB class OperationDiv(Operation): def __init__(self, numA, numB): super().__init__(numA, numB) def yunsuan(self): return self.numA // self.numB #工厂类 class OperationFactory(object): @classmethod def getOperation(cls,fu,numA,numB): if '+'.__eq__(fu): return OperationAdd(numA,numB) elif '-'.__eq__(fu): return OperationSub(numA,numB) elif '*'.__eq__(fu): return OperationMul(numA,numB) elif '/'.__eq__(fu): return OperationDiv(numA,numB) if '__main__'==__name__: numA = int(input('请输入第一个操作数:')) numB = int(input('请输入第二个操作数:')) fu = input('请输入操作符:') #返回与操作符对应的 运算对象 Opera = OperationFactory.getOperation(fu,numA,numB) jg = Opera.yunsuan() print('运算结果;',jg)
isinstance()函数 判断是否 继承关系 某一个变量是否是某一个数据类型(例子接上面)
getattr(类名/对象名)、setattr(类名/对象名)以及hasattr(类名/对象名,'属性名'),
类名/对象名有 __getattribute__ __setattr__ 没有__hasattr__()
if isinstance(Oper,OpreationAdd) print('创建的为加法类型')
Oper = OperationFactory.getOpreation('+',6,9) print(Oper.__getattribute__('numA')) #打印6如果不能获取__getattribute__,可以通过setattr增加属性和值
Oper.__setattr__('numC',7) print(Oper.__getattribute__('numC'))可以通过print(dir(Opre)),打印出所有可以用的内置函数
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'n1', 'n2', 'suan']
可以直接操作一个对象的 形态-
给类动态添加函数,只能在类级别添加,所有对象都能用,给某一个对象添加
def set_score(self, score):
self.score = score
Student.set_score = set_score
动态语言的灵活性:
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,
来限制该class实例能添加的属性
class 类名:
_slots__ = ('name', 'age') #第一句
@property 注解优化getter setter--> @函数名.setter
__call__ 直接在实例本身上调用 s = Student('Michael') s()
通过callable()函数,我们就可以判断一个对象是否是“可调用”对象。
总结:
不同的类对同一个信息/动作,做出不同的解释,执行不一样的代码:
3个必要条件:
1. 发生继承关系
2.子类重写父类
3.里氏代换原则
使用方式:
以父类类型为形参
好处:节省代码,更符合现实逻辑