1.1 继承与派生
1.1.1 什么是继承
是一种新建类的方式,新建的类称为子类,子类会遗传父类的属性,可以减少代码冗余
在python中,子类(派生类)可以继承一个或者多个父类(基类,超类)
python中类的继承分为:单继承和多继承
class Parent1: #定义父类 pass class Parent2(object): #定义父类 pass class Sub1(Parent1): ##单继承,基类是Parent1,派生类是Sub1 pass class Sub2(Parent1,Parent2): #python支持多继承,用逗号分隔开多个继承的类 pass
查看继承
print(Sub1.__bases__) #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 print(Sub2.__bases__) 提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。 print(Parent1.__bases__) print(Parent2.__bases__)
在Python2中类分为两种:
1、经典类:指的就是没有继承object类的类,以及该类的子类
2、新式类:指的就是继承object类的类,以及该类的子类
在Python3中统一都为新式类
class OldboyPeople: school = ‘Oldboy‘ def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex)) class OldboyStudent(OldboyPeople): def learn(self): print(‘%s is learning‘ %self.name) def tell_info(self): print(‘我是学生:‘,end=‘‘) print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex)) class OldboyTeacher(OldboyPeople): def teach(self): print(‘%s is teaching‘ %self.name) def tell_info(self): print(‘我是老师:‘,end=‘‘) print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex)) stu1=OldboyStudent(‘牛榴弹‘,18,‘male‘) teacher1=OldboyTeacher(‘egon‘,18,‘male‘) print(stu1.__dict__) print(stu1.school) print(stu1.x) stu1.tell_info() teacher1.tell_info()
属性查找
继承描述的是子类与父类之间的关系,是一种什么是什么的关系。要找出这种关系,必须先抽象再继承
抽象即抽取类似或者说比较像的部分。
class Foo: def f1(self): print(‘Foo.f1‘) def f2(self): #self=obj print(‘Foo.f2‘) self.f1() #obj.f1() class Bar(Foo): def f1(self): print(‘Bar.f1‘) obj=Bar() print(obj.__dict__) obj.f2()
1.2 子类重用父类方法part1:
在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时
我们不可能从头开始写一个类B,这就用到了类的继承的概念。
通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用
class OldboyPeople: school = ‘Oldboy‘ def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex)) class OldboyStudent(OldboyPeople): def learn(self): print(‘%s is learning‘ %self.name) def tell_info(self): print(‘我是学生:‘,end=‘‘) # self.tell_info() #stu1.tell_info() OldboyPeople.tell_info(self) stu1=OldboyStudent(‘牛榴弹‘,18,‘male‘) stu1.tell_info()
class OldboyPeople: school = ‘Oldboy‘ def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex)) class OldboyStudent(OldboyPeople): def __init__(self,name,age,sex,course,stu_id): # self.name=name # self.age=age # self.sex=sex OldboyPeople.__init__(self,name,age,sex) self.course=course self.stu_id=stu_id def learn(self): print(‘%s is learning‘ %self.name) def tell_info(self): print(‘我是学生:‘,end=‘‘) # self.tell_info() #stu1.tell_info() OldboyPeople.tell_info(self) stu1=OldboyStudent(‘牛榴弹‘,18,‘male‘,‘Python‘,1) stu1.tell_info()
1.3 组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
class OldboyPeople: school = ‘Oldboy‘ def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex)) class OldboyStudent(OldboyPeople): def __init__(self,name,age,sex,course,stu_id,year,mon,day): OldboyPeople.__init__(self,name,age,sex) self.course=course self.stu_id=stu_id self.year=year self.mon=mon self.day=day def learn(self): print(‘%s is learning‘ %self.name) def tell_info(self): print(‘我是学生:‘,end=‘‘) # self.tell_info() #stu1.tell_info() OldboyPeople.tell_info(self) def tell_birth(self): print(‘出生日期是:<%s-%s-%s>‘ %(self.year,self.mon,self.day)) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level,salary,year,mon,day): OldboyPeople.__init__(self, name, age, sex) self.level=level self.salary=salary self.year=year self.mon=mon self.day=day def tell_birth(self): print(‘出生日期是:<%s-%s-%s>‘ %(self.year,self.mon,self.day)) def teach(self): print(‘%s is teaching‘ % self.name) def tell_info(self): print(‘我是老师:‘, end=‘‘) OldboyPeople.tell_info(self) stu1=OldboyStudent(‘牛榴弹‘,18,‘male‘,‘Python‘,1,1983,3,11) teacher1=OldboyTeacher(‘啊狗‘,18,‘female‘,10,4000,1990,2,17) stu1.tell_birth() teacher1.tell_birth()
组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,
1.继承的方式
通过继承建立了派生类与基类之间的关系,它是一种‘是‘的关系,比如白马是马,人是动物。
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人
2.组合的方式
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...
class OldboyPeople: school = ‘Oldboy‘ def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex)) class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, course, stu_id,): OldboyPeople.__init__(self, name, age, sex) self.course = course self.stu_id = stu_id def learn(self): print(‘%s is learning‘ % self.name) def tell_info(self): print(‘我是学生:‘, end=‘‘) # self.tell_info() #stu1.tell_info() OldboyPeople.tell_info(self) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level, salary): OldboyPeople.__init__(self, name, age, sex) self.level = level self.salary = salary def teach(self): print(‘%s is teaching‘ % self.name) def tell_info(self): print(‘我是老师:‘, end=‘‘) OldboyPeople.tell_info(self) class Date: def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day def tell_birth(self): print(‘出生日期是:<%s-%s-%s>‘ % (self.year, self.mon, self.day)) stu1 = OldboyStudent(‘牛榴弹‘, 18, ‘male‘, ‘Python‘, 1,) date_obj1=Date(1983, 3, 11) stu1.birth=date_obj1 teacher1 = OldboyTeacher(‘啊狗‘, 18, ‘female‘, 10, 4000) date_obj2=Date( 1990, 2, 17) teacher1.birth=date_obj2 # print(stu1.birth) # print(teacher1.birth) stu1.birth.tell_birth() #date_obj1.tell_birth() teacher1.birth.tell_birth()
class OldboyPeople: school = ‘Oldboy‘ def __init__(self, name, age, sex,date_obj): self.name = name self.age = age self.sex = sex self.birth = date_obj def tell_info(self): print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex)) class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, course, stu_id,date_obj): OldboyPeople.__init__(self, name, age, sex,date_obj) self.course = course self.stu_id = stu_id def learn(self): print(‘%s is learning‘ % self.name) def tell_info(self): print(‘我是学生:‘, end=‘‘) # self.tell_info() #stu1.tell_info() OldboyPeople.tell_info(self) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level, salary,date_obj): OldboyPeople.__init__(self, name, age, sex,date_obj) self.level = level self.salary = salary def teach(self): print(‘%s is teaching‘ % self.name) def tell_info(self): print(‘我是老师:‘, end=‘‘) OldboyPeople.tell_info(self) class OldboySale(OldboyPeople): def __init__(self,name,age,sex,kpi,date_obj): OldboyPeople.__init__(self,name,age,sex,date_obj) self.kpi=kpi def tell_info(self): print(‘我是销售: ‘,end=‘‘) OldboyPeople.tell_info(self) class Date: def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day def tell_birth(self): print(‘出生日期是:<%s-%s-%s>‘ % (self.year, self.mon, self.day)) date_obj1=Date(1983, 3, 11) sale1=OldboySale(‘歪歪‘,38,‘male‘,7.3,date_obj1) # sale1.birth=date_obj1 # sale1.tell_info() sale1.birth.tell_birth()
class OldboyPeople: school = ‘Oldboy‘ def __init__(self, name, age, sex,date_obj): self.name = name self.age = age self.sex = sex self.birth = date_obj def tell_info(self): print(‘<名字:%s 年龄:%s 性别:%s>‘ % (self.name, self.age, self.sex)) class OldboyStudent(OldboyPeople): def __init__(self, name, age, sex, stu_id,date_obj): OldboyPeople.__init__(self, name, age, sex,date_obj) self.courses=[] self.stu_id = stu_id def learn(self): print(‘%s is learning‘ % self.name) def tell_info(self): print(‘我是学生:‘, end=‘‘) # self.tell_info() #stu1.tell_info() OldboyPeople.tell_info(self) class OldboyTeacher(OldboyPeople): def __init__(self, name, age, sex, level, salary,date_obj): OldboyPeople.__init__(self, name, age, sex,date_obj) self.level = level self.salary = salary self.courses=[] def teach(self): print(‘%s is teaching‘ % self.name) def tell_info(self): print(‘我是老师:‘, end=‘‘) OldboyPeople.tell_info(self) class OldboySale(OldboyPeople): def __init__(self,name,age,sex,kpi,date_obj): OldboyPeople.__init__(self,name,age,sex,date_obj) self.kpi=kpi def tell_info(self): print(‘我是销售: ‘,end=‘‘) OldboyPeople.tell_info(self) class Date: def __init__(self,year,mon,day): self.year = year self.mon = mon self.day = day def tell_birth(self): print(‘出生日期是:<%s-%s-%s>‘ % (self.year, self.mon, self.day)) class Course: def __init__(self,name,price,period): self.name=name self.price=price self.period=period def tell_info(self): print(‘课程详细信息:<%s,%s,%s>‘ %(self.name,self.price,self.period)) Python=Course(‘python自动化养猪‘,3000,‘3mon‘) Linux=Course(‘大数据分析-linux‘,3000,‘3mon‘) date_obj=Date(1993,3,13) teacher1=OldboyTeacher(‘egon‘,18,‘male‘,100,3000,date_obj) teacher1.courses.append(Python) teacher1.courses.append(Linux) # print(teacher1.courses) for course in teacher1.courses: course.tell_info() stu1=OldboyStudent(‘xxxx‘,28,‘female‘,1,date_obj) # print(stu1.courses) stu1.courses.append(Python) stu1.courses.append(Linux) print(stu1.courses)
1.4 抽象类
1.4.1 什么是抽象类
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
为什么要有抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。
比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西。
从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。
从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的,即将揭晓答案
import abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod def eat(self): pass @abc.abstractmethod def run(self): pass class People(Animal): def eat(self): pass def run(self): pass class Pig(Animal): def eat(self): pass def run(self): pass peo1=People() pig1=Pig()
1.4.2 抽象类与接口
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
import abc class File(metaclass=abc.ABCMeta): @abc.abstractmethod def read(self): pass @abc.abstractmethod def write(self): pass class Disk(File): def read(self): print(‘disk read‘) def write(self): print(‘disk write‘) class Process(File): def read(self): print(‘Process read‘) def write(self): print(‘Process write‘) d=Disk() p=Process() d.read() d.write() p.read() p.write()
1.5 继承的实现原理
继承顺序
在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)
如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性
如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先
图1-1
图1-2
class A(object): # def test(self): # print(‘from A‘) pass class B(A): # def test(self): # print(‘from B‘) pass class C(A): # def test(self): # print(‘from C‘) pass class D(B): # def test(self): # print(‘from D‘) pass class E(C): # def test(self): # print(‘from E‘) pass class F(D,E): # def test(self): # print(‘from F‘) pass f1=F() print(F.mro()) # f1.test()
1.6 子类重用父类的方法part2
1.6.1 方法一:指名道姓,即父类名.父类方法()
class OldboyPeople: school = ‘Oldboy‘ def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def tell_info(self): print(‘<名字:%s 年龄:%s 性别:%s>‘ %(self.name,self.age,self.sex)) class OldboyStudent(OldboyPeople): def __init__(self,name,age,sex,course): # OldboyPeople.__init__(self,name,age,sex) super(OldboyStudent,self).__init__(name,age,sex) self.course=course def tell_info(self): print(‘我是学生: ‘,end=‘‘) # OldboyPeople.tell_info(self) super(OldboyStudent,self).tell_info() stu1=OldboyStudent(‘egon‘,18,‘male‘,‘python‘) # print(stu1.name,stu1.age,stu1.sex,stu1.course) stu1.tell_info()
1.6.2 方法二:super()
class Foo: def f2(self): print(‘====?>‘) def f1(self): print(‘Foo.f1‘) # super().f2() Foo.f2(123) class Bar: def f2(self): print(‘Bar f2‘) class Sub(Foo,Bar): pass s=Sub() # print(Sub.mro()) # [<class ‘__main__.Sub‘>, # <class ‘__main__.Foo‘>, # <class ‘__main__.Bar‘>, # <class ‘object‘>] s.f1()
强调:二者使用哪一种都可以,但最好不要混合使用
即使没有直接继承关系,super仍然会按照mro继续往后查找
1.6.3 指名道姓与super()的区别
当你使用super()函数时,Python会在MRO列表上继续搜索下一个类。只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次(注意注意注意:使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表)
1.7 多态与多态性
1.7.1 多态:同一种事物的多种形态
import abc class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod def speak(self): pass class Pig(Animal): def speak(self): print(‘哼哼‘) class Dog(Animal): def speak(self): print(‘汪汪‘) class People(Animal): def speak(self): print(‘say hello‘) people1=People() dog1=Dog() pig1=Pig()
1.7.2 多态性:指的是在不考虑对象具体类型的情况下,直接使用对象(对象的方法)
people1.speak() dog1.speak() pig1.speak() def talk(obj): obj.speak() talk(people1) #people1.speak() talk(dog1) talk(pig1) list,str,tuple l=list([1,2,3]) s=str(‘hello‘) t=tuple((1,‘a‘,4,‘b‘,‘c‘)) l.__len__() s.__len__() t.__len__() print(len(l)) print(len(s)) print(len(t))
多态性是指在不考虑实例类型的情况下使用实例
多态:同一种事物的多种形态
1.7.3 多态性分为静态多态性和动态多态性
静态多态性:如任何类型都可以用运算符+进行运算
动态多态性:
import abc class Pig: def speak(self): print(‘哼哼‘) class Dog: def speak(self): print(‘汪汪‘) class People: def speak(self): print(‘say hello‘) class Radio: def speak(self): print(‘radio speak‘) people1=People() dog1=Dog() pig1=Pig()
1.7.4 为什么要用多态性
其实大家从上面多态性的例子可以看出,我们并没有增加什么新的知识,也就是说python本身就是支持多态性的,这么做的好处是什么呢?
1.增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
import abc class Disk: def read(self): print(‘disk read‘) def write(self): print(‘disk write‘) class Process: def read(self): print(‘Process read‘) def write(self): print(‘Process write‘)
1.8 封装之如何隐藏
1.8.1 封装:
1、__开头的属性只是一种语法意义上的变形,并不会真的限制外部的访问
2、这种变形只在类定义阶段发送一次,类定义之后再新增的__开头的属性不会变形
3、这种隐藏只对外不对内,因为类内部定义的属性在类定义阶段统一发生变形
先看如何隐藏
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
class Foo: __N=1 #_Foo__N=1 def __init__(self,x,y): self.x=x self.__y=y #self._Foo__y=y def __f1(self): #_Foo__f1 print(‘f1‘) def f2(self): print(self.__N,self.__y) #print(self._Foo__N,self._Foo__y) print(Foo.__N) print(Foo.__f1) print(Foo.__dict__) print(Foo._Foo__N) print(Foo._Foo__f1) obj=Foo(1,2) print(obj.__dict__) print(obj._Foo__y) Foo.__M=2 print(Foo.__dict__) print(Foo.__M) obj=Foo(1,2) print(obj.__dict__) obj.__z=3 print(obj.__dict__) print(obj.__z) obj=Foo(1,2) obj.f2() print(obj.__N)
这种变形需要注意的问题是:
1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,主要用来限制外部的直接访问。
2.变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形
3.继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
class Foo: def __f1(self): #_Foo__f1 print(‘Foo.f1‘) def f2(self): print(‘Foo.f2‘) self.__f1() #b._Foo__f1() class Bar(Foo): def __f1(self): #_Bar__f1 print(‘Bar.f1‘) b=Bar() b.f2()
1.9 封装之真正意义
封装数据属性的目的:外部无法直接访问数据属性,类内部开放接口,然后可以在接口内严格控制对属性的增删改查操作
class People: def __init__(self,name,age): # self.__name=name # self.__age=age self.set_info(name,age) def tell_info(self): print("姓名:<%s> 年龄:<%s>" %(self.__name,self.__age)) def set_info(self,name,age): if type(name) is not str: raise TypeError(‘name must be str‘) if type(age) is not int: raise TypeError(‘age must be int‘) self.__name=name self.__age=age p=People(‘egon‘,18) # print(p.__name,p.__age) # p.tell_info() # p.set_info(‘EGON‘,20) p.set_info(3537,20) p.tell_info()
封装方法的目的是:隔离复杂度
class ATM: def __card(self): print(‘插卡‘) def __auth(self): print(‘用户认证‘) def __input(self): print(‘输入取款金额‘) def __print_bill(self): print(‘打印账单‘) def __take_money(self): print(‘取款‘) def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money()
1.10 封装之property
1.10.1 什么是特性property
property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)
成人的BMI数值:
过轻:低于18.5
正常:18.5-23.9
过重:24-27
肥胖:28-32
非常肥胖, 高于32
体质指数(BMI)=体重(kg)÷身高^2(m)
EX:70kg÷(1.75×1.75)=22.86
class People: def __init__(self,name,age,height,weight): self.name=name self.age=age self.height=height self.weight=weight @property def bmi(self): return self.weight / (self.height ** 2) egon=People(‘egon‘,18,1.80,75) egon.height=1.82 # print(egon.bmi()) print(egon.bmi)
1.10.2 为什么要用property
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
class People: def __init__(self,name,): self.__name=name @property def name(self): return self.__name @name.setter def name(self,obj): if type(obj) is not str: raise TypeError(‘name must be str‘) self.__name=obj @name.deleter def name(self): # del self.__name raise PermissionError(‘不让删‘) egon=People(‘egon‘) # print(egon.name) # egon.name=‘EGON‘ # egon.name=35357 # print(egon.name) del egon.name # print(egon.name)
封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
1.11 绑定方法与非绑定方法
一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入):
1. 绑定到类的方法:用classmethod装饰器装饰的方法。
为类量身定制
类.boud_method(),自动将类当作第一个参数传入
(其实对象也可调用,但仍将类当作第一个参数传入)
2. 绑定到对象的方法:没有被任何装饰器装饰的方法。
为对象量身定制
对象.boud_method(),自动将对象当作第一个参数传入
(属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)
二:非绑定方法:用staticmethod装饰器装饰的方法
1. 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。就是一个普通工具而已
注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说
1.11.1 绑定方法
绑定给对象的方法(略)
绑定给类的方法(classmethod)
classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入),python为我们内置了函数classmethod来把类中的函数定义成类方法
import settings import hashlib import time class MySQL: def __init__(self,host,port): self.host=host self.port=port def func(self): print(‘%s 说:你好啊我的天‘ %self.name) @classmethod def from_conf(cls): return cls(settings.HOST,settings.PORT) @staticmethod def create_id(n): m=hashlib.md5() m.update(str(time.clock()+n).encode(‘utf-8‘)) return m.hexdigest() # conn=MySQL(‘127.0.0.1‘,3306)
#绑定方法:绑定给谁就应该由谁来调用,谁来调用就会把谁当做第一个参数自动传入
1.11.2 非绑定方法
在类内部用staticmethod装饰的函数即非绑定方法,就是普通函数
statimethod不与类或对象绑定,谁都可以调用,没有自动传值效果
conn=MySQL.from_conf() # print(conn.host,conn.port) print(MySQL.create_id(1)) print(conn.create_id(2))
1.12 内置函数补充
l=list([]) print(type(l) is list) print(isinstance(l,list)) class Foo: pass class Bar(Foo): pass print(issubclass(Bar,Foo))
1.13 反射
1.13.1 什么是反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。
class Foo: def __init__(self,name): self.name=name def f1(self): print(‘===>f1‘) obj=Foo(‘egon‘) obj.name #obj.__dict__[‘name‘]
1.13.2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
下列方法适用于类和对象(一切皆对象,类本身也是一个对象)
hasattr
print(hasattr(obj,‘name‘)) #obj.name print(hasattr(obj,‘f1‘))#obj.f1
getattr
if hasattr(obj,‘f1‘): f=getattr(obj,‘f1‘) #f=obj.f1 f() print(getattr(obj,‘xxx‘,None))
setattr
obj.x=1 setattr(obj,‘x‘,1) print(obj.__dict__)
delattr
del obj.name delattr(obj,‘name‘) print(obj.__dict__)
导入其他模块,利用反射查找该模块是否存在某个方法
class FtpClient: def __init__(self,host,port): self.host=host self.port=port self.conn=‘xxx‘ def interactie(self): while True: cmd=input(‘>>: ‘).strip() if not cmd:continue cmd_l=cmd.split() print(cmd_l) if hasattr(self,cmd_l[0]): func=getattr(self,cmd_l[0]) func(cmd_l) def get(self,cmd_l): print(‘geting...‘,cmd_l) def put(self,cmd_l): print(‘putting....‘,cmd_l) client=FtpClient(‘1.1.1.1‘,23) client.interactie()
1.14 类的内置方法
__str__
l=list([1,2,3,4]) print(l) class People: def __init__(self,name,age): self.name=name self.age=age
def __str__(self): return ‘<name:%s age:%s>‘ %(self.name,self.age) egon=People(‘egon‘,18) print(egon) #print(egon.__str__())
注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__
__del__
f=open(‘a.txt‘,‘w‘,encoding=‘utf-8‘) f.read() f.close()
class Foo: def __del__(self): print(‘del---->‘) obj=Foo() del obj # print(‘主‘)
setting.py
HOST=‘10.10.10.9‘ PORT=3306
class Mysql: def __init__(self,host,port): self.host=host self.port=port self.conn=Connect(host,port) def __del__(self): self.conn.close() m=Mysql(‘1.1.1.1‘,3306) m.conn.execute(‘select * from db.user;‘)
1.15 异常处理
1.15.1 什么是异常
异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止),在python中,错误触发的异常如下
而错误分成两种
1.语法错误(这种错误,根本过不了python解释器的语法检测,必须在程序执行前就改正)
2.逻辑错误
# x= raise TypeError(‘xxxx‘)
为了保证程序的健壮性与容错性,即在遇到错误时程序不会崩溃,我们需要对异常进行处理,
如果错误发生的条件是可预知的,我们需要用if进行处理:在错误发生之前进行预防
#基本语法为
try: 被检测的代码块 except 异常类型: try中一旦检测到异常,就执行这个位置的逻辑 #举例 try: f=open(‘a.txt‘) g=(line.strip() for line in f) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) except StopIteration: f.close()
原文地址:https://www.cnblogs.com/x-y-j/p/8342779.html