1、面向对象(oop
)
面向过程:面向处理,更多的是注重计算每一个步骤
面向对象:认为万事万物皆对象,程序是由多个对象协作共同完成的,能更好的直接代码复用和设计复用
问题->面向对象分析(OOA)->发现对象->类->用类实例化对象->对象协作完成功能
2、类和对象
-
类:具有相同特征和行为的对象的集合
-
对象:具有某些功能和特征的具体事物的抽象,是类的实例
-
类定义必须使用关键字class,类名一般用大驼峰命名规则:每个单词首字母大写,其他小写
-
class MyDog(object):
#python3
默认继承自object,可以class Mydog
: 函数体
-
3、类
class MyDOg(object):
num = 100
#类属性 可以通过类名访问,也可以被对象访问.如果成员属性名和类属性名冲突,优先访问成员属性,成员属性屏蔽类属性.
def __init__(self,name,age,sex) #构造函数,一般用于完成对象数据成员设置初值或进行其他必要的 self.name = name #初始化工作,不会创建对象,如未提供,python会提供一个默认的构造函数
#成员属性,描述对象的静态特征,其实就是一个变量,作用域属于类。python中成员属性可以在构造函数中添加。成员属性属于对象,每个对象的成员属性的值都不同。
self.__age =age # 私有变量 外界不能直接对象.__age调用了,只能通过调用对象的公用方法来访问。
self.__sex =sex #私有变量
def bark(self):
print('汪汪') #成员公有方法,作用域在类内,成员方法的第一个参数必须是self,代表调用当前对象,只有对象可以调用
def eat(self):
print('吃骨头') #成员公有方法
#定义一个公开方法,间接访问私有变量 外界通过对象.get_age()
def get_age(self):
return self.__age
#定义一个公开方法,间接设置私有变量 外界通过对象.set_age()
def set_age(self,age):
self.__age =age
#对于私有属性的访问,使用公开方法间接访问的方法太麻烦,python提供了一种便捷语法,属性装饰器,通过属性装饰器,可以很方便的对私有属性访问,属性装饰器可以把方法属性化
@property #外界使用 对象.sex
def sex(self):
return self.__sex
@sex.setter #外界使用 对象.sex =sex
def sex(self,sex)
self.sex = sex
#定义一个成员私有方法(双下划线)
def __sleep(self):
print('这是我的地盘')
#外界通过,对象.__sleep()会报错,该方法为私有方法,只能在当前类中被成员公有方法调用。外界通过公有方法获取
#定义一个类方法
@classmethod
def c1(cls):
rerurn('我是类方法')
#定义一个静态方法
@staticmethod
def show():
return time.time()
def __del__(self): #析构函数,用来释放对象占用的资源,如果未提供,python将会提供一个默认的析构函数进行必要的清理工作。
def __str__(self):
return self.name
def __repr__(self):
return self.__str__()
#将对象转化为字符串,凡是涉及对象向字符串转化的都会调用(`print,str`),返回值是字符串.
#__repr__作用同__str__,不过是给解释器看的
dog = MyDog('泰迪') #对象的创建,对象的实例化 ,定义了一个 类 类型的变量
print(dog.__dict__) #__dict__属性可以查看实例属性
print(dog.__class__) #查看对象的类名
#属性获取
print(dog.name) #成员属性的调用:对象。成员属性
print(dog.get_age()) #获取私有属性age的值go
dog.set_age(10) #设置私有属性的值
print(dog.sex) #用了@property方法后获取属性值
dog.sex = sex #用了@sex.setter方法后修改属性值
dog.bark() #成员方法的调用
dog.eat().bark() #成员方法的连贯调用
- 属性私有化:如果想让类的内部属性不被外界直接访问,可以在这个属性的前面加两个下划线 ,在Python中,如果一个属性的前面出现两个下划线,就表示这个属性只能在当前类中的方法中访问,不能通过对象直接访问,这个变量就被称为私有变量
单下划线:_age #受保护的,可以访问的,约定俗称,不要使用它
双下划线:__age #私有的
两边都有双下划线: __age__ #系统内置变量
-
属性装饰器:对于私有属性的访问,使用公开方法间接访问的方法太麻烦,python提供了一种便捷语法,属性装饰器,通过属性装饰器,可以很方便的对私有属性进访问,属性装饰器可以把方法属性化。
描述器:描述器在监视特定属性的时候很有用,其只在新式类中起作用,种类至少实现了3个特殊的方法__get__, __set__, __delete__中的一个。 如果一个对象同时定义了 get() 和 set(),它叫做资料描述器(data descriptor)。仅定义了 get() 的描述器叫非资料描述器 描述器在属性访问时被自动调用。 调用优先级: 资料描述器 -> 实例字典 -> 非资料描述器
-
成员私有方法(属于对象)
- 如果以对一个方法的名字前面加双下划线__,声明该方法为私有方法,只能在当前类中被成员公有方法调用,在外界不能通过对象调用,这就是私有方法。
-
类方法
- 使用了装饰器
@classmethod
,第一个参数是当前类对象,该参数一般约定为cls
,通过它来传递类的属性和方法(不能传实例的属性和方法) - 调用:实例和类都可以调用
- 使用了装饰器
-
静态方法
- 使用装饰器
@staticmethod
。参数没有self和cls
,函数体也没有类和对象的属性和方法,就是一个独立的、单纯的函数放在类里了,仅仅托管于某个类的命名空间。 - 调用:实例对象和类对象都可以调用
- 其实,我们可以在类外面写一个同样的函数来做这些事,但是这样做就打乱了逻辑关系,也会导致以后代码维护困难
- 使用装饰器
-
实例成员的动态绑定(了解)
- 实例的属性和方法都可以动态绑定,也就是在程序运行期间可以给程序增加功能。
- 给实例动态添加的属性只属于这个实例,其他对象没有该属性
- 使用
__slot__
限制属性的动态绑定 - 给类绑定成员方法,所有对象都可以使用
4、类的三大特性
-
封装
- 隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读取和修改的访问级别。
- 类本身就是一种封装,通过类将数据(属性)和行为(方法)相结合,提供外部接口,以特定的权限来使用类的成员。成员私有化是实现封装的手段。
-
继承
-
所谓继承就是使现有的类无需编码就可以拥有基类的方法和属性
-
被继承的类称为父类,基类,超类,继承的类称之为子类,派生类。
-
继承的优点:可以简化代码,减少冗余度
提高了代码的可维护性,扩展性
提高了代码的安全性
-
单继承:就是只继承一个父类,子类会继承父类所有的属性和方法
-
继承自父类的私有成员在子类中无法直接使用,要用原父类的方法调用。因为私有方法,它现在已经不在父类中了,在子类
-
子类方法和父类方法重名,通过子类对象调用的是子类方法(重写覆盖)
构造函数的继承 class Mydog(Animal) def __init__(self,name,age,gender) 父类名.__init__(self,name,age) self.gender = gender #或者 super(Mydog,self).__init__(name,age) #实参列表不要带self self.gender =gender #或者 super().__init__(name,age) self.gender =gender
-
-
多继承:继承自多个父类,如果两个父类中有同名方法,调用的前面父类的方法,前面父类的方法会遮蔽后面的
class MyDog(Animal,Pet)
:
-
-
多态
- 多态指的是根据对象或类的不同而表现出不同的行为,
- 不同的子类对象调用相同的父类方法,产生了不同的执行结果
- 多态好处:
- 提高了方法调用的灵活性
-
鸭子类型: 鸭子类型就是不关系对象的类型,只关心对象的行为
- 如果一只鸟 走起来像鸭子,叫起来也像鸭子,那么这只鸟就可以被称为鸭子
- 鸭子类型是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。
- 比如如果一个对象实现了
__getitem__
方法,那python的解释器就会把它当做一个collection
,就可以在这个对象上使用切片,获取子项等方法;如果一个对象实现了__iter__
和next
方法,python就会认为它是一个iterator
,就可以在这个对象上通过循环来获取各个子项。
5、魔术方法
-
魔术方法就是一个类的特殊方法,和普通方法唯一的不同时,普通方法需要调用!而魔术方法由系统自动调用。
-
常用魔术方法
1.
__init__
初始化魔术方法 触发时机:初始化对象时触发(不是实例化触发,但是和实例化在一个操作中) p1 = Person() p1对象 实例化对象p1 p1 实例 参数:至少有一个self,接收对象 返回值:无 作用:初始化对象的成员
2.
__new__
实例化魔术方法 类方法 触发时机: 在实例化对象时触发 参数:至少一个cls 接收当前类 返回值:必须返回一个对象实例 作用:实例化对象 注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。 没事别碰这个魔术方法,先触发__new__才会触发__init__ class Dog: def __new__(cls, *args, **kwargs): print('new方法在执行') // return super().__new__(cls,*args, **kwargs) #必须通过父类的__new__创建对象 return object.__new__(cls,*args, **kwargs) def __init__(self,name,age): self.name = name self.__age = age print('init方法在执行')
3.
__del__
析构魔术方法 触发时机:当对象没有用(没有任何变量引用)的时候被触发 参数:一个self 返回值:无 作用:在销毁对象时回收资源 注意:del不一定会触发当前方法,只有当前对象没有任何变量引用时才会触发
4.
__call__
调用对象的魔术方法 触发时机:将对象当作函数调用时触发,方式: 对象() 参数:至少一个self接收对象,其余根据调用时参数决定 返回值:根据情况而定 作用:可以将复杂的步骤进行合并操作,减少调用的步骤,方便使用 注意:无
5.
__len__
触发时机:使用len(对象) 的时候触发 参数:一个参数self 返回值:必须是一个整型 作用:可以设置为检测对象成员个数,但是也可以进行其他任意操作 注意:返回值必须必须是整数,否则语法报错,另外该要求是格式要求。
6.
__str__
触发时机:使用print(对象)或者str(对象)的时候触发 参数:一个self接收对象 返回值:必须是字符串类型 作用:print(对象时)进行操作,得到字符串,通常用于快捷操作 注意:无
7.
__repr__
触发时机:在使用repr(对象)的时候触发 参数:一个self接收对象 返回值:必须是字符串 作用:将对象转使用repr化为字符串时使用,也可以用于快捷操作
8.
__bool__
触发时机: 使用bool(对象)的时候触发 参数:一个self接收对象 返回值:必须是布尔值 作用:根据实际情况决定,可以作为快捷方式使用 注意:仅适合于返回布尔值的操作
9.
__format__
触发时机:使用字符串.format(对象)时候触发 参数:一个self接收对象,一个参数接收format的{}中的格式,例如:>5 返回值:必须是字符串 作用:设置对象可以作为format的参数,并且自定义对象格式化的规则 注意:无
10.
__eq__
比较运算符重载:__eq__,__ge__,__le__,__gt__,__ne__
6、常用内建函数
-
issubclass(sub,sup)
如果sub是sup的子类,返回True,否则返回False。sub和sup必须是类
-
isinstance(obj,class)
如果obj是class的对象或子类对象,返回
Ture
,否则返回False,属性必须是公有的才能判断。isinstance与type区别 isinstance考虑继承关系,isinstance(对象或子类,父类) True type不考虑继承关系 type(子类对象或子类) = 父类 False
-
hasattr(object,name)
判断对象是否具有指定属性(name),有则返回True,否则返回False
getattr(object,name[,default])
获取object对象的属性值
-
setattr(object,name)
设置对象的属性值,属性必须存在
-
callable(object)
判断一个对象是否可调用
-
dir(obj/class)
显示类或对象属性、方法等详细信息
-
super(obj,self)
调用父类(超类)的一个方法
7.装饰器
-
装饰器就是用于拓展原来函数功能的一种函数,在不改变源代码的情况下,动态的添加功能,经常用在插入日志、性能测试。 写代码要遵循开放封闭原则,虽然在这个原则是用的面向对象开发,但是也适用于函数式编程,简单来说,它规定已经实现的功能代码不允许被修改,但可以被扩展,即: • 封闭:已实现的功能代码块 • 开放:对扩展开发
-
#无参装饰器 def decorator(func): print('我被调用了') @wraps(func) #加不加都可以,减少装饰器带来的一些副作用,如函数名等属性变化 def wrapper(*args,**kwargs): print('任务开始') r=func(*args,**kwargs) print('任务完成') return wrapper @decorator def f1(): print(123) f1() f1() #同一个函数如f1执行两次,装饰器中print('我被调用了')只会执行一次,在函数调用第一次执行。 @decorator def f2(a,b): print(a,b) f2(1,2) f2(1,2)
-
#有参装饰器 def decorator(number): print(number) def decorator1(func): def wrapper(*args, **kwargs): print('--------->开始') r=func(*args, **kwargs) print('--------->结束') return r return wrapper return decorator1 #比无参装饰器多套了一层 @decorator(10) def show(): rerurn '调用show函数' a=show() print(a) # 如果装饰的函数有返回值,装饰器的内层函数也要有返回值,从而保证装饰后的函数与原函数保持一致性
-
#多个装饰器 def decorator1(func): print('我是装饰器1') def wrapper(*args, **kwargs): func(*args, **kwargs) # func = house print('铺地板') return wrapper def decorator2(func): # func = 第一层wrapper print('我是装饰器2') def wrapper(*args, **kwargs): func(*args, **kwargs) print('买衣柜') return wrapper @decorator2 @decorator1 def house(): print('------》毛坯房') house() # 多层装饰器:谁离原函数最近先执行哪个装饰器,将第一层装饰器的返回结果传给第二层装饰器。 最后:原函数得到的地址是第二层函数的返回值wrapper # 执行结果 我是装饰器1 我是装饰器2 ------》毛坯房 铺地板 买衣柜
##### 8.设计模式
- 单例设计模式的实现
- 基于`__new__`方法实现
```python
class Singleton:
def __new__(cls, *args, **kwargs):
if not hasattr(cls,"_instance"):
cls.instance = object.__new__(cls)
return cls._instance
-
基于装饰器
def singleton(cls): _instance = {} #创建一个字典,一会字典中键就是类,值就是对象 def _singleton(*args,**kwargs): if cls not in _instance: _instance[cls] = cls(*args,**kwargs) #类创建对象,赋值给字典_instance,字典键cls唯一,所以一个类只有一个键 return _instance[cls] return _singleton @singleton class A: def __init__(self,name): self.name = name a1 = A(2) a2 =A(3)
-
基于python模块
python模块就是天然的单例模式,因为模式在第一次导入时,会生成.pyc文件。当第二次导入时,就会直接加载.pyc文件,而不会再次执行模块代码,因此我们只需把相关的函数和数据定义在一个天然模块中,就可以获得一个单例对象了。
新建一个a.py文件 class Singleton: pass singleton =Singleton()
#使用 from a.py import singleton
-
基于
__metaclass__
它是在类创建过程中 -
设计模式共23种,主要分三个类型 :创建型、结构型和行为型
-
创建型
Singleton 单例模式
Abstract Factory 抽象工厂
Factory Method 工厂方法
Prototype 原型模式
-
行为型
iterator 迭代器模式
Observer 观察者模式
Visitor 访问者模式
Mediator 中介者模式
-
结构型
composite 组合模式
decrator
装饰模式Bridge 桥模式
Flyweight 享元模式
-
9 、函数重载
- python不需要函数重载,函数重载是为了解决两个问题
两个函数仅仅是参数类型 和 参数个数多少。
python参数可以是任意类型的,参数个数可以设置为缺省。