一、面向对象的程序设计
1、面向对象的程序设计怎么来的
a. 面向过程的程序设计
优点:极大的降低了程序的复杂度
缺点:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
b. 面向对象的程序设计
优点:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,无法预测最终结果
应用场景:迭代更新快,游戏
2、什么是面向对象
a. 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用
b. 类 是一个模板,模板中包装了多个 "函数" 供使用(可以将多个函数公用的变量封装到对象中)
c. 对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
d. 面向对象的三大特性:封装,继承和多态
3、类和对象
a. 从一组对象中提取相似的部分就是类
b. 对象是类的实例化
#self的意义
class a:
sex = 'F'
def __init__(self,name):
self.name = name
def b(self,age):
print(self.name,age)
# 类的第一个功能:实例化
a1 = a('alex') # a.__init__(a1,'alex')
# 类的第二个功能:属性引用,包含数据属性和函数属性
print(a.sex)
print(a.__init__)
print(a.b)
# 对于一个实例来说,只有一种功能:属性引用,实例本身只拥有数据属性
print(a1.name)
# 实例可以调用类的数据属性和函数属性
print(a1.sex)
print(a1.b)
print(a1.b(22))
c. 对象之间的交互
![]()
class Garen:
camp = 'Demacia'
def __init__(self, nickname, aggresivity, life_value):
self.nickname = nickname # gi.nickname = nickname
self.aggrv = aggresivity
self.life_value = life_value
def attack(self, enemy):
print('is attacking', self, enemy)
class Riven:
camp = 'Noxus'
def __init__(self, nickname, aggresivity, life_value):
self.nickname = nickname
self.aggrv = aggresivity
self.life_value = life_value
def attack(self, enemy):
print('is attacking', self, enemy)
enemy.life_value -= self.aggrv # g1.life_value -= r1.aggrv
g1 = Garen('草丛伦', 82, 100)
r1 = Riven('锐雯雯', 50, 200)
print(g1.life_value)
r1.attack(g1)
print(g1.life_value)
View Code
3、继承与派生
a. 什么是继承和派生
继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类。python中类的继承分为:单继承和多继承
b. 查看继承
python2中经典类和新式类的书写方式如下,python3中全部都是新式类,默认继承object
查看继承使用__bases__
# 经典类
class A(object):
pass
class B(A):
pass
# 新式类
class A:
pass
class B(A):
pass
print(B.__bases__)
print(A.__bases__)
(<class '__main__.A'>,)
(<class 'object'>,)
c. 继承顺序
经典类 深度优先
新式类 广度优先
mro查看继承顺序
从左到右查找父类
子类会优先父类被检查
多个父类会根据他们在列表中的顺序被检查
d. 继承与重用性
![]()
class Hero:
def __init__(self,nickname,aggressivity,life_value):
self.nickname=nickname
self.aggressivity=aggressivity
self.life_value=life_value
def move_forward(self):
print('%s move forward' %self.nickname)
def move_backward(self):
print('%s move backward' %self.nickname)
def move_left(self):
print('%s move forward' %self.nickname)
def move_right(self):
print('%s move forward' %self.nickname)
def attack(self,enemy):
enemy.life_value-=self.aggressivity
class Garen(Hero):
pass
class Riven(Hero):
pass
g1=Garen('草丛伦',100,300)
r1=Riven('锐雯雯',57,200)
print(g1.life_value)
r1.attack(g1)
print(g1.life_value)
View Code
e. 组合与重用性
一个类的数据属性调用另一个类的实例
class People:
def __init__(self, name, birth):
self.name = name
self.birth = Date(1999, 1, 25)
class Date:
def __init(self, year, mon, day):
self.year = year
f. 接口与归一化的设计
接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。
归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的一切皆文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。
接口的概念是,父类的位置只写名字,不写实现。具体实现在子类实现,只是一种设计思路。
class Text(AllFile):
def read(self):
print('text read')
def write(self):
print('text write')
class Sata(AllFile):
def read(self):
print('sata read')
def write(self):
print('sata write')
t = Text()
s = Sata()
t.read()
t.write()
g. 抽象类
在父类的方法上加上abc.abstractmethod装饰器,在继承的类里面必须重写一遍,否则会报错
有点像接口的概念,父类定义方法名,子类实现功能
抽象类本身是不能被实例化的,只用来被别人继承的
与接口的区别:方法必须被子类实现,但接口不能限定子类必须实现什么功能
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
#一切皆文件
import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta):
all_type='file'
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
'子类必须定义读功能'
pass
@abc.abstractmethod #定义抽象方法,无需实现功能
def write(self):
'子类必须定义写功能'
pass
# class Txt(All_file):
# pass
#
# t1=Txt() #报错,子类没有定义抽象方法
class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('文本数据的读取方法')
def write(self):
print('文本数据的读取方法')
class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('硬盘数据的读取方法')
def write(self):
print('硬盘数据的读取方法')
class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('进程数据的读取方法')
def write(self):
print('进程数据的读取方法')
wenbenwenjian=Txt()
yingpanwenjian=Sata()
jinchengwenjian=Process()
#这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read()
print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
h. 子类调用父类的方法
4、多态与多态性
a. 多态
多态指的是一类事务的不同形态,如序列类型包括:列表、元组、字符串
b. 多态性
多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
c. 多态性的作用
那么,多态的作用是什么呢?我们知道,封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!多态的作用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
灵活性、可扩展性
l = [1,2,3]
t = ('a','b','c')
s = (abc)
def func(obj):
print(obj.__len__())
5、封装
a. 第一个层面的封装
b. 第二个层面的封装
用__来封装,私有属性,外部无法调用
self.__money = monye ==> _Foo__money
c. __dict__ 将实例的属性变成字典保存起来
d. property
特性是用来
把类的函数做成类的属性
@name.setter
@name.deleter
e. 封装的好处
可扩展性
6、静态方法 @staticmethod
与类只是名义上的归属关系,实际上与类没有关系,
class Dog(object):
def __init__(self, name):
self.name = name
# 静态方法与类没有关系
@staticmethod
def eat(self): # 把eat变成静态方法
print("%s is eating" % self.name)
d = Dog("ll")
# 在调用时必须要把对象传进去
d.eat(d)
7、类方法 @classmethod
只能访问类变量,不能访问实例变量
class Dog(object):
name = "dddd" # 类变量
def __init__(self, name):
self.name = name # 类方法不会访问到实例变量
@classmethod
def talk(self):
print("%s is talking" % self.name)
d = Dog("ll")
d.talk()
8、属性方法 @property
把一个方法变成静态属性,按照使用属性的方式调用,可以进行赋值操作,也可以进行删除操作
class Dog(object):
def __init__(self, name):
self.name = name
@property
def speak(self):
print("%s is speaking" % self.name)
@speak.setter
def speak(self, num):
print("changing status", num)
@speak.deleter
def speak(self):
print("deleting......", self)
d = Dog("ll")
d.speak
d.speak = 4444
del d.speak
9、类的特殊成员方法
__doc__ 输出注释
class Foo:
""" 描述类信息,这是用于看片的神奇 """
def func(self):
pass
print Foo.__doc__
#输出:类的描述信息
__module__ 输出模块
__class__ 输出类
__import__ 导入模块
class C:
def __init__(self):
self.name = 'wupeiqi'
from lib.aa import C
obj = C()
print obj.__module__ # 输出 lib.aa,即:输出模块
print obj.__class__ # 输出 lib.aa.C,即:输出类
a = __import__("lib.aa")
importlib
b = importlib.import_module("lib.aa")
__del__ 析构方法,当对象在内存中被释放时,自动触发执行
__dict__ 查看类或对象中的所有成员
__str__ 如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值
class Foo:
def __str__(self):
return 'alex li'
obj = Foo()
print obj
# 输出:alex li
__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']
__call__ 对象后面加括号,触发执行
__new__、__metaclass__
type手动创建类
def init(self, name, age):
self.name = name
self.age = age
def sayhi(self):
print("hello", self.name)
Test = type("Test", (object,), {"sayhi": sayhi, "__init__": init})
# print(Test)
# print(type(Test))
# print(dir(Test))
f_obj = Test('ll', '23')
f_obj.sayhi()
__new__ # 类的实例化先执行__new__,__new__调用执行__init__
class Foo:
def __init__(self, name):
self.name = name
print("Foo __init__")
def __call__(self, *args, **kwargs):
print("call....")
def __new__(cls, *args, **kwargs):
print("Foo __new__", *args, **kwargs)
obj = object.__new__(cls)
print("obj", obj)
return obj
f = Foo("alex")
print(f)
print(f.name)
metaclass
以下代码的执行顺序
1、type.__call__
2、MyType.__new__
3、MyType.__init__
4、f = Foo('alex') #实例化,加上括号就会调用__call__
5、MyType.__call__
6、调用MyType.__new__
7、调用MyType.__init__
8、定义参数age
9、return结果给f
-------------------------------------------------------
class MyType(type): # 原类
def __init__(self, *args, **kwargs):
print("MyType __init__", self, *args, **kwargs)
def __call__(self, *args, **kwargs):
print("MyType __call__", self, *args, **kwargs)
obj = self.__new__(self)
self.__init__(obj, *args, **kwargs)
obj.age = 22
return obj
def __new__(cls, *args, **kwargs):
print("MyType __new__", *args, **kwargs)
obj = type.__new__(cls, *args, **kwargs)
return obj
class Foo(object, metaclass=MyType):
def __init__(self, name):
self.name = name
print("Foo __init__")
def __call__(self, *args, **kwargs):
print("call ....")
f = Foo("Alex")
print(f.name, f.age)
-------------------------------------------------------
type.__call__
MyType.__new__
MyType.__init__
f = Foo('alex') #实例化,加上括号就会调用__call__
MyType.__call__
调用MyType.__new__
调用MyType.__init__
return结果给f
![]()
10、反射
a. getattr
![]()
def getattr(object, name, default=None): # known special case of getattr
"""
getattr(object, name[, default]) -> value
Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
When a default argument is given, it is returned when the attribute doesn't
exist; without it, an exception is raised in that case.
"""
pass
View Code
b. hashattr
判断object中有没有一个name字符串对应的方法或属性
c. setattr
def setattr(x, y, v): # real signature unknown; restored from __doc__
"""
Sets the named attribute on the given object to the specified value.
setattr(x, 'y', v) is equivalent to ``x.y = v''
d. delattr
def delattr(x, y): # real signature unknown; restored from __doc__
"""
Deletes the named attribute from the given object.
delattr(x, 'y') is equivalent to ``del x.y''
"""
e. 反射代码
class Foo(object):
def __init__(self):
self.name = 'wupeiqi'
def func(self):
return 'func'
obj = Foo()
# #### 检查是否含有成员 ####
hasattr(obj, 'name')
hasattr(obj, 'func')
# #### 获取成员 ####
getattr(obj, 'name')
getattr(obj, 'func')
# #### 设置成员 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1)
# #### 删除成员 ####
delattr(obj, 'name')
delattr(obj, 'func')
11、异常处理
常见的异常
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError 试图访问字典里不存在的键
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
try:
except:
else:
finally:
try:
names = ['alex', 'jack']
info = {1: 32}
# print(names[3])
info[5]
except ValueError as e:
print(e)
except IndexError as e:
print(e)
except BaseException as e:
print("unknown error", e)
exit()
else:
print("什么错都没有")
finally:
print("无论有没有错,都执行")
print("keep going...")
raise 触发自定义异常
class WupeiqiException(Exception):
def __init__(self, msg):
self.message = msg
try:
raise WupeiqiException('我的异常')
except WupeiqiException as e:
print(e)
12、断言
assert
assert 1 == 1
assert 1 == 2
条件为真不报错,条件为假报错。必须要求这个条件成立程序才能继续往下走。更多的用于强调