其实就是一个解决问题的步骤,设计一条流水线,完成机械式的操作
优点:复杂的问题流程化,进而简单化
缺点:可扩展性差(流水线式开发中,当需要对其中进行扩展的时候,很可能对后面的功能造成影响导致扩展非常困难)
适用于扩展需求低的开发项目
应用场景:简单流程特点的脚本程序
就是特征与功能的结合体,三大特性:继承、多态
优点:可扩展性强
(可扩展性是软件质量的指标之一)
缺点:编程复杂度高
应用场景:用户需求经常变化,互联网用用,游戏,企业内部应用
一系列对象相似的特征与功能的结合体
强调:不同角度得到的分类是不一样的。现实世界的认知中,是先有一个个具体的对象,后面才有类的概念;在程序的世界里,一定得先定义类,后调用类来产生对象
#先定义类
class Employee:
company= 'sony'
def career(self):
print('python programmer')
def salary(self,money):
print('月薪:%d $'%(money))
#后产生对象
emp1=Employee()
emp2=Employee()
emp3=Employee()
定义类阶段,内部代码就会运行;调用类可以‘.’直接操作属性
*setitem()
*getitem()
*delitem()
*del()
*init()用来为对象定制对象自己独有的方法
class Employee:
.......
def __init__(self,name,sex,age,):
self.Name=name
self.Sex=sex
self.Age=age
........
........
emp1=Employee('lida','男',29)
emp2 .........
emp3 .........
带__init__方法后实例化的步骤:
1,先产生一个空对象
2,触发调用__init__()函数
类实例化成对象,类中的数据属性(变量),是所有对象共有的:
print(Employee.company,id(Employee.company))
print(emp1.company,id(emp1.company))
print(emp2.company,id(emp2.company))
print(emp3.company,id(emp3.company))
输出:
sony 1574809750192
sony 1574809750192
sony 1574809750192
sony 1574809750192
(地址相同,可以看出对象取共有属性是直接取类里面的)
类中函数属性,是绑定给对象,绑定到不同的对象是不同的绑定方法
print(Employee.career)
print(emp1.career)
print(emp2.career)
print(emp3.career)
输出:
(内存地址不同)
对象调用绑定方式时,会把对象本身当成第一个参数给self
emp1.salary(8000)
输出:
月薪:8000 $
属性查找顺序:(对象本身只存放独有属性,相似特征放在类里面) 调用时优先找对象属性,如果没有再去类里面找,如果没有会去父类里找(总之查找范围在类及其父类里面),未找到则报错
xxx='from global'
class A:
..........
A.x='x from class'
A.xx='xx from class'
a=A()
a.x='from object'
print(a.x)
print(a.xx)
print(a.xxx)
输出:
from object
xx from class
Traceback (most recent call last):
File “F:/pyCode/test/object.py”, line 37, in
print(a.xxx)
AttributeError: ‘A’ object has no attribute ‘xxx’
python3统一了类与类型的概念
定义一个类型实际上就是实例化一个对象
将数据与专门操作该数据的功能整合到一起
class A:
......
def fun(self):
print('from A')
class B(A):
.......
b = B()
b.fun()
输出:
from A
python允许多继承
查找顺序:合并了所有父类的MRO列表,遵循:1,子类优先父类 1,多个父类根据他在列表中的顺序被检查,如果存在多个选择则选择第一个
查找方式:深度优先(对于经典类)和广度优先(新式类),python3都是新式类
方式一:不依赖继承,在子类中直接调用父类的方法或属性
方式二:依赖继承,super(子类的类名,self)
class student:
def __init__(self,name,age):
self.name=name
self.age=age
class course:
def __init__(self,course_name,course_time):
self.course_name=course_name
self.course_time=course_time
yexb = student('ye xiabin',31)
java=course('java',31)
yexb.course=java
这其中student类的对象以course类对象作为其属性,这种重用的方式叫做类的组合
#与一般类的区别:抽象类只能被继承不能被实例化
import abc
class warrior(metaclass=abc.ABCMeta):
playable_race='人类,兽人,牛头人'
#定义抽象方法,无需实现功能
@abc.abstractmethod
def skill(self):
pass
@abc.abstractmethod
def blood(self):
pass
@abc.abstractmethod
def armor(self):
pass
class player(warrior):
def skill(self):
print('这是技能函数')
def blood(self):
print('这是生命值函数')
def armor(self):
print('这是护甲值函数')
play_a=player()
play_a.skill()
print(paly_a.playable_race)
抽象类与一般类的区别:抽象类只能被继承不能被实例化定义抽象类的方法(@abc.abstr
actmethod),在子类里面必须实现
多态:同一类事物的多种形态
多态性:不用考虑对象的类型的情况下而直接使用对象
多态的好处:
def func(warrior):
warrior.skill()
func(play_a)
1.增加了程序的灵活性
2.增加了程序的拓展性
先解释下什么是隐藏属性:
双下划线开头:__xxxx, 在定义阶段会发生变形
class A:
__x=1
def __init__(self,name):
self.__name=name
def __foo(self):
print('run foo')
a=A('zoro')
print(a.__dict__)
输出:
{’_A__name’: ‘zoro’}
(可见: __name变形成_A__name)
特点:
1.在类外部无法直接使用它obj._attrName
2.在类内部可以直接使用 (原理:因为在你引用之前,在类的定义阶段就已经自动重命名为_className__attrName的形式了)
3.子类无法覆盖父类的隐藏属性
关于变形的注意事项:
1.这种机制并没有真正限制从外部访问隐藏属性,只要知道类名和属性名就可以拼出访问属性(_类名__属性名)
2.变形过程只在类的定义发生一次,在定义后的赋值操作不变形(外部无法对类再设置隐藏属性)
3.继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的(__className)
封装的意义和用法:
封装属性:类里面隐藏一个方法,再创建一个调用这个方法的接口,外部直接使用这个接口来设置属性
class A:
def __init__(self,name):
self.__name=name
def tell_info(self):
print(self.__name)
a=A('li')
a.tell_info()
封装方法:隔离复杂度
class ATM:
def __card(self):
print('插卡')
def __input(self):
print('输入取款金额')
def __take_money(self):
print('取款')
def withdraw(self):
self.__card()
self.__input()
self.__take_money()
aa=ATM()
aa.withdraw()
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('egon',75,1.85)
print(p1.bmi)
输出:
21.913805697589478
可以像访问数据属性一样调用一个方法
**也可以另写一个加上@bmi.setter的函数,实现修改
class People:
............
@bmi.setter
def weight(self,val):
if isinstance(val,int):
self.__weight=val
else:
print('值必须是数字')
p=People()
p.weight=70
输出:
20.45288531775018
在类内部定义的函数分为:
一.绑定方法:(绑定给谁,就应该谁来调用,谁来调用就会把调用者当作第一个参数传入)
1.绑定到对象:(一般是没有被装饰器修饰的函数)
2.绑定到类:(由@classmethod修饰)
二.非绑定方法
由@staticmethod修饰无自动传值功能,就是类里定义的普通工具,类和对象均能使用它
xSetter.py :
name='lida'
sex='boy'
age=29
(实例化成对象的不同方式:)
import xSetter
import hashlib
import time
class Person:
def __init__(self,name,sex,age):
self.id=self.create_id()
self.name=name
self.sex=sex
self.age=age
def get_person(self):
print('名字:%s 证件号:%s 性别:%s 年龄:%s'%(self.name,self.id,self.sex,self.age))
@classmethod
def conf_setter(cls):
obj=cls(xSetter.name,xSetter.sex,xSetter.age)
return obj
@staticmethod
def create_id():
local_time = str(time.time())
m=hashlib.md5(local_time.encode('utf-8'))
return m.hexdigest()
p=Person.conf_setter() *#通过绑定到类的实例化*
p.get_person()
p1 = Person('fiona','woman',31) *#绑定到对象的实例化*
p1.get_person()
输出:
名字:lida 证件号:f6242afac4a7b7126de2728070b4661c 性别:boy 年龄:29
名字:fiona 证件号:1b70e5784986d242c231f3d284f7c3aa 性别:woman 年龄:31
通过字符串映射到一个对象(或类)的属性
hasattr(obj,‘name’) # 判断对象是否存在一个叫name的属性
getattr(obj,‘name’,none) #获取属性name
setattr(obj,‘age’,29) #新增(或修改)对象的age属性
delattr(obj,‘age’) #删除属性
我们就可以实现字符串反射到属性:
class service:
def run(self):
while True:
choose = input(">>>>>:")
if hasattr(self,choose):
func = getattr(self,choose)
func()
def get(self):
print("get....")
def put(self):
print("put....")
obj = service()
obj.run()
构造函数
析构函数
…
元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为
exec参数:
参数一:字符串形式的命令
参数二:全局作用域(字典形式),如果不指定,默认为globals()
参数三:局部作用域(字典形式),如果不指定,默认为locals()
调用元类type(也可以自定义)来产生类
创建类主要分为三部分:类名,类的父类,类体
1.创建一个空字典,再用exec去执行类体
class_dic={}
exec(class_body,globals(),class_dic)
2.调用元类type(也可以自定义)来产生类Chinense
Foo=type(class_name,class_bases,class_dic) #实例化type得到对象Foo,即我们用class定义的类Foo
print(Foo)
print(type(Foo))
print(isinstance(Foo,type))
打印:
True
我们看到,type 接收三个参数:
第 1 个参数是字符串 ‘Foo’,表示类名
第 2 个参数是元组 (object, ),表示所有的父类
第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
**补充:若Foo类有继承,即class Foo(Bar):… 则等同于type(‘Foo’,(Bar,),{})
程序发生异常的信号,如果没有处理程序就会抛出异常,运行随之结束
异常错误法分为两种: