Python 面向对象
1、编程范式
2、面向对象特性
3、属性、方法
4、三大特性
5、高级方法
6、类的特殊成员方法
7、反射
8、异常处理
9、单例模式
一、编程范式
编程:程序员用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程 , 实现一个任务的方式有很多种不同的方式, 对这些不同的编程方式的特点进行归纳总结得出来的编程方式类别,即为编程范式。
面向过程编程(Procedural Programming)
面向过程编程依赖:procedures,一个procedure包含一组要被进行计算的步骤,面向过程又被称为top-down languages, 就是程序从上到下一步步执行。基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。这样做的问题也是显而易见的,就是如果你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改,所以我们一般认为, 如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护 的, 那还是用面向对象最方便了。
面向对象编程(Object-Oriented Programming )
面向对象编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
二、面向对象的特性
类:class,一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法
对象 :object,一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性
封装:Encapsulation,在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法
继承:Inheritance ,一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
多态:Polymorphism ,多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
三、属性、方法
1、属性、方法、类变量、实例变量
1 class dog: #dog:类名 2 n = 123 #类变量 3 def __init__(self,name): 4 #构造函数 5 #在实例化时做一些类的初始化工作 6 self.name = name #实例变量(静态属性),作用域就是实例本身 7 def bulk(self): #类的方法(动态属性),功能 8 print("%s:wang wang wang !"% self.name) 9 10 d1 = dog("狗") #d1 叫做dog类的实例 11 d1.bulk()
2、构造函数、析构函数、私有方法、私有属性
1 #析构函数:在实例释放、销毁的时候执行的,通常用于做一些收尾工作,如关闭一些数据库连接打开的临时文件 2 class dog: #dog:类名 3 def __init__(self,name,age = 0): 4 #构造函数 5 #在实例化时做一些类的初始化工作 6 self.name = name 7 self.__age = age #私有属性:只能在内部访问和修改(私有方法同理也是在函数前面加两个_) 8 def show_age(self): 9 print("name:%s age:%s"%(self.name,self.__age)) 10 def after_year(self): 11 self.__age += 1 12 print("一年过去了。。。") 13 def __del__(self): #析构函数 14 print(self.name) 15 r1 = dog("哈士奇") 16 r1.after_year() 17 r1.show_age()
四、特性
1、封装
封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容
将内容封装到某处:
1 class foo: #类名 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 pop1 = foo("zz",12) 6 pop2 = foo("aa",13) 7 # foo相当于一类事物的模板,当执行pop1 = foo("zz",12)时 8 # 相当于在foo中:self = poo1,pop1 = foo("zz",12) 即 pop1 = foo(por1,"zz",12) 9 # 将类中的内容封装到了对象 pop1中,而pop1有了自己的name 和 age 属性并在内存中保存了下来
从某处调用被封装的内容
class foo: #类名def __init__(self,name,age):self.name = nameself.age = age pop1 = foo("zz",12)print(pop1.name,pop1.age) #通过对象直接调用
1 class foo: #类名 2 def __init__(self,name,age): 3 self.name = name 4 self.age = age 5 def detail(self): 6 print(self.name,self.age) 7 pop1 = foo("zz",12) 8 pop1.detail() #通过self间接调用
2、继承
继承:面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容
所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法
class People:def __init__(self,name,age):self.name = nameself.age = agedef eat(self):print("%s is eating..."%self.name)def talk(self):print("%s is talking..."%self.name)def sleep(self):print("%s is sleeping..."%self.name) class man(People):def __init__(self,name,age,money):# People.__init__(self,name,age) #重构父类构造函数super(man,self).__init__(name,age)self.money = moneydef drink(self):print("%s is drinking..."%self.name)def sleep(self):People.sleep(self) #重构父类方法print("man is sleeping...") class woman(People):def makeup(self):print("%s is makeuping..."%self.name)m1 = man("zz",12,1) m1.drink() m1 .sleep() m2 = woman("aa",10)
多继承:
1、Python的类可以继承多个类,Java和C#中则只能继承一个类
1 # 经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法 2 # 从写法上区分的话,如果当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类 3 #class People: #经典类 4 class People(object): #新式类 5 def __init__(self,name,age): 6 self.name = name 7 self.age = age 8 def eat(self): 9 print("%s is eating..."%self.name) 10 def talk(self): 11 print("%s is talking..."%self.name) 12 def sleep(self): 13 print("%s is sleeping..."%self.name) 14 class relation(object): 15 def make_friend(self,obj): 16 print("%s is making friend with %s"%(self.name,obj.name)) 17 18 class man(People,relation): 19 def __init__(self,name,age,money): 20 # People.__init__(self,name,age) #重构父类构造函数 21 super(man,self).__init__(name,age) 22 self.money = money 23 def drink(self): 24 print("%s is drinking..."%self.name) 25 def sleep(self): 26 People.sleep(self) #重构父类方法 27 print("man is sleeping...") 28 class woman(People,relation): 29 def makeup(self): 30 print("%s is makeuping..."%self.name) 31 32 m1 = man("zz",12,1) 33 w1 = woman("aa",10) 34 m1.make_friend(w1)
2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先
#经典类多继承:深度优先 class D:def bar(self):print ('D.bar') class C(D):def bar(self):print ('C.bar') class B(D):def bar(self):print ('B.bar') class A(B, C):def bar(self):print ('A.bar') a = A() # 执行bar方法时 # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错 # 所以,查找顺序:A --> B --> D --> C # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 a.bar()#新式类多继承:广度优先 class D(object):def bar(self):print ('D.bar') class C(D):def bar(self):print ('C.bar') class B(D):def bar(self):print ('B.bar') class A(B, C):def bar(self):print ('A.bar') a = A() # 执行bar方法时 # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错 # 所以,查找顺序:A --> B --> C --> D # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 a.bar()# 经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错 # 新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错 # 在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了
从py3开始全部都是广度优先,没有深度优先
3、多态
Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,其Python崇尚“鸭子类型”。
多态的作用是实现接口的重用
1 class Animal(object): 2 def __init__(self, name): # Constructor of the class 3 self.name = name 4 def talk(self): # Abstract method, defined by convention only 5 raise NotImplementedError("Subclass must implement abstract method") 6 7 class Cat(Animal): 8 def talk(self): 9 print('%s: 喵喵喵!' %self.name) 10 11 class Dog(Animal): 12 def talk(self): 13 print('%s: 汪!汪!汪!' %self.name) 14 # c1 = Cat('猫') 15 # c1.talk() 16 # d1 = Dog('狗') 17 # d1.talk() 18 # 为采用多态 19 def anmiaml(obj): #一个接口,多种形态 20 obj.talk() 21 c1 = Cat('猫') 22 d1 = Dog('狗') 23 anmiaml(c1) 24 anmiaml(d1)
五、高级方法
1、静态方法
只是名义上归类管理,实际上在静态方法里访问不了类或实例中的任何属性
1 class dog(object): 2 def __init__(self,name): 3 self.name = name 4 @staticmethod #加上之后下面的方法和类就没有关系了 5 def eat(self): 6 print("%s is eating %s"%(self.name,"骨头")) 7 # 通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法 8 # 可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量 9 # 但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了 10 # 它与类唯一的关联就是需要通过类名来调用这个方法 11 d = dog("狗") 12 # d.eat("骨头") 未加@staticmethod时的调用 13 d.eat(d)
2、类方法
只能访问类变量,不能访问实例变量
1 class dog(object): 2 name = "gou" 3 def __init__(self,name): 4 self.name = name 5 @classmethod 6 def eat(self): 7 print("%s is eating %s"%(self.name,"骨头")) 8 def talk(self): 9 print("%s is talking.."%self.name) 10 d = dog("狗") 11 d.eat() #gou is eating 骨头 输出内容为类变量参数而非实例变量参数
3、属性方法
把一个方法变成一个静态属性
1 class dog(object): 2 name = "gou" 3 def __init__(self,name): 4 self.name = name 5 self.__food = "骨头" 6 @property #把一个方法变成静态属性 7 def eat(self): 8 print("%s is eating %s"%(self.name,self.__food)) 9 @eat.setter #给静态属性传参数 10 def eat(self,food): 11 print("set to food:",food) 12 self.__food = food 13 @eat.deleter 14 def eat(self): 15 del self.__food 16 print("删除私有food!") 17 def talk(self): 18 print("%s is talking.."%self.name) 19 d = dog("狗") 20 d.eat #只能按照静态属性调用方式调用不能传参数,也不能d.eat() 21 d.eat = "狗粮" #给静态属性传参数 22 d.eat #狗 is eating 狗粮 23 del d.eat 24 d.eat #报错
六、类的特殊成员方法
1 class dog(object): 2 '''描述狗这个对象''' 3 '''写类的时候一定写上这个类是作什么用的''' 4 name = "gou" 5 def __init__(self,name): 6 self.name = name 7 def eat(self): 8 print("%s is eating.."%self.name) 9 def talk(self): 10 print("%s is talking.."%self.name) 11 def __call__(self, *args, **kwargs): 12 print("run in call..",args,kwargs) 13 def __str__(self): 14 return "<obj:%s>"%self.name 15 # 1、 __doc__ 输出:类的描述信息 16 print(dog.__doc__) #输出:类的描述信息 (描述狗这个对象) 17 # 2、__module__ 表示当前操作的对象在那个模块 18 # 3、__class__ 表示当前操作的对象的类是什么 19 print(dog.__module__) #__main__ 如果这个类是import的则会返回这个类所在模块的目录 20 print(dog.__class__) #<class 'type'> 输出这个类本身 21 # 4、__init__ 构造方法,通过类创建对象时,自动触发执行 22 # 5、__del__ 析构方法,当对象在内存中被释放时,自动触发执行 23 # 6、__call__ 对象后面加括号,触发执行 24 d = dog("狗") 25 d(1,2,3,name = 321) #输出:run in call.. (1, 2, 3) {'name': 321} 26 # 7、__dict__ 查看类或对象中的所有成员 27 print(dog.__dict__) #以一个字典的形式把类中的方法属性全部打印,不包括实例属性 28 print(d.__dict__) #输出:{'name': '狗'} 打印所有实例属性,不包括类属性 29 # 8、__str__ 如果一个类中定义了__str__方法,那么在打印 对象时,默认输出该方法的返回值 30 print(d) #输出:<obj:狗> 31 # 9、__getitem__、__setitem__、__delitem__ 用于索引操作,如字典。分别表示获取、设置、删除数 32 class Foo(object): 33 def __getitem__(self, key): 34 print('__getitem__',key) 35 def __setitem__(self, key, value): 36 print('__setitem__',key,value) 37 def __delitem__(self, key): 38 print('__delitem__',key) 39 obj = Foo() 40 result = obj['k1'] # 自动触发执行 __getitem__ 41 obj['k2'] = 'zz' # 自动触发执行 __setitem__ 42 del obj['k1'] # 自动触发执行 __delitem__ 43 # 10、__new__ \ __metaclass__ 44 class Foo(object): 45 def __init__(self,name): 46 self.name = name 47 f = Foo("zz") 48 print(type(f)) #<class '__main__.Foo'> 表示,obj 对象由Foo类创建 49 print(type(Foo)) #<class 'type'> 表示,Foo类对象由 type 类创建 50 # 即:Foo是通过type类的构造方法创建 51 # 创建类就可以有两种方式 52 # 普通方式 53 class Foo(object): 54 def func(self): 55 print("in Foo!") 56 #特殊方式 57 def func(self): 58 print("in func!") 59 foo = type('foo',(object,), {'func': func}) 60 #type第一个参数:类名 61 #type第二个参数:当前类的基类 62 #type第三个参数:类的成员 63 # 类 是由 type 类实例化产生 64 # 类默认是由 type 类实例化产生,type类中如何实现的创建类: 65 # 类中有一个属性 __metaclass__,其用来表示该类由谁来实例化创建,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看类创建的过程。 66 # 类的生成调用顺序依次是 __new__ --> __init__ --> __call__
七、反射
通过字符串映射或修改程序运行时的状态、属性、方法
1 def bulk(self): 2 print("%s is bulking..."%self.name) 3 class Dog(object): 4 def __init__(self,name): 5 self.name = name 6 def eat(self): 7 print("%s is eating..."%self.name) 8 9 d = Dog("狗") 10 choice = input(">>:").strip() 11 #输入eat 12 print(hasattr(d,choice)) #True 13 #hasattr(obj,name_str) 判断一个对象obj里是否有对应的name_str字符串的方法映射 14 # print(getattr(d,choice)) #<bound method Dog.eat of <__main__.Dog object at 0x0000022F8A69C7F0>> 内存对象 15 #getattr(obj,name_str) 根据字符串去获取obj对象里的对应的方法的内存地址 16 if hasattr(d,choice): 17 func = getattr(d,choice) 18 func() 19 else: 20 setattr(d,choice,bulk) 21 d.bulk(d) 22 #setattr(obj,'y',z) 通过字符串设置新的方法 23 #delattr 24 delattr(d,choice)
八、异常处理
1、介绍
在编程过程中为了增加友好性,在程序出现报错时一般不会将错误信息显示给用户,而是显示一个提示的页面。
1 name = [] 2 dir = {} 3 try: 4 dir["aa"] 5 name[2] 6 except KeyError as e: 7 print("没有这个key:",e) 8 except IndexError as e: 9 print("列表操作错误:",e)
1 name = [] 2 dir = {} 3 try: 4 dir["aa"] 5 name[2] 6 open('zz.txt') 7 except KeyError as e: 8 print("没有这个key:",e) 9 except IndexError as e: 10 print("列表操作错误:",e) 11 # except (KeyError,IndexError) as e: #一般不这么写,这样不知道是哪个触发的 12 except Exception as e: #抓住所有错误 13 #对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行 14 print(e) 15 else: 16 print("一切正常!") #如果程序没有任何错误走这里 17 finally: 18 print("不管有没有错都执行!")
2、异常种类
#常用异常: ''' AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入模块或包;基本上是路径问题或名称错误 IndentationError 语法错误(的子类) ;代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译 TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的 ''''''其他异常: ArithmeticError AssertionError AttributeError BaseException BufferError BytesWarning DeprecationWarning EnvironmentError EOFError Exception FloatingPointError FutureWarning GeneratorExit ImportError ImportWarning IndentationError IndexError IOError KeyboardInterrupt KeyError LookupError MemoryError NameError NotImplementedError OSError OverflowError PendingDeprecationWarning ReferenceError RuntimeError RuntimeWarning StandardError StopIteration SyntaxError SyntaxWarning SystemError SystemExit TabError TypeError UnboundLocalError UnicodeDecodeError UnicodeEncodeError UnicodeError UnicodeTranslateError UnicodeWarning UserWarning ValueError Warning ZeroDivisionError '''
3、自定义异常
1 class My_Exception(Exception): 2 def __init__(self, msg): 3 self.message = msg 4 try: 5 raise My_Exception('我的异常') #主动触发异常 6 except My_Exception as e: 7 print(e) 8
九、单例模式
1 #单例模式:永远用一个实例的模式 2 3 # class Foo(object): 4 # instance = None 5 # 6 # def __init__(self): 7 # self.name = 'alex' 8 # @classmethod 9 # def get_instance(cls): 10 # if Foo.instance: 11 # return Foo.instance 12 # else: 13 # Foo.instance = Foo() 14 # return Foo.instance 15 # 16 # def process(self): 17 # return '123' 18 19 # obj1 = Foo() 20 # obj2 = Foo() 21 # print(id(obj1),id(obj2)) 22 23 #low的单例模式 24 # obj1 = Foo.get_instance() 25 # obj2 = Foo.get_instance() 26 # print(id(obj1),id(obj2)) 27 28 29 #基于new方法实现单例模式 30 class Foo(object): 31 instance = None 32 33 def __init__(self): 34 self.name = 'alex' 35 36 def __new__(cls, *args, **kwargs): 37 if Foo.instance: 38 return Foo.instance 39 else: 40 Foo.instance = object.__new__(cls, *args, **kwargs) 41 return Foo.instance 42 43 # obj1 = Foo() 44 # obj2 = Foo() 45 # print(id(obj1),id(obj2))