2025年Python菜鸟编程第十课之面向对象

Python菜鸟编程第十课之面向对象Python 菜鸟编程第十课之面向对象 1 面向过程与面向对象编程 面向过程 所谓过程 就是我们解决问题的步骤 一步步的按照流程走 有先后之分 整个设计就好比流水线 思维上比较机械 优点 复杂问题流程化 将问题分解 缺点 拓展性不好 面向对象

大家好,我是讯享网,很高兴认识大家。

Python菜鸟编程第十课之面向对象

1.面向过程与面向对象编程

  • 面向过程:

    所谓过程,就是我们解决问题的步骤,一步步的按照流程走,有先后之分。整个设计就好比流水线,思维上比较机械。

    优点:复杂问题流程化,将问题分解。

    缺点:拓展性不好

  • 面向对象:

    对象是一个数据以及相关行为的集合,面向对象是功能上指向建模对象。面向对象是通过数据和行为方式来描述交互对象的集合。

    优点:解决程序的拓展性

    缺点:复杂度远高于面向过程。交互式解决问题,无法准确预测结果。

object1 Tom 特征: school=zucc name=tom age=20 sex=male 技能: eat study sleep object2 Jack 特征: school=zucc name=jack age=21 sex=male 技能: eat study sleep sing 

讯享网

类就是类别、种类。对象就是特征和技能的统一体。类则是这一系列对象的特征和技能的结合。现实生活中,先有个体(对象)才有类别,但对于程序,必须先有类,才会有对象。

2.面向对象编程

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 方法:类中定义的函数。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
讯享网OOP(object oriented programming) 

OOP把对象作为程序的一个基本单元,一个对象就包含了数据和操作数据的函数。

在Python中,所有数据类型,都可以称之为对象,同时我们也可以自定义对象。

自定义的对象的数据类型就是面向对象中类(class)的概念。

demo1:

用面向对象编程来处理学生成绩。

class Student: def __init__(self, name, score): self.name = name self.score = score def find_score(self): print(self.name, ':', self.score) stu1 = Student('Tom', 90) stu1.find_score() 
讯享网运行结果: Tom : 90 

用面向过程来处理学生成绩:

stu1 = { 
   'name': 'Tom', 'score': 90} def find_score(stu): print(stu['name'], ":", stu['score']) find_score(stu1) 
讯享网运行结果: Tom : 90 

demo2:

class Student: def __init__(self, name, score, school, age): self.name = name self.score = score self.school = school self.age = age def find_score(self): print(self.name, ':', self.score) def eating(self): print(self.name, '来自', self.school, ',今年', self.age, '岁,', '正在eat') def studying(self): print(self.name, '来自', self.school, ',今年', self.age, '岁,', '正在 study') stu1 = Student('Tom', 90, 'zucc', 18) stu1.find_score() stu1.eating() stu1.studying() 
讯享网运行结果: Tom : 90 Tom 来自 zucc ,今年 18, 正在eat Tom 来自 zucc ,今年 18, 正在 study 

3.类的定义和使用

3.1类的定义

类的命名,约定俗成使用大驼峰式命名。大驼峰就是变量名称的首字母大写。

语法:

class ClassName(object): '''说明文档''' def \__init__(self,para1,para2...): self.对象属性1=para1 def 方法名1(self): pass class_statement obj=ClassName(para1,para2) #类的实例化,代表具体的东西,ClassName():调用\__init__,括号内传参,无需传入self,参数一一对应,结果返回对象obj obj.对象属性1#查看对象的属性 obj.方法名#调用类的方法 

类的两个作用:

  • 属性引用:类名.属性
  • 实例化:类名加括号就是实例化,它能够自动触发__init__函数,进而为每个实例定制自己的特征。

demo:1

定义一个简单的类。

讯享网class Student: def __init__(self, name, score, school, age): self.name = name self.score = score self.school = school self.age = age stu1 = Student('Tom', 90, 'zucc', 18)#将类实例化 print(stu1.name,stu1.score) 
运行结果: Tom 90 

和普通函数相比,在类中定义方法时,第一个参数必须是self。除了第一个参数外,其他的和普通函数没什么区别。

__init__方法:为对象初始化自己独有的特征。该方法中可以有任意的代码,但是一定不能有返回值。

demo2:

讯享网class Student: def test_instance(self): print(self) stu1 = Student() stu1.test_instance() 
运行结果: <__main__.Student object at 0x0000025338BB82B0> 

self 代表的是实例,而非类。

3.2数据封装

demo:

讯享网class Student: def __init__(self, name, score): self.name = name self.score = score def find_score(self): print(self.name, ':', self.score) stu1 = Student('Tom', 90) stu1.find_score() 

通过_init_()让stu1实例本身就拥有了相关数据,如果要访问这些数据,我们可以直接在student类的内部定义相关的函数来访问,以此来“封装”数据。这些封装数据的函数与Student类本身是关联起来的,称之为方法。

demo1:

class Point: pass p1 = Point() p1.x = 5 p1.y = 4 print(p1.x, p1.y) 
讯享网运行结果: 5 4 

通过点记法给实例化的对象赋予任何属性。

demo2:

class Point: def resect(self): self.x=0 self.y=0 p1 = Point() p1.resect() print(p1.x, p1.y) p1.x = 5 p1.y = 4 print(p1.x, p1.y) 
讯享网运行结果: 0 0 5 4 

demo:

import math class Point: def move(self, x, y): self.x = x self.y = y def resect(self): self.move(0,0) def cal_distence(self, other_point): return math.sqrt((self.x - other_point.x)  2 + (self.y - other_point.y)  2) p1 = Point() p1.resect() p2=Point() p2.move(3,4) print(p1.cal_distence(p2)) 
讯享网运行结果: 5.0 

demo:

import math class Point: def __init__(self, x, y): self.x = x self.y = y def move(self, x, y): self.x = x self.y = y def resect(self): self.move(0, 0) def cal_distence(self, other_point): return math.sqrt((self.x - other_point.x)  2 + (self.y - other_point.y)  2) p3 = Point(6, 8) print(p3.x, p3.y) 
讯享网运行结果: 6 8 

3.3类属性的查看

  1. dir()

demo:

import math class Point: def __init__(self, x, y): self.x = x self.y = y def move(self, x, y): self.x = x self.y = y def resect(self): self.move(0, 0) def cal_distence(self, other_point): return math.sqrt((self.x - other_point.x)  2 + (self.y - other_point.y)  2) print(dir(Point)) 
讯享网运行结果: ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'cal_distence', 'move', 'resect'] 

2.类名.__dict__查看

返回字典,key为属性名,value为属性值。


讯享网

demo:

import math class Point: def __init__(self, x, y): self.x = x self.y = y def move(self, x, y): self.x = x self.y = y def resect(self): self.move(0, 0) def cal_distence(self, other_point): return math.sqrt((self.x - other_point.x)  2 + (self.y - other_point.y)  2) print(Point.__dict__) 
讯享网运行结果: { 
   '__module__': '__main__', '__init__': <function Point.__init__ at 0x0000016F891A6488>, 'move': <function Point.move at 0x0000016F8A24A950>, 'resect': <function Point.resect at 0x0000016F8A24A9D8>, 'cal_distence': <function Point.cal_distence at 0x0000016F8A24AA60>, '__dict__': <attribute '__dict__' of 'Point' objects>, '__weakref__': <attribute '__weakref__' of 'Point' objects>, '__doc__': None} 

特殊的类属性:

函数名 描述
类名._name_ 返回类的名字
类名._doc_ 返回类的文档字符串
类名._base_ 返回类的第一个父类
类名._bases_ 返回类的所有父类构成的元组
类名._module_ 返回类定义所以的模块
类名._class_ 返回实例所对应的类
类名._dict_ 返回类的字典属性

3.4类的交互

demo:

class Person: def __init__(self, name, aggressivity, life_value): self.name = name self.aggressivity = aggressivity self.life_value = life_value def attack(self, dog): dog.life_value -= self.aggressivity class Dog: def __init__(self, name, breed, aggressivity, life_value): self.name = name self.breed = breed # 品种 self.aggressivity = aggressivity self.life_value = life_value def bite(self, people): people.life_value -= self.aggressivity per = Person('Bob', 10, 1000) dog = Dog('Wawa', 'Husky', 20, 500) print(dog.life_value) per.attack(dog) print(dog.life_value) 
讯享网运行结果: 500 490 

3.5类命名空间与对象、实例的空间

创建一个类就会创建一个类的名称空间,用来存储我们定义的所有变量名,这些名字就是属性。

类的属性分为:

  • 静态属性:

    直接在类中定义的变量

  • 动态属性:

    在类中定义的方法

静态属性是共享给所有对象的,动态属性是绑定到所有对象的。

demo:

class Person: face = 'aaa' def __init__(self, name, aggressivity, life_value): self.name = name self.aggressivity = aggressivity self.life_value = life_value def attack(self, dog): dog.life_value -= self.aggressivity per = Person('Bob', 10, 1000) per1=Person('Tom',23,1000) print(id(per.face)) print(id(per1.face)) print(per.attack)#注意,这里都是没有加括号的 print(per1.attack) print(Person.attack) 
讯享网运行结果: 40 40 <bound method Person.attack of <__main__.Person object at 0x00000E5940>> <bound method Person.attack of <__main__.Person object at 0x00000E5E80>> <function Person.attack at 0x00000A950> 

3.6类的继承

类的三大特性:继承、多态、封装。

在面向对象编程中,当我们定义一个新的类时,可以从某个现有的类继承,新的类就被称为子类(Sub Class),而被继承的类则被称为基类,父类,超类(Base Class,Father Class ,Super Class)。

demo1:

class Animal(object): def run(self): print('Animal is runing.') class Dog(Animal): pass class Cat(Animal): pass dog=Dog() cat=Cat() print(dog.run()) print(cat.run()) 
讯享网运行结果: Animal is runing. None Animal is runing. None 

demo2:

class Animal(object): # 定义父类 def run(self): print('Animal is runing.') class Animal2: pass class Dog(Animal): # 单继承 pass class Cat(Animal): # 单继承 pass class Huaky(Animal, Animal2): # 多继承,用逗号隔开 pass print(Dog.__bases__) print(Huaky.__bases__) print(Animal.__bases__) print(Animal2.__class__) 
讯享网运行结果: (<class '__main__.Animal'>,) (<class '__main__.Animal'>, <class '__main__.Animal2'>) (<class 'object'>,) <class 'type'> 

如果不指定基类,Python会默认继承object类。object是所有Python的基类,提供一些常见方法的实现。

demo3:

多态,当子类与父类存在相同的方法时,子类的方法会覆盖父类的方法。

定义一个类的时候,实际上就是定义了一种数据类型。我们自定义的数据类型和Python自带的数据类型,如str,int等什么区别。

class Animal(object): # 定义父类 def run(self): print('Animal is runing.') class Dog(Animal): # 单继承 def run(self): print('Dog is Running') dog=Dog() print(dog.run()) 
讯享网运行结果: 

demo4:

class Animal(object): # 定义父类 def run(self): print('Animal is runing.') class Dog(Animal): # 单继承 def run(self): print('Dog is Running') dog=Dog() li=[] print(isinstance(li,list))#isinstance()用来判断数据类型 print(isinstance(dog,Dog)) print(isinstance(dog,Animal)) 
讯享网运行结果: True True True 

对于一个变量,我们只需知道他的父类型,无需知道子类型,就可以放心调用相关的方法。运行时的具体方法时作用在子类型上还是父类型上,由运行对象决定。也即是说,调用时只管调用,不管细节,当我们新增一个子类时,只要保证相关的方法编写正确,就不用管原来的代码是如何调用的。

“开闭”原则:

  • 对拓展开放:允许新增子类
  • 对修改封闭:不需要修改依赖父类类型的函数。

demo5:

class Student: school = 'zucc' def __init__(self, name, score): self.name = name self.score = score def find_score(self): print(self.name, ':', self.score) stu1=Student('Bob',98) print(stu1.score) stu1.score=50 print(stu1.score) 
讯享网运行结果: 98 50 

从这里可以看出,外部代码可以修改实例的属性(name,score)。如果要让内部的属性不被外部访问,可以在属性前面加两个下划线。

在Python中,实例的变量名如果以双下划线开头,就变成了一个私有变量,只有内部可以访问,外部不能访问。

demo6:

class Student: school = 'zucc' def __init__(self, name, score): self.name = name self.__score = score def find_score(self): print(self.name, ':', self.__score) stu1 = Student('Bob', 98) print(stu1.score) stu1.score = 50 print(stu1.score) 
讯享网运行结果: Traceback (most recent call last): File "D:/PyCharm/BClass/PXClass/2019-7-29/daylystudy.py", line 153, in <module> print(stu1.score) AttributeError: 'Student' object has no attribute 'score' 

demo7:

class Student: school = 'zucc' def __init__(self, name, score): self.__name = name self.__score = score def get_name(self): return self.__name def get_score(self): return self.__score def find_score(self): print(self.__name, ':', self.__score) stu1 = Student('Bob', 98) print(stu1.get_score()) stu1.score = 50 print(stu1.get_score()) 
讯享网运行结果: 98 98 

3.7类的封装

隐藏对象的属性和实现细节仅对外提供公共访问的方式。

这样做的优点在于:

  1. 可以将变化隔离。
  2. 便于使用
  3. 提高安全性
  4. 提高复用性

封装的原则:将不需要对外提供的内容隐藏起来。隐藏属性,提供公共方法对其进行访问。

demo:

class Student: school = 'zucc' def __init__(self, name, score): self.__name = name self.__score = score def get_name(self): return self.__name def get_score(self): return self.__score def set_score(self,score): if 0<=score<=100: self.__score=score else: raise ValueError('Bad score') def find_score(self): print(self.__name, ':', self.__score) stu1 = Student('Bob', 98) print(stu1.find_score()) stu1.score=97 print(stu1.score) print(stu1.find_score()) print(stu1.set_score(97)) print(stu1.find_score()) print(stu1._Student__score) 
讯享网运行结果: Bob : 98 #print(stu1.find_score()) None 97 #print(stu1.score) Bob : 98 #print(stu1.find_score()) None None #print(stu1.set_score(97)) Bob : 97 #print(stu1.find_score()) None #print(stu1._Student__score) 97 

demo:

class Animal(object): # 定义父类 def run(self): print('Animal is runing.') class Dog(Animal): # 单继承 def run(self): print('Dog is Running') class Cat(Animal): # 单继承 pass class Duck: def run(self): print('多态测试。') dog = Dog() cat = Cat() duck = Duck() dog.run() cat.run() duck.run() def run_twice(animal): animal.run() animal.run() run_twice(duck) 
讯享网运行结果: Dog is Running Animal is runing. 多态测试。 多态测试。 多态测试。 

鸭子类型不需要有严格的继承关系,一个对象,只要”看起来像鸭子,走路像鸭子“,也就是说,如果要编写现有对象的自定义版本,可以继承该对象,也可以创建一个外观和行为相似但与其没有任何关系的全新对象。

比方说,利用标准库中定义的各种“与文件类似”的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法。

博主:,欢迎批评指正!

小讯
上一篇 2025-04-09 21:14
下一篇 2025-03-15 17:30

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/40613.html