面向对象编程(Python3版详解)
一.面向对象编程介绍:
- 如今主流的软件开发思想有两种:一个是面向过程,另一个是面向对象。面向过程出现得较早,典型代表为C语言,开发中小型项目的效率很高,但是很难适用于如今主流的大中型项目开发场景。面向对象则出现得更晚一些,典型代表为Java或C++等语言,更加适合用于大型开发场景。两种开发思想各有长短。
- 对于面向过程的思想: 需要实现一个功能的时候,看重的是开发的步骤和过程,每一个步骤都需要自己亲力亲为,需要自己编写代码(自己来做)
- 对于面向对象的思想:当需要实现一个功能的时候,看重的并不是过程和步骤,而是关心谁帮我做这件事(偷懒,找人帮我做)
- 面向对象的三大特征有:封装性、继承性、多态性。
生活举例:
- 洗衣服
-
面向过程(手洗):脱衣服、找一个盆、加水、加洗衣粉、浸泡30分钟、搓洗、拧衣服、倒掉水、再加水、漂洗、拧衣服、倒掉水、晾衣服。 -
面向对象(机洗):脱衣服、放入洗衣机、按下开关、拿出衣服晾晒。 -
买电脑
-
面向过程(自己买):需要电脑、查询参数信息、横向比较机型、了解打折信息、与店家讨价还价、下单、收快递、开机验货、确认收货。 -
面向对象(找人买):需要电脑、找秘书帮我买、收电脑。
类的基础:
#类定义 class people: #定义基本属性 name = '' age = 0 #定义私有属性,私有属性在类外部无法直接进行访问 __weight = 0 #定义构造方法 def __init__(self,n,a,w): self.name = n self.age = a self.__weight = w def speak(self): print("%s 说: 我 %d 岁。" %(self.name,self.age)) # 实例化类 p = people('runoob',10,30) p.speak()
面向对象和面向过程案例:
###################面向对象:算学生的平均成绩####################### class Student1: def __init__(self, name, chinese, math, english): self.name = name self.chinese = chinese self.math = math self.english = english def average(self): return (self.chinese + self.math + self.english) / 3 studenta = Student1("小张", 85, 78, 90) print(studenta.average()) ######################面向过程:算学生的平均成绩#################### def average(name,chinese, math, english): return (chinese + math + english) / 3 name="小张" chinese = 85 math = 78 english = 90 print(average(name,chinese, math, english))
通过遍历方式实例化对象
#!/usr/bin/env python # -*- coding: utf-8 - #######################通过列表方式实例化对象########################## class Student: def __init__(self, name, score): self.name = name self.score = score def calculate_average(self): total = sum([self.score]) count = 1 return total / count ##通过列表遍历方式,实例化对象 students = [ Student("Alice", 80), Student("Bob", 90) ] for student in students: average = student.calculate_average() print("{}的平均分是:{}".format(student.name, average))
类的嵌套:
#_________________________________类的嵌套__________________________________ class parent: def __init__(self): self.name = 'parent' def getName(self): print(self.name) #子类 class child: def __init__(self): self.name = 'child' def getName(self): print(self.name) if __name__ == '__main__': #从内部类-实例化 child = parent.child() child.getName() #这里从父类引用内部类-实例化 p = parent() c = p.child() c.getName()
私有变量与内部函数:
'''python中带有双下划线的为私有变量''' class Site: def __init__(self, name, url): self.name = name # public self.__url = url # private def who(self): print('name : ', self.name) print('url : ', self.__url) def __foo(self): # 私有方法 print('这是私有方法') def foo(self): # 公共方法 print('这是公共方法') self.__foo() x = Site('菜鸟教程', 'www.runoob.com') x.who() # 正常输出 x.foo() # 正常输出 print(x.name) print(x.__url) #报错,不能调用内部变量 x.__foo() #报错,不能私有函数
继承与重写:
定义:继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法
#!/usr/bin/env python # encoding: utf-8 #__________________________单继承_____________________________________ class Shape: def draw(self,content): print("画",content) class Form(Shape): def area(self): print("此图形的面积为...") chen=Form() chen.area() chen.draw('123') #____________________________多继承___________________________________ class People: def __init__(self): self.name = People def say(self): print("People类",self.name) class Animal: def __init__(self): self.name = Animal def say(self): print("Animal类",self.name) #People中的 name 属性和 say() 会遮蔽 Animal 类中的 class Person(People, Animal): pass zhangsan = Person() zhangsan.name = "张三" zhangsan.say() #__________________________类方法的重写_______________________________ # 父类定义 class people: def __init__(self, name, age, weight): self.name = name self.age = age self.__weight = weight def speak(self): print("%s 说: 我 %d 岁。" % (self.name, self.age)) # 单继承示例 class student(people): def __init__(self, name, age, weight, grade): # 调用父类people的实例化方法 people.__init__(self, name, age, weight)#初始化父类 #super(student, self).__init__(name,age,weight)#初始化父类 self.grade = grade # 重写父类的speak方法 def speak(self): print('speak方法被重写') print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade)) s = student('ken', 10, 30, 3) s.speak()
调用父类构造方法:
#!/usr/bin/env python # encoding: utf-8 class A: def __init__(self, name): self.name = name print("父类的__init__方法被执行了!") def show(self): print("父类的show方法被执行了!") class B(A): def __init__(self, name, age): #super(B, self).__init__(name=name)#初始化父类 A.__init__(self,name)#初始化父类 self.age = age def show(self): #调用父类show方法 super(B, self).show() obj = B("jack", 18) obj.show()
多态:
定义:对不同类型的变量进行相同的操作,它会根据对象(或类)类型的不同而表现出不同的行为 (同一个方法名,在不同的对象上调用时,会表现出不同的行为)
#!/usr/bin/env python # encoding: utf-8 class Animal: def kind(self): print("i am animal") class Dog(Animal): def kind(self): print("i am a dog") class Cat(Animal): def kind(self): print("i am a cat") class Pig(Animal): def kind(self): print("i am a pig") # 这个函数接收一个animal参数,并调用它的kind方法 def show_kind(animal): animal.kind()#animal相当于d、c、p
#实例化类(创建对象) d = Dog() c = Cat() p = Pig()
#调用show_kind函数传不同的对象过去 show_kind(d) show_kind(c) show_kind(p)
在类的函数中调用另一个函数:
#!/usr/bin/env python # encoding: utf-8 class Shape: def draw(self,content): print("画",content) def area(self): print("此图形的面积为...") self.draw('3333333333333')#在类的函数中调另一个函数 chen=Shape() chen.area()
@classmethod修饰符:
使用场景:可以直接在类方法中调用类属性/变量
#!/usr/bin/env python # encoding: utf-8 ##属于类的方法不使用self参数, 而使用参数cls,代表类本身。另外习惯上对类方法我们会加上@classmethod的修饰符做说明 ''' classmethod: 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。 ''' class Student: # number属于类属性/变量,不属于某个具体的学生实例 number = 0 # 定义学生属性,初始化方法 # name和score属于实例变量 def __init__(self, name, score): self.name = name#实例属性/变量 self.score = score #每次实例化 number都会加1 Student.number = Student.number + 1 # 定义打印学生信息的方法 def show(self): print("Name: {}. Score: {}".format(self.name, self.score)) # 类方法(不需要实例化类就可以被类本身调用) @classmethod def total(cls): # cls : 表示没用被实例化的类本身 #两种获取类属的办法 print("Total: {0}".format(Student.number)) #print("Total: {0}".format(cls.number)) # 实例化,创建对象 student1 = Student("John", 100) student2 = Student("Lucy", 99) Student.total() # 打印 Total: 2 #student1.show() #______________________________classmethod修饰符_____________________________________________ class B(object): num = 10 def func1(self): print('self') @classmethod def func2(cls): print('func2') print(cls.num)#直接在类方法里调用类的属性num cls().func1() B.func2() # 不需要实例化
@property描述符
作用是:将方法变成属性调用
#!/usr/bin/env python # encoding: utf-8 # 创建一个学生类 class Student: # 定义学生属性,初始化方法 # name和score属于实例变量, 其中score属于私有变量 def __init__(self, name, score): self.name = name self.__score = score#私有变量 # 利用property装饰器把函数伪装成属性(不用括号即可调用) @property def score(self): print("Name: {}. Score: {}".format(self.name, self.__score)) # 实例化,创建对象 student1 = Student("John", 100) #print(student1.name)#可以访问 #print(student1.__score)#私有变量,无法在外部访问 student1.score #直接执行score函数,以变量方式执行函数
# #!/usr/bin/env python # # encoding: utf-8 #______________________________@property修饰符多个函数_______________________________________ # 创建一个学生类 class Student: # 定义学生属性,初始化方法 # name和score属于实例变量, 其中score属于私有变量 def __init__(self, name, score): self.name = name self.__score = score#私有变量 # 利用property装饰器把函数伪装成属性(不用括号即可调用) @property def score(self): print("Name: {}. Score: {}".format(self.name, self.__score)) #带参数property函数 #setter方法变成属性赋值 @score.setter def chen(self,value): print("Name: {}. Score: {}.age:{}".format(self.name, self.__score,value)) # 实例化,创建对象 student1 = Student("John", 100) #print(student1.name)#可以访问 #print(student1.__score)#私有变量,无法在外部访问 student1.score student1.chen = 50 #直接执行score函数,以变量方式执行函数 #_____________________________________________setter和getter_________________________________ class Test(object): def __init__(self): self.__A = 1 def changeA(self, value): self.__A = value#2 def getA(self): return self.__A # 利用property装饰器把函数伪装成属性-获取 @property def A(self): print('property') return self.__A #setter方法变成属性赋值 @A.setter def A(self, value): print('A.setter-----') self.__A = value #把value赋值给self._A #取方法-重写 @A.getter def A(self): print('A.getter') return self.__A t = Test() t.changeA(2) t.A#默认执行property,当有getter就执行getter下 t.A = 3 print(t.A) print(t.getA())
#!/usr/bin/env python # encoding: utf-8 class People: def __init__(self, name, age): self.__name = name self.__age = age @property def age(self): return self.__age @age.setter def age(self, age): if isinstance(age, int): self.__age = age else: raise ValueError @age.deleter#当删除的时候调用 def age(self): print("删除年龄数据!") obj = People("jack", 18) print(obj.age) obj.age = 500#重新复制 print("obj.age: ", obj.age) del obj.age
面向对象的三种方法:
实例方法
定义:第一个参数必须是实例对象,该参数名一般约定为“self”,通过它来传递实例的属性和方法(也可以传类的属性和方法);
调用:只能由实例对象调用。
类方法
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:类和实例对象都可以调用。
静态方法
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:类和实例对象都可以调用。
#!/usr/bin/env python # encoding: utf-8 __author__ = "晨晨" ''' 1.一般都是实例方法,,@classmethod声明类方法,,@staticmethod声明静态方法。 实例方法调用:只能由实例对象调用 类方法调用:类和实例对象都可以调用 静态方法调用:类和实例对象都可以调用。 ''' import requests class HttpRequest(): #类属性 num = 0 def __init__(self,url,data): #实例属性 self.url = url self.data = data # 实例方法 def send_post(self,url,data): # 实例方法,只能通过实例来调用 res = requests.post(url,data) print('实例方法') print(res.status_code) @classmethod def add(cls,x,y): print('我是类方法') return x+y @staticmethod def print_msg(): print('我是静态方法') if __name__ == '__main__': ''' 注意: 类方法和静态方法可以通过“类名.方法名”直接调用,可以绕过实例方法的初始化函数, 实例方法,只能通过实例来调用 ''' print(HttpRequest.add(7,8))#调用类方法 HttpRequest.print_msg()#静态方法 url = 'https://www.ketangpai.com/UserApi/login' data = { "email": "1489088761@qq.com", "password": "A1234568","remember": 0 } chen_post=HttpRequest(url,data)#创建对象 或实例化类 chen_post.send_post(url,data)#调用实例方法
单例模式:
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
当类初始化的时候,就创建这个实例对象,以后永远返回同一个实例对象。
class Singleton1(object): # 通过覆盖__new__方法来控制对象的创建。 def __new__(cls, *args, **kwargs): # hasattr用于查看对象cls是否有instance属性,该属性作用是检测该类是否已经生成了一个对象 if not hasattr(cls, 'instance'): cls.instance = super(Singleton1, cls).__new__(cls) return cls.instance s = Singleton1() s1 = Singleton1() print(s) print(s1) '''结果: <__main__.Singleton1 object at 0x102c3b198> <__main__.Singleton1 object at 0x102c3b198>
备注:创建多次对象,实际只有一个对象实例
'''
初始化类的时候不创建对象,第一次调用才创建。这个时候就要注意线程安全性了。
class Singleton2(object): __instance = None # 初始化时,如果存在对象,就直接返回这个对象,不存在就不管,也不new它 def __init__(self): if Singleton2.__instance: self.get_instance() # 实际的对象创建发生在调用get_instance的时候 @classmethod def get_instance(cls): if not cls.__instance: cls.__instance = Singleton2() return cls.__instance s = Singleton2() print(s.get_instance()) s1 = Singleton2() print(s1.get_instance()) '''结果: <__main__.Singleton2 object at 0x110062240> <__main__.Singleton2 object at 0x110062240>'''
单例模式优缺点
- 单例模式优点很明显:只提供一个实例化的对象。
- 单例模式具有全局访问权限,全局变量可能在某处已经被修改,但是开发人员仍然认为他们没有发生变化。
- 可能会对同一个对象创建多个引用。
- 所有依赖于全局变量的类都会由于一个类的改变而紧密偶合为全局数据,从而可能在无意中影响另一个类
面向对象案例:
1.总分和平均分数
class Student: def __init__(self, name, score1, score2, score3): self.name = name self.scores = [score1, score2, score3] def get_total_score(self): """计算总分""" return sum(self.scores) def get_average_score(self): """计算平均成绩""" return sum(self.scores) / len(self.scores) student1 = Student("张三", 90, 80, 70) print("学生{}的总分是{},平均分是{}".format(student1.name, student1.get_total_score(), student1.get_average_score()))
每个案例都演示“子类需要额外参数”时,如何把参数一路向上传,同时复用父类逻辑。
class Base: def __init__(self, a): self.a = a print(f'Base 拿到 a={self.a}') class Middle(Base): def __init__(self, a, b): # 把 a 继续往上抛 super().__init__(a) self.b = b print(f'Middle 拿到 b={self.b}') class Leaf(Middle): def __init__(self, a, b, c): # 把 a、b 都往上抛 super().__init__(a, b) self.c = c print(f'Leaf 拿到 c={self.c}') obj = Leaf(1, 2, 3)
参考链接:
https://blog.csdn.net/weixin_45393094/article/details/105273070.................解释python面向对象
https://blog.csdn.net/weixin_44239490/article/details/86357989....................解释python面向对象2
https://blog.csdn.net/zcx1203/article/details/89187495 ...............................类与对象的解释
https://blog.csdn.net/qq_25343557/article/details/81303903 ......................常见的魔法方法,,python面向对象实验一之烤地瓜-CSDN博客
https://blog.csdn.net/weixin_42134789/article/details/80194788 .................Python面向对象编程核心思想
https://www.cnblogs.com/chenxiaoyong/p/6279874.html .............................类定义与使用,,面向对象30个小例子
https://www.liujiangblog.com/course/python/42 .........................................面向对象和面向过程-通俗的例子
https://www.cnblogs.com/hemengjita/p/12590875.html ...............................@property的作用和getter setter的解释
https://blog.csdn.net/The_Time_Runner/article/details/96339117 ..............解释def和class的区别(https://blog.csdn.net/Marry_Ma/article/details/99853975)
https://blog.csdn.net/likunkun__/article/details/93884227 ..........................单例模式的3种方法
浙公网安备 33010602011771号