一、
1.1面向过程编程:过程二字为重点,是指解决问题的步骤。类似一条流水线,机械式的思维方式
优点:复杂的流程流程化,进而简单化。
缺点:可扩展性差
面向对象编程:对象为重点,对象就是”数据“和”功能“的组成。
优点:可扩展性强,
缺点:编程复杂度高
应用场景:用户需求经常变化,互联网应用,游戏,企业
1.2类:是一系列对象相似特征与技能的结合体。强调:站的角度不一样,得到的分类是不一样的。
现实中:是先有类,再有对象。
在程序中:是先定义类,后调用类来产生对象。
类的用途:属性----增、删、改、查、
类的定义:
#先定义类 class LuffyStudent: school='luffycity' #数据属性 def learn(self): #函数属性 print('is learning')
类体内的代码在类定义阶段就会执行!!!,可以使用__dict__来查看。
#__init__方法用来为对象定制对象自己独有的特征 class LuffyStudent: school='luffycity' def __init__(self,name,sex,age): #对象的独有特征 self.Name=name self.Sex=sex self.Age=age def learn(self): # 对象的公共特征 print('is learning') def eat(self): print('is sleeping') #后产生对象 stu1=LuffyStudent('王二丫','女',18) #LuffyStudent.__init__(stu1,'王二丫','女',18) print(stu1.__dict__) >>>>>>{'Name': '王二丫', 'Sex': '女', 'Age': 18} #加上__init__方法后,实例化的步骤 # 1、先产生一个空对象stu1 # 2、LuffyStudent.__init__(stu1,'王二丫','女',18)
类中的数据属性:是所以对象共有的
类中的函数属性:是绑定给对象使用的,绑定到不同的对象是不同的绑定方法,对象调用绑定方式时,会把对象本身当作第一个传入,传给self
pyrhon中一切皆对象。
1.3继承:指的是类与类之间的关系,主要功能就是解决代码中用的问题;是一种创建新类的方式,新建的类可以继承一个或者多个父类,新建的类可称为子类和派生类,父类又可称为基类或者超类。
内置属性可以用通过__bases__来查看类继承的所有父类
属性查找:1.对象本身>>>2.对象的类>>>>3.父类
继承多个父类时的属性查找顺序:python会解析顺序(mro)列表,其遵循的原则:1.子类会先于父类被检查;2.多个父类会根据他们在列表中的顺序被检查;3.如果下一个类存在两个合法的选择,会选择第一个父类。
1.4派生:
子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
在子类派生出新的方法中重用父类的方法:
方式一:指名道姓(不依赖继承)【父类名称.方法名称(self,参数)】
方式二:super() (依赖继承) Python2:---【super(对象本身的类名,self).方法名称(具体的数据)】 python3---【super().方法名称(具体的数据)】
1.5组合:在一个类中以另外一个类的对象作为数据属性,称为类的组合
class Date: def __init__(self,year,mon,day): self.year=year self.mon=mon self.day=day def tell_info(self): print('%s-%s-%s' %(self.year,self.mon,self.day))
二、抽象类
import abc class Animal(metaclass=abc.ABCMeta): #只能被继承,不能被实例化 all_type='animal' @abc.abstractmethod def run(self): pass @abc.abstractmethod def eat(self): pass # animal=Animal()
class People(Animal):
def run(self):
print('people is running')
def eat(self):
print('people is eating')
三、多态与多态性
多态指一类事物拥有多种形态
多态性指在不考虑实例类型的情况下使用实例
多态性分为静态多态性和动态多态性
多态性的好处:
1.增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
2.增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
四、封装
封装指的是如何进行属性的隐藏
如何进行封装:使用双下划线(__)开头的方式将属性隐藏起来(设置成私有的)
其实所有的双下划线开头的名称都会在类定义阶段变形,且只变形一次。
class A: __N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N def __init__(self): self.__X=10 #变形为self._A__X def __foo(self): #变形为_A__foo print('from A') def bar(self): self.__foo() #只有在类内部才可以通过__foo的形式访问到. #A._A__N是可以访问到的, #这种,在外部是无法通过__x这个名字访问到。
变形的特点:
1.在类的外部无法直接访问属性;可间接访问_类名__属性。如:_A__foo
2.类的内部可以直接访问;直接访问:__属性
3.子类无法覆盖父类__开头的属性。
封装的意义:
封装的数据属性:明确的区分内外。把数据隐藏起来,然后对外提供操作该数据的接口,在接口内附加上对该数据的限制,已完成对该数据属性操作的严格限制。
封装的方法:目的是隔离复杂度
封装与扩展性:封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
property(特性):property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值。
如何使用:
class People: def __init__(self,name,weight,height): self.name=name self.weight=weight self.height=height @property def bmi(self): return self.weight / (self.height**2) p1=People('jake',80,1.95) print(p1.bmi)
绑定方法与非绑定方法
一、绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入【自动传值】):
1. 绑定到类的方法:用classmethod装饰器装饰的方法。
为类量身定制
类.boud_method(),自动将类当作第一个参数传入
(其实对象也可调用,但仍将类当作第一个参数传入)
2. 绑定到对象的方法:在类内定义的没有被任何装饰器装饰的方法。
为对象量身定制
对象.boud_method(),自动将对象当作第一个参数传入
(属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)
二:非绑定方法:用staticmethod装饰器装饰的方法
1. 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。就是一个普通工具而已
注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说。
反射:通过字符串映射到对象的属性
hasattr(对象名/类,'属性') 判断有没有这个属性
getattr(对象名/类,'属性') 拿到对象的属性
setattr(对象名/类,'属性') 修改对象的属性
delattr(对象名/类,'属性') 删除对象的属性
内置方法介绍:链接
item系列:
class Foo: #Dict def __init__(self,name): self.name=name def __getitem__(self, item): #item='namexxx' # print('getitem...') return self.__dict__.get(item) def __setitem__(self, key, value): # print('setitem...') # print(key,value) self.__dict__[key]=value def __delitem__(self, key): # print('delitem...') # print(key) del self.__dict__[key] obj=Foo('egon') print(obj.__dict__) # 查看属性: obj.属性名 print(obj['namexxx']) #obj.name # 设置属性: obj.sex='male' obj['sex']='male' print(obj.__dict__) print(obj.sex) # 删除属性 del obj.name del obj['name'] print(obj.__dict__)
__str__内置方法:
class People: def __init__(self,name,age): self.name=name self.age=age def __str__(self): # print('====>str') return '<name:%s,age:%s>' %(self.name,self.age) obj=People('egon',18) print(obj) #res=obj.__str__()
__del__内置方法:
class Open: def __init__(self,filename): print('open file.......') self.filename=filename def __del__(self): print('回收操作系统资源:self.close()') f=Open('settings.py') del f #f.__del__() print('----main------') #del f #f.__del__()
一切皆对象,对象可以怎么用?
1.都可以被引用,x=obj
2.都可以当做函数的参数传入
3.都可以当做函数的返回值
4.都可以当做容器类的元素,l = [func,time,obj,1]
exec的用法:
#exec:三个参数 #参数一:包含一系列python代码的字符串 #参数二:全局作用域(字典形式),如果不指定,默认为globals() #参数三:局部作用域(字典形式),如果不指定,默认为locals() #可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中 g={ 'x':1, 'y':2 } l={} exec(''' global x,z x=100 z=200 m=300 ''',g,l) print(g) #{'x': 100, 'y': 2,'z':200,......} print(l) #{'m': 300}
元类:产生类的类称为元类,默认所有用class定义的类的元类是type
# 定义类的两种方式: # 方式一:class class Chinese: # Chinese=type(...) country = 'China' def __init__(self, namem, age): self.name = namem self.age = age def talk(self): print('%s is talking' % self.name) # print(Chinese) obj = Chinese('egon', 18) print(obj, obj.name, obj.age) # 方式二:type # 定义类的三要素:类名,类的基类们,类的名称空间 class_name = 'Chinese' class_bases = (object,) # 默认为object class_body = """ country='China' def __init__(self,namem,age): self.name=namem self.age=age def talk(self): print('%s is talking' %self.name) """ class_dic = {} exec(class_body, globals(), class_dic) print(class_dic)
Chinese = type(class_name,class_bases,class_dic)
如何自定义元类来控制类的创建
class Mymeta(type): def __init__(self, class_name, class_bases, class_dic): if not class_name.istitle(): raise TypeError('类名的首字母必须大写') if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): raise TypeError('必须有注释,且注释不能为空') # 主动抛出异常 super(Mymeta, self).__init__(class_name, class_bases, class_dic) # 继承原来的属性 class Chinese(object, metaclass=Mymeta): # 指定元类 """中文人的类""" country = 'China' def __init__(self, name, age): self.name = name self.age = age def talk(self): print('%s is talking' % self.name) # Chinese=Mymeta(class_name,class_bases,class_dic)
如何自定义元类来控制类的实例化
__call__
class Foo: def __call__(self, *args, **kwargs): print(self) print(args) print(kwargs) obj=Foo() #1、要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法,该方法会在调用对象时自动触发 #2、调用obj的返回值就是__call__方法的返回值 res=obj(1,2,3,x=1,y=2)
由此可得,调用一个对象,就是在触发对象所在类的__call__方法的执行,同理得类本身也存在一个__call__方法。分析如下:
class Mymeta(type): # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类 def __call__(self, *args, **kwargs): # self=<class '__main__.Foo'> # 1、调用__new__产生一个空对象obj obj = self.__new__(self) # 此处的self是类Foo,必须传参,代表创建一个Foo的对象obj # 2、调用__init__初始化空对象obj self.__init__(obj, *args, **kwargs) # 3、返回初始化好的对象obj return obj class Foo(object, metaclass=Mymeta): school = 'beida' def __init__(self, name, age): self.name = name self.age = age def say(self): print('%s says welcome to the BeiDa to learn Python' % self.name) # 调用Foo就是在调用Foo类中的__call__方法 # 然后将Foo传给self,溢出的位置参数传给*,溢出的关键字参数传给** # 调用Foo的返回值就是调用__call__的返回值 t1 = Foo('jake', 22) print(t1) # 123
默认的在调用Foo时会发生三件事:
1.产生一个空对象
2.调用__init__方法初始化对象obj
3.返回初始化以后的对象obj
异常处理:异常时错误发生的信号,一旦程序出错,并且程序没有处理这个错误,就会抛出异常,并且程序的运行就会终止。
错误的类型,分成两种:
1.语法错误,(在程序运行之前就会检测语法,需要先改正过来才可以运行程序);
2.逻辑错误
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入模块或包;基本上是路径问题或名称错误 IndentationError 语法错误(的子类) ;代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了) TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
异常处理:为了保证程序的容错性,在遇到错误时程序不会奔溃,我们就需要进行异常处理。
1.如果错误发生的条件是可以预知的我们用if进行处理,在错误发生之前进行处理
AGE=10 while True: age=input('>>: ').strip() if age.isdigit(): #只有在age为字符串形式的整数时,下列代码才不会出错,该条件是可预知的 age=int(age) if age == AGE: print('you got it') break
2.如果错误发生的条件是不可以预知的,则需要用try.......except....处理,在错误发生之后进行处理
#基本语法为 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()
try....except...详细用法:
#1 异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。 s1 = 'hello' try: int(s1) except IndexError as e: # 未捕获到异常,程序直接报错 print e #2 多分支 s1 = 'hello' try: int(s1) except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) #3 万能异常Exception s1 = 'hello' try: int(s1) except Exception as e: print(e) #4 多分支异常与万能异常 #4.1 如果你想要的效果是,无论出现什么异常,我们统一丢弃,或者使用同一段代码逻辑去处理他们,那么骚年,大胆的去做吧,只有一个Exception就足够了。 #4.2 如果你想要的效果是,对于不同的异常我们需要定制不同的处理逻辑,那就需要用到多分支了。 #5 也可以在多分支后来一个Exception s1 = 'hello' try: int(s1) except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) except Exception as e: print(e) #6 异常的其他机构 s1 = 'hello' try: int(s1) except IndexError as e: print(e) except KeyError as e: print(e) except ValueError as e: print(e) #except Exception as e: # print(e) else: print('try内代码块没有异常则执行我') finally: print('无论异常与否,都会执行该模块,通常是进行清理工作') #7 主动触发异常 try: raise TypeError('类型错误') except Exception as e: print(e) #8 自定义异常 class EgonException(BaseException): def __init__(self,msg): self.msg=msg def __str__(self): return self.msg try: raise EgonException('类型错误') except EgonException as e: print(e) #9 断言:assert 条件 assert 1 == 1 assert 1 == 2 #10 总结try..except 1:把错误处理和真正的工作分开来 2:代码更易组织,更清晰,复杂的工作任务更容易实现; 3:毫无疑问,更安全了,不至于由于一些小的疏忽而使程序意外崩溃了;