类:
属性:
实例变量
类变量
私有属性__var
方法:
构造方法
析构函数
私有方法
对象:一个类实例化之后的得到的对象
封装:把一些功能的实现细节不对外暴露
继承:
代码的重用
单继承
多继承
2.x、经典类,深度优先 新式类,广度优先
3.x、都是广度优先
继承的时候:
class Foo(SchoolMember):
def __init__(self,name,age,sex,selary,coures): #括号里写全参数,先写父类的,再写自己的
super(Foo,self).__init__(name,age,sex) #前面写子类的名字,后面写父类的参数
#SchoolMember.__init__(self,name,age,sex) #经典类的写法,上面是新式类的写法
self.selary = selary
self.course = coures
多态:接口的重用
静态方法:只是名义上归类管理,实际上在静态方法里访问不了类或实例中的任何属性
类方法:只能访问类变量,不能访问实例变量
属性方法:把一个方法变成一个静态属性
反射:
hasattr(obj,name_str),判断一个对象里是否有对应的字符串的方法
getattr(object, name, default=None),根据字符串去获取obj对象里的对应的方法的内存地址
setattr(x, y, v)
异常处理
动态导入模块
断言
面向过程 VS 面向对象
编程范式:
编程是程序员用特定语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程,一个程序是程序员为了得到一个任务结果而
编写的一组指令的集合,正所谓条条大路通罗马,实现一个任务的方式有很多种不同的方式,对这些不同的编程方式的特点进行归纳总结
得出来的编程方式类别,即为编程范式。不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路,大多数语言只支持
一种编程范式,当然也有些语言可以同时支持多种编程范式。
两种最重要的编程范式分别是面向过程编程和面向对象编程。
面向过程编程(Procedural Programming):
Procedural programming uses a list of instructions to tell the computer what to do step-by-step.
面向过程编程依赖-你猜到了-procedures,一个procedure包含一组要被进行计算的步骤,面向过程又被称为top-down languages,
就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 。基本设计思路就是程序一开始是要着手解决一个大的问题,
然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。
1、面向对象介绍:
Object-Oriented Programming
OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和
扩展变得更简单,并且可以大大提高程序开发效率,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发
变得更从容。
面向对象的几个核心特性如下:
1.1、Class 类:
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法
1.2、Object 对象 :
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,
就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同
1.3、Encapsulation 封装:
不对外暴露细节,只提供一个接口
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法
1.4、Inheritance 继承:
一个类可以派生出子类, 在这个父类里定义的属性、方法自动被子类继承
1.5、Polymorphism 多态:
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。
对不同类的对象发出相同的消息将会有不同的行为。比如,你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”, 因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。
多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定.
1.6、例子:
class Role(object):
n = 123 #类变量
def __init__(self,name,role,weapon,life_value=100,money=15000):
#构造函数
#在实例化时,做一些类的初始化的工作
self.name = name #实例变量(静态属性),作用域是实例本身
self.role = role
self.weapon = weapon
self.life_value = life_value
self.money = money
def shot(self): #类的方法,类的功能(动态属性)
print("shooting...")
def got_shot(self):
print("ah...,I got shot...")
def buy_gun(self,gun_name):
print("just bought %s" %gun_name)
print(Role.n)
r1 = Role('Alex','police','AK47’) #实例化(把一个类变成具体对象的过程)
print(r1.n,r1.name)
r1.name = "李尚" #可以修改实例中的值
print(r1.n,r1.name)
r2 = Role('Jack','terrorist','B22’) #生成一个角色r2,,,r1和r2叫Role这个类的实例
print(r2.n,r2.name)
r1.buy_gun("M16")
r1.got_shot #杀死r1 === 相当于Role.got_shot(r1)
r1.bullet_prove = True #也可以在实例化之后再添加属性
print(r1.n,r1.name,r1.bullet_prove)
del r1.weapon #删除一条属性
r1.n = "改类变量" #直接在r1的内存里生成了新的 n = "改类变量"
print("r1:",r1.name,r1.n)
print("r2:",r2.name,r2.n)
--->
123
123 Alex
123 李尚
123 Jack
Alex just bought M16
ah...,I got shot...
r1: 李尚 改类变量 #只是在r1的内存里生成了一个新的 n = "改类变量"
r2: Jack 123 #r2里没有n,就去调用类里的 n = 123
2、类变量的用途?大家共用的属性,节省开销
3、构造函数:
def __init__(self,n1,n2,n3):
self.n1 = n1
self.n2 = n2
self.n3 = n3
4、析构函数:在实例释放、销毁的时候执行的,通常用于做一些收尾工作,如关闭一些数据库连接、关闭一些打开的临时文件
#用法1:__del__()析构函数会在程序执行完时自执行
class Role:
def __init__(self, name, role, weapon, life_value=100, money=15000):
self.name = name
self.role = role
self.weapon = weapon
self.life_value = life_value
self.money = money
def __del__(self):
print("%s 彻底死了..."% self.name)
def shot(self):
print("shooting...")
def got_shot(self):
print("ah...,I got shot...")
def buy_gun(self, gun_name):
print("%s just bought %s" % (self.name,gun_name))
r1 = Role('Alex', 'police', 'AK47')
r1.buy_gun("M4A1")
r1.got_shot()
r2 = Role('Jack', 'terrorist', 'B22')
r2.got_shot()
--->
Alex just bought M4A1
ah...,I got shot...
ah...,I got shot...
Alex 彻底死了... #程序执行完毕时自动执行__del()__
Jack 彻底死了... #同上
也可以在程序执行过程中手动执行__del()__
#用法2:在程序执行过程中手动执行析构函数
class Role:
def __init__(self, name, role, weapon, life_value=100, money=15000):
self.name = name
self.role = role
self.weapon = weapon
self.life_value = life_value
self.money = money
def __del__(self):
print("%s 彻底死了..."% self.name)
def shot(self):
print("shooting...")
def got_shot(self):
print("ah...,I got shot...")
def buy_gun(self, gun_name):
print("%s just bought %s" % (self.name,gun_name))
r1 = Role('Alex', 'police', 'AK47')
r1.buy_gun("M4A1")
r1.got_shot()
del r1 #手动执行r1的死亡
r2 = Role('Jack', 'terrorist', 'B22')
r2.got_shot()
--->
Alex just bought M4A1
ah...,I got shot...
Alex 彻底死了... #这时Alex的死亡就会出现在r2的实例之前,而不是等程序执行完毕再执行
ah...,I got shot...
Jack 彻底死了...
5、私有方法,私有属性(变量)
##私有属性和私有方法
class Role:
def __init__(self, name, role, weapon, life_value=100, money=15000):
self.name = name
self.role = role
self.weapon = weapon
self.__life_value = life_value #前面加__,变为私有属性,对外不可见,在内部可以添加一个方法
self.money = money
def __shot(self): #前年加__,变为私有方法,外面不能直接调用这个方法
print("shooting...")
def got_shot(self):
print("ah...,I got shot...")
def buy_gun(self, gun_name):
print("%s just bought %s" % (self.name,gun_name))
def show_status(self):
print("name:%s weapon:%s life_val:%s" %(self.name,self.weapon,self.__life_value))
r1 = Role('Alex', 'police', 'AK47')
print(r1.show_status)
--->
name:Alex weapon:AK47 life_val:100
6、类的继承:
#经典类
class People():
def __init__(self,name,age,):
self.name = name
self.age = age
def eat(self):
print("%s is eating..." % self.name)
def talk(self):
print("%s is talking..." % self.name)
def sleep(self):
print("%s is sleepping..." % self.name)
class Man(People):
def __init__(self,name,age,money): #想让Man调用继承的父类People()时有单独的属性,再重新def一次
People.__init__(self,name,age) #把父类的方法都调用过来
################################################################################
#super(Man,self).__init__(name.age) #方法2:与上一行效果完全一样() #新式类的写法
################################################################################
self.money = money #这个是自己新加的
print("%s 一出生就有%s money"%(self.name,self.money))
def piao(self):
print("%s is piaoing ..... 20s....done" % self.name)
def sleep(self): #父类本身有sleep方法,在此处重构父类的方法
People.sleep(self) #调用的父类的方法
print("man is sleepping") #自己添加的新功能
class Woman(People):
def get_birth(self):
print("%s is born a baby" % self.name)
m1 = Man('lishang',23,'10000000000') #调用Man()就得需要3个参数
m1.eat() #eat是从父亲People()继承的方法
m1.piao() #piao是Man()自己的方法
m1.sleep()
w1=Woman("Houruijuan",26) #调用Woman()只需从父类继承的2个参数
w1.get_birth()
--->
lishang 一出生就有10000000000 money
lishang is eating...
lishang is piaoing ..... 20s....done
lishang is sleepping...
man is sleepping
Houruijuan is born a baby
6.1、新式类与经典类区别主要在多继承上:
#新式类
class People(object):
def __init__(self,name,age,):
self.name = name
self.age = age
def eat(self):
print("%s is eating..." % self.name)
def talk(self):
print("%s is talking..." % self.name)
def sleep(self):
print("%s is sleepping..." % self.name)
class Relation(object):
#def __init__(self):
def make_friends(self,obj):
print("%s is making friends with %s" %(self.name,obj.name))
class Man(People,Relation):
def __init__(self,name,age,money):
super(Man,self).__init__(name,age)
self.money = money
print("%s 一出生就有%s money"%(self.name,self.money))
def piao(self):
print("%s is piaoing ..... 20s....done" % self.name)
def sleep(self):
People.sleep(self)
print("man is sleepping")
class Woman(People,Relation):
def get_birth(self):
print("%s is born a baby" % self.name)
m1=Man('lishang',23,'10000000000')
w1=Woman("ZhaoXiaomeng",26)
m1.make_friends(w1)
--->
lishang 一出生就有10000000000 money
lishang is making friends with ZhaoXiaomeng
6.2、多继承的广度优先原则
先找与他相连接的最近的类,找完该层级后,再去找他们的父类
class A:
def __init__(self):
print("A")
class B(A):
pass
# def __init__(self):
# print("B")
class C(A):
def __init__(self):
print("C")
class D(B,C):
pass
# def __init__(self):
# print("D")
D()
--->
C #执行D的时候,会先找B,再找同级的C,最后才找上层的A(广度优先原则)
6.3、深度优先原则
深度优先查询方法:先找B,再找B的父类,然后才找与B同层的C类
6.4、python2 和 python3上经典类与新式类继承方式的区别
在python2上,经典类是按深度优先来继承的,新式类先按广度优先来继承的
在python3上,经典类和新式类都是统一按广度优先来继承的
python2上,将第一行 class A: 改为 class A(object): 就将经典类变成了新式类,再次查询就按照广度优先的方法查找了
7、类—多态,“一个接口,多种实现”
多态性(polymorphish)是允许你将父对象设置成和一个更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的
子对象的特性以不同的方式运作。简单的说,一句话:允许将子类类型的指针赋值给父类类型的指针。
多态的作用是什么呢?我们知道,封装可以隐藏显示细节,使得代码模块化;继承可以扩展已存在的代码模块(类)。他们的目的都是
为了--代码重用。那么多态则是为了实现另一个目的--接口重用!多态的作用就是为了类在继承和派生的时候,保证使用"家谱"中任一
类的实例的某一属性时的正确调用。
- python不直接支持多态,但可以间接实现
class Animal(object):
def __init__(self,name):
self.name = name
def talk(self):
pass
@staticmethod #装饰器,一个静态方法,跟类没关系
def animal_talk(obj):
obj.talk()
class Dog(Animal):
def talk(self):
print('%s: 汪!汪!汪!'%self.name)
class Cat(Animal):
def talk(self):
print('%s: Meow~ Meow~' % self.name)
a = Dog('赵晓萌')
b = Cat('孙凯欣')
Animal.animal_talk(a) #同一个接口,不同的表现形式
Animal.animal_talk(b)
--->
赵晓萌: 汪!汪!汪!
孙凯欣: Meow~ Meow~
8、静态方法
class Dog(object):
def __init__(self,name):
self.name = name
@staticmethod #加上这个装饰器,这个功能和类已经没有关系,d.eat()不能直接调用
def eat(self):
print("%s is eatting %s" % (self.name,'包子'))
d = Dog('赵晓萌')
d.eat(d) #因为和上面的eat加上了这个装饰器,想再调用得把d传进来
--->
赵晓萌 is eatting 包子
9、类方法
class Dog(object):
name = 'lishang'
def __init__(self,name):
self.name = name
@classmethod
def eat(self):
print("%s is eatting %s" % (self.name,'包子'))
d = Dog('赵晓萌')
d.eat()
--->
lishang is eatting 包子 #明明传得是'赵晓萌',得到的却是lishang
10、属性方法
class Dog(object):
name = 'lishang'
def __init__(self,name):
self.name = name
@property #将方法转为了一个属性
def eat(self):
print("%s is eatting %s" % (self.name,'包子'))
@eat.setter #修改这个属性
def eat(self,food):
print("set to food:",food)
self.__food = food
@eat.deleter #删除这个属性
def eat(self):
del self.__food
print("删完了")
d = Dog('赵晓萌')
d.eat
d.eat = '包子'
d.eat
del d.eat
--->
赵晓萌 is eatting 包子
set to food: 包子
赵晓萌 is eatting 包子
删完了
11、一些特殊方法
- doc 表示类的描述信息
class Dog(object):
'''这个类是描述狗这个对象的'''
def __init__(self,name):
self.name = name
self.__food = None
@property
def eat(self):
print("%s is eatting %s" % (self.name,self.__food))
@eat.setter
def eat(self,food):
print("set to food:",food)
self.__food = food
@eat.deleter
def eat(self):
del self.__food
print("删完了")
print('1:',Dog.__doc__) #打印这个类的描述信息
--->
1:这个类是描述狗这个对象的
2、module 和 class
##/lib/aa
class C(object):
def __init__(self):
self.name = 'lishang'
##index.py
from lib.aa import C
obj = C()
print (obj.__module__) # 输出 lib.aa,即:输出C是从哪个模块导出来的
print (obj.__class__) # 输出 lib.aa.C,即:输出类
--->
lib.aa
<class 'lib.aa.C'>
- call 对象后面加括号,触发执行
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print '__call__'
obj = Foo() # 执行 __init__
obj() # 执行 __call__
- dict 查看类或对象中的所有成员
class Dog(object):
#name = 'lishang'
'''这个类是描述狗这个对象的'''
def __init__(self,name):
self.name = name
self.__food = None
def eat(self):
print("%s is eatting %s" % (self.name,self.__food))
print('6:',Dog.__dict__) #打印类里的所有属性,不包括实例属性
d = Dog('赵晓萌')
print('6:',d.__dict__) #打印所有实例属性,不包括类属性
--->
6: {'__module__': '__main__', '__doc__': '这个类是描述狗这个对象的', '__init__': <function Dog.__init__ at 0x00000000027C43A8>, 'eat': <property object at 0x00000000027068B8>, '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>}
6: {'name': '赵晓萌', '_Dog__food': None}
7.str 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
class Foo(object):
def __init__(self,name):
self.name = name
def __str__(self):
return '<obj:%s>' %self.name
obj = Foo('lishang')
print (obj)
--->
<obj:lishang> #返回了__str__(self)方法的返回值
8.getitem、setitem、delitem
用于索引操作,如字典。以上分别表示获取、设置、删除数据
class Foo(object):
def __getitem__(self, key):
print('__getitem__',key)
def __setitem__(self, key, value):
print('__setitem__',key,value)
def __delitem__(self, key):
print('__delitem__',key)
obj = Foo()
result = obj['k1'] # 自动触发执行 __getitem__
obj['k2'] = 'alex' # 自动触发执行 __setitem__
del obj['k1']
- new \ metaclass
###a). 普通方式
class Foo(object):
def func(self):
print ('hello alex')
###b). 特殊方式
def func(self):
print 'hello wupeiqi'
Foo = type('Foo',(object,), {'func': func})
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类的成员
###c). 手动将函数链接成类
def func(self):
print( 'hello %s' % self.name)
def __init__(self,name,age):
self.name = name
self.age = age
Foo = type('Foo', (object,), {'talk': func,
'__init__':__init__})
f = Foo('lishang','22')
f.talk()
print(type(Foo))
--->
hello lishang
<class 'type'>
12、学校的例子,类的继承、组合等
class School(object):
def __init__(self,name,addr):
self.name = name
self.addr = addr
self.students = []
self.teachers = []
self.staffs = []
def enroll(self,stu_obj):
print("为%s学生办理注册手续" % stu_obj.name)
self.students.append(stu_obj)
def hire(self,staff_obj):
print("雇佣新员工%s" % staff_obj.name)
self.staffs.append(staff_obj)
class SchoolMember(object):
def __init__(self,name,age,sex,):
self.name = name
self.age = age
self.sex = sex
def tell(self):
pass
class Teacher(SchoolMember):
def __init__(self,name,age,sex,selary,coures):
super(Teacher,self).__init__(name,age,sex)
self.selary = selary
self.course = coures
def tell(self):
print('''
------ info of Teacher:%s
Name:%s
Age:%s
Sex:%s
Selary:%s
Coures:%s
'''%(self.name,self.name,self.age,self.sex,self.selary,self.course))
def teach(self):
print("%s is teaching course [%s]" % (self.name,self.course))
class Student(SchoolMember):
def __init__(self,name,age,sex,stu_id,grade):
super(Student,self).__init__(name,age,sex)
self.stu_id = stu_id
self.grade = grade
def tell(self):
print('''
------ info of Student:%s
Name:%s
Age:%s
Sex:%s
Stu_id:%s
Grade:%s
'''%(self.name,self.name,self.age,self.sex,self.stu_id,self.grade))
def pay_tuition(self,account):
print("%s has paid tuition for $%s" %(self.name,account) )
school = School('老男孩IT','沙河')
t1 = Teacher('oldboy',56,'mf',2000000,'linux')
t2 = Teacher('alex',22,'boy',3000,'python')
s1 = Student('李尚',23,'boy',20110001,'gao1')
s2 = Student('赵晓萌',22,'girl',20110002,'gao2')
s1.tell()
t1.tell()
school.enroll(s1)
school.enroll(s2)
school.hire(t1)
school.staffs[0].teach()
for stu in school.students:
stu.pay_tuition(5000)
--->###运行结果:
------ info of Student:李尚
Name:李尚
Age:23
Sex:boy
Stu_id:20110001
Grade:gao1
------ info of Teacher:oldboy
Name:oldboy
Age:56
Sex:mf
Selary:2000000
Coures:linux
为李尚学生办理注册手续
为赵晓萌学生办理注册手续
雇佣新员工oldboy
oldboy is teaching course [linux]
李尚 has paid tuition for $5000
赵晓萌 has paid tuition for $5000
13、反射
通过字符串映射或修改程序运行时的状态、属性、方法, 有以下4个方法
getattr(object, name, default=None) #根据字符串去获取obl对象里的对应的方法的内存地址
hasattr(object,name) #判断一个对象obj里是否有对应的name_str字符串的方法
setattr(x, y, v) #相当于` x.y = z `,
delattr(x, y) #删除一段属性
def bulk(self):
print("%s is yelling..." %self.name)
class Dog(object):
def __init__(self,name):
self.name = name
def eat(self,food):
print("%s is eatting" %self.name,food)
d = Dog("Zhao Xiao Meng")
choice = input(">>>:").strip()
print(hasattr(d,choice))
if hasattr(d,choice):
func = getattr(d,choice) #d.eat('椰子')
func("椰子")
delattr(d,choice)
else:
setattr(d,choice,bulk)
d.talk(d)
--->
>>>:eat
Zhao Xiao Meng is eatting 椰子
>>>:talk
22
14、异常处理
list = [1,2,3]
data = {}
try:
list[3]
data['name']
except KeyError as e:
print("没有这个key:",e)
except IndexError as e:
print("列表操作错误:",e)
except Exception as e: #这个是总的方法,可以卸写在最后
print("未知出错了:",e)
else: #前面的错误提示没有捕捉到,就为正常
print("一切正常")
finally: #不管是否有错误,最后都执行这个
print("不管有没有错误都执行")
--->
列表操作错误: list index out of range
不管有没有错误都执行
- 常见的异常错误类型
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
14.1、自定义异常
class LiShangException(Exception):
def __init__(self, msg):
self.message = msg
# def __str__(self): #这一段可加可不加,基类(Exception)已定义好了
# return self.message
try:
raise LiShangException('大桥未久的异常')
except LiShangException as e:
print(e)
--->
大桥未久的异常
15、动态导入模块
###第一种情况,python解释器内部自己的用法
文件夹lib下有aa.py
###cat aa.py
class C(object):
def __init__(self):
self.name = 'lishang'
与lib同级目录下有'动态导入模块.py'
lib = __import__('lib.aa')
obj = lib.aa.C()
print(obj.name)
--->
lishang
----------------------------------------------------------------
###第二种情况,官方建议 import importlib;aa = importlib.import_module('lib.aa')
import importlib
aa = importlib.import_module('lib.aa')
print(aa.C().name)
--->
lishang
16、断言
用于安检当前完全正确,确认没毛病,才进行后面的步骤,否则就会报错
a = 'lishang'
print(type(a))
assert type(a) is str
print("你说得对")