首页 > 编程语言 >面向对象之面向对象编程

面向对象之面向对象编程

时间:2024-01-29 14:59:42浏览次数:29  
标签:__ 对象 self 绑定 面向对象 面向对象编程 print 属性

面向对象之面向对象编程

一、面向过程与面向对象

[1]面向过程

  • 面向过程着重于过程,就是将程序“流程化”
  • 所谓“流程化”就是将功能、问题等一步一步地逐步实现,像流水线一样,整个过程从开始到结尾线状排序

(1)面向程序的优点

  • 将复杂的问题逐步拆分,进而简单化

(2)面向对象的缺点

  • 一套流程就用来解决一个问题,如果需要实现其他功能或者解决其他问题就要重新再设置另一套流程
  • 如果流程中其中一步出错,需要检查整个流程来排除错误,非常麻烦

[2]面向对象

  • 面向对象着重于过程,就是将程序“整合”
  • 对象就是“容器”,用来盛放数据和功能

(1)面向对象的理解

  • 我们进行面向对象的编程相当于上帝来创造万物,我们想要什么样功能和特性的对象就可以设计怎么样,就像上帝想创造什么就创造什么。

(2)面向对象的简单设计

  • 如果我们要设计一个关于学校的模拟器,那么学校里各种各样的人,比如学生、老师、各类职工等就是我们的对象。
  • 不同的人有不同的名字、性别、年龄等也能做不同的事,就有不同的属性和功能:
    • 学生有姓名、年龄、班级等,可以上课、学作业、运动等。
    • 老师有也有姓名、年龄、班级等,可以授课,批改作业,组织考试等
  • 我们将整个学生所有的信息(属性)和能做的事(功能)全部封装起来就形成了一个关于学生的类;当然整个老师所有的信息(属性)和能做的事(功能)全部封装起来就形成了一个关于老师的类

(3)面向对象的优点

  • 解决了程序的扩展性。
  • 对某一个对象单独修改,会立刻反映到整个体系中。

(4)面向对象的缺点

  • 编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。
    • 一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。
  • 无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法准确地预测最终结果。
    • 于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。

(5)小结

  • 在了解了对象的基本概念之后,理解面向对象的编程方式就相对简单很多了
  • 面向对象编程就是要造出一个个的对象,把原本分散开的相关数据与功能整合到一个个的对象里
  • 这么做既方便使用,也可以提高程序的解耦合程度,进而提升了程序的可扩展性(需要强调的是,软件质量属性包含很多方面,面向对象解决的仅仅只是扩展性问题)

二、类与对象

[1]引言

  • 类即类别/种类,是面向对象分析和设计的基石,如果多个对象有相似的数据与功能,那么该多个对象就属于同一种类。
  • 有了类的好处是:
    • 我们可以把同一类对象相同的数据与功能存放到类里,而无需每个对象都重复存一份,这样每个对象里只需存自己独有的数据即可,极大地节省了空间。
  • 所以,如果说对象是用来存放数据与功能的容器,那么类则是用来存放多个对象相同的数据与功能的容器。

  • 综上所述,虽然我们是先介绍对象后介绍类,但是需要强调的是:
    • 在程序中,必须要事先定义类,然后再调用类产生对象(调用类拿到的返回值就是对象)。
    • 产生对象的类与对象之间存在关联,这种关联指的是:对象可以访问到类中共有的数据与功能
    • 所以类中的内容仍然是属于对象的,类只不过是一种节省空间、减少代码冗余的机制
  • 面向对象编程最终的核心仍然是去使用对象。

[2]什么是类

  • 类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体
  • 所以,先有鸡和先有蛋的问题就出来了
    • 先有的一个个具体存在的对象(比如一个具体存在的人)
    • 还是先有的人类这个概念,这个问题需要分两种情况去看

(1)现实中

  • 在现实世界中:先有对象,再有类
  • 世界上肯定是先出现各种各样的实际存在的物体,然后随着人类文明的发展,人类站在不同的角度总结出了不同的种类,如人类、动物类、植物类等概念
  • 也就说,对象是具体的存在,而类仅仅只是一个概念,并不真实存在

(2)程序中

  • 类的关键字(class

  • 在程序中:务必保证先定义类,后产生对象

  • 这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类

  • 不一样的是,调用函数会执行函数体代码返回的是函数体执行的结果,而调用类会产生对象,返回的是对象

三、面向对象编程

[1]引入

  • 按照上述的理论我们来定义一个类
  • 我们构建一个学校:先有对象,后有类

(1)对象的设计

  • 对象1:桃源氏

    • 信息(属性):

      ​ 学校 : 世外桃源

      ​ 姓名:桃源氏

      ​ 性别:男

      ​ 班级:101

    • 能做的事(功能):上课、写作业、运动

  • 对象2:小桥

    • 信息(属性):

      ​ 学校 : 世外桃源

      ​ 姓名:小桥

      ​ 性别:女

      ​ 班级:101

    • 能做的事(功能):上课、写作业、运动

(2)类的设计

  • 构建的学校类
    • 相同的信息(属性):学校:世外桃源
    • 能做的相同的事(功能):上课、写作业、运动
  • 这样我们就可以总结出一个学生类,用来存放学生相同的数据和功能

[2]类的实现

  • 基于上述分析的结果,我们接下来需要做的就是在程序中定义出类,然后调用类产生对象
# 1. 在程序中特征用变量标识,技能用函数标识
# 2. 因而类中最常见的无非是:变量和函数的定义
# 在程序中定义一个类
# 类的命名应该使用“驼峰体”

class XanaduStudent(object):
    school = '世外桃源'

    def attend_class(self):
        print('可以上课')

    def repair_homework(self):
        print('可以修作业')

    def sport(self):
        print('可以运动')
  • 注意:
    • 类中可以有任意python代码,这些代码在类定义阶段便会执行
    • 因而会产生新的名称空间,用来存放类的变量名与函数名,可以通过XanaduStudent.__dict__查看
    • 对于经典类来说我们可以通过该字典操作类名称空间的名字(新式类有限制),但python为我们提供专门的.语法
    • 点是访问属性的语法,类中定义的名字,都是类的属性

[3]类的使用

(1)查看类的名称空间

  • 类体最常见的是变量的定义和函数的定义,但其实类体可以包含任意Python代码,类体的代码在类定义阶段就会执行,因而会产生新的名称空间用来存放类中定义的名字,可以打印XanaduStudent.__dict__来查看类这个容器内盛放的东西
print(XanaduStudent.__dict__)
# {'__module__': '__main__', 'school': '世外桃源', 
# 'attend_class': <function XanaduStudent.attend_class at 0x000001D4E5DA28C0>, 
# 'repair_homework': <function XanaduStudent.repair_homework at 0x000001D4E5DA36D0>, 
# 'sport': <function XanaduStudent.sport at 0x000001D4E6071AB0>, 
# '__dict__': <attribute '__dict__' of 'XanaduStudent' objects>,
# '__weakref__': <attribute '__weakref__' of 'XanaduStudent' objects>,
# '__doc__': None}

(2)对象的实例化

  • 调用类的过程称为将类实例化
    • 拿到的返回值就是程序中的对象,或称为一个实例
student_1 = XanaduStudent()  # 每实例化一次Student类就得到一个学生对象
student_2 = XanaduStudent()  # 但是这样实例化出来的对象全都一样没有各自独特的数据了
  • 想在实例化的过程中就为三位学生定制各自独有的数据:
    • 姓名,性别,年龄,需要我们在类内部新增一个__init__方法,如下
class XanaduStudent(object):
    school = '世外桃源'

    # 该方法会在对象产生之后自动执行,专门为对象进行初始化操作,可以有任意代码,但一定不能返回非None的值
    def __init__(self, name, sex, age):
        self.name = name
        self.sex = sex
        self.age = age


    def attend_class(self):
        print('可以上课')

    def repair_homework(self):
        print('可以修作业')

    def sport(self):
        print('可以运动')
  • 现在我们实例化出来的学生就可以有自己独特的数据
student_1 = XanaduStudent('桃源氏', "男", 22)
print(student_1.__dict__)  # {'name': '桃源氏', 'sex': '男', 'age': 22}
student_2 = XanaduStudent('小桥', '女', 20)
print(student_2.__dict__)  # {'name': '小桥', 'sex': '女', 'age': 20}
  • 使用__dict__方法我们可以看到对象的名称空间

[4]属性访问

(1)类属性与对象属性

  • 在类中定义的名字,都是类的属性,细说的话,类有两种属性:
    • 数据属性和函数属性
    • 可以通过__dict__访问属性的值,比如XanaduStudent.__dict__[‘school’],但Python提供了专门的属性访问语法
print(XanaduStudent.school)  # 世外桃源
print(XanaduStudent.attend_class)  # <function XanaduStudent.attend_class at 0x000001AD305F36D0>
# 除了查看属性外,我们还可以使用Student.attrib=value(修改或新增属性),用del Student.attrib删除属性。
  • 操作对象的属性也是一样
print(student_1.name)  # 桃源氏
student_1.grades = 100  # 新增,等同于obj1.__dict__[‘grades']='100'
print(student_1.grades)  # 100
student_1.age = 18  # 修改,等同于obj1.__dict__[‘age']=18
print(student_1.age)  # 18
del student_1.grades  # 修改,等同于del obj1.__dict__['grades']
print(student_1.grades)  # AttributeError: 'XanaduStudent' object has no attribute 'grades'

(2)属性查找

  • 对象的名称空间里只存放着对象独有的属性,而对象们相似的属性是存放于类中的。
  • 对象在访问属性时,会优先从对象本身的__dict__中查找,未找到,则去类的__dict__中查找
1、类中定义的变量是类的数据属性,是共享给所有对象用的,指向相同的内存地址
print(id(XanaduStudent))  # 2378796475824

print(id(student_1.school))  # 2378796475824
print(id(student_2.school))  # 2378796475824
2、类中定义的函数是类的函数属性,类可以使用,但必须遵循函数的参数规则,有几个参数需要传几个参数
student_1.repair_homework()  # 桃源氏可以修作业
student_2.repair_homework()  # 小桥可以修作业
  • 但其实类中定义的函数主要是给对象使用的,而且是绑定给对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法,内存地址各不相同
print(id(XanaduStudent.repair_homework))  # 2054066543280

print(id(student_1.repair_homework))  # 2054066526080
print(id(student_2.repair_homework))  # 2054066526016
  • 绑定到不同对象的repair_homework技能
    • 虽然都是选课,但桃源氏选的课,不会选给小桥,这正是”绑定“二字的精髓所在。
  • 注意:绑定到对象方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但命名为self是约定俗成的。

[5]小结

在上述介绍类与对象的使用过程中,我们更多的是站在底层原理的角度去介绍类与对象之间的关联关系

如果只是站在使用的角度,我们无需考虑语法“对象.属性"中”属性“到底源自于哪里,只需要知道是通过对象获取到的就可以了

所以说,对象是一个高度整合的产物,有了对象,我们只需要使用”对象.xxx“的语法就可以得到跟这个对象相关的所有数据与功能,十分方便且解耦合程度极高。

[6]绑定方法与非绑定方法

  • 类中的属性有两种:一种是变量类型的属性,称为数据属性:另一种是函数类型的属性,称为函数属性,也可以称之为方法
  • 类中的函数,也就是方法,有其特殊的特性和分类,一般通过不同角色调用方式的不同分为绑定方法和非绑定方法;绑定方法有通过绑定目标的不同分为绑定给对象的方法和绑定给类的方法

方法(函数属性):

  • 绑定方法(动态方法)
    • 绑定给对象的方法
    • 绑定给类的方法
  • 非绑定方法(静态方法)

(1)绑定方法(动态方法)

1.绑定给对象的方法
  • 绑定给对象的方法是最常见的一种方法:就是直接在类中定义的函数
class Student(object):
    def __init__(self, name):
        self.name = name

    # 绑定给对象的方法(默认参数需要将self也就是对象的自身传入函数内部)
    def attend_class(self):
        print(f'{self.name}可以上课。')


# 实例化出一个对象并调用,不要需要传入额外参数,因为实例方法默认第一个参数是self会自动传入
stu_1 = Student('桃源氏')
stu_1.attend_class()  # 桃源氏可以上课。
# 直接使用类调用就需要传入self参数,不然就会报错
Student.attend_class()  # TypeError: Student.attend_class() missing 1 required positional argument: 'self'
Student.attend_class(stu_1)  # 桃源氏可以上课。
2.绑定给类的方法
  • 绑定给类的方法需要在定义的函数前加上@classmethod语法糖来装饰
class Student(object):
    def __init__(self, name):
        self.name = name  
        
    # 绑定给类的方法(默认参数需要将cls也就是对象的自身传入函数内部)
    @classmethod
    def do_homework(cls):
        print(f'做作业。')


#  实例化出一个对象并调用绑定给类的方法,不需要额外传入参数
stu_1 = Student('桃源氏')
stu_1.do_homework()  # 做作业。
# 直接使用类调用绑定给类的方法,也不需要额外传入参数
Student.do_homework()  # 做作业。

#这样就可以在不实例化对象的前提下,直接使用类中的方法

(2)非绑定方法(静态方法)

  • 绑定给类的方法需要在定义的函数前加上@staticmethod语法糖来装饰
class Student(object):
    def __init__(self, name):
        self.name = name
        
    #  非绑定方法(静态方法)
    #  静态方法没有默认的第一个参数,与一般函数类似
    @staticmethod
    def run():
        print('跑步')


#  实例化出一个对象并调用非绑定方法,不需要额外传入参数
stu_1 = Student('桃源氏')
stu_1.run()  # 跑步
# 直接使用类调用非绑定方法,也不需要额外传入参数
Student.run()  # 跑步

[7]__init__(self) 方法初识

  • 为了使类能实例化出带有独特属性的对象我们可以在类的内部使用__init__(self)方法
class Person(object):
    country = 'China'

    def __init__(self, name, age):
        self.name = name
        self.age = age


people_1 = Person('桃源氏', 22)
people_2 = Person('小桥', 20)

print(people_1.name)  # 桃源氏
print(people_2.name)  # 小桥

# 强调:
#   1、该方法内可以有任意的python代码
#   2、一定不能有返回值

[8]注意

1. 站的角度不同,定义出的类是截然不同的

2. 现实中的类并不完全等于程序中的类,比如现实中的公司类,在程序中有时需要拆分成部门类,业务类......

3. 有时为了编程需求,程序中也可能会定义现实中不存在的类,比如策略类,现实中并不存在,但是在程序中却是一个很常见的类

标签:__,对象,self,绑定,面向对象,面向对象编程,print,属性
From: https://www.cnblogs.com/taoyuanshi/p/17994489

相关文章

  • 面向对象的三大特性之继承
    面向对象的三大特性之继承一、什么是继承继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类。子类会“”遗传”父类的属性,从而解决代码重用问题(去掉冗余的代码)python中类的继承分为:单继承和多继承二......
  • 面向对象之抽象类
    面向对象之抽象类一、接口与抽象类[1]什么是接口因为Python中没有具体的接口概念我们以Java中的接口来对接口进行解释:我们以IAnimal.java(动物类)为例Java的Interface接口的特征是一组功能的集合,而不是一个功能接口的功能用于交互,所有的功能都是public,即别的对象可操作......
  • 面向对象之元类
    面向对象之元类一、什么是元类产生已知类的类就叫做元类,typeclassPerson(object):...deffunc():...people=Person()#产生对象的是类print(type(people))#<class'__main__.Person'>print(type(func))#<class'function'>#产生类的就是元类p......
  • 面向对象之内置方法
    面向对象之内置方法​Python的Class机制内置了很多特殊的方法来帮助使用者高度定制自己的类这些内置方法都是以双下划线开头和结尾的,会在满足某种条件时自动触发__init__ :初始化类时触发__del__ :删除类时触发__new__ :构造类时触发__str__ :str函数或者print函数触发__......
  • 面向对象之派生和组合
    面向对象之派生和组合派生派生是指,子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法一、派生的方法子类是必须要派生出自己的数据属性不然就无数据属性可用子类无法使用父类中__init__定义的属性classPerson(object):def__init__(self,name,age......
  • 面向对象基础 成员变量、成员方法、构造方法、this关键字、静态字段、静态方法..
    成员变量与局部变量的区别:  1.作用域:成员变量作用于整个类,局部变量只作用于它所属的范围(函数、语句)  2.生命周期&位置:成员变量存储在堆内存中,是属于对象的,随着对象存在消失。局部变量存储在栈内存中,是属于他所属的范围的,使用完自动释放。  3.初始值:成员变量有默认初始......
  • day01-面向对象高级
    day01——面向对象高级各位同学,接下来的三天课程中,我们继续学习面向对象的相关课程。面向对象是写Java程序的核心套路,如何你不懂面向对象,那就相当于Java你白学了。所以在接下来的三天时间里,各位同学也需要克服重重困难好好学习。前面我们说过面向对象最核心的套路是:设计对象来处......
  • C# 面向对象编程进阶:构造函数详解与访问修饰符应用
    C#构造函数构造函数是一种特殊的方法,用于初始化对象。构造函数的优势在于,在创建类的对象时调用它。它可以用于为字段设置初始值:示例获取您自己的C#服务器创建一个构造函数://创建一个Car类classCar{publicstringmodel;//创建一个字段//为Car类创建一个......
  • C# 面向对象编程进阶:构造函数详解与访问修饰符应用
    C#构造函数构造函数是一种特殊的方法,用于初始化对象。构造函数的优势在于,在创建类的对象时调用它。它可以用于为字段设置初始值:示例获取您自己的C#服务器创建一个构造函数://创建一个Car类classCar{publicstringmodel;//创建一个字段//为Car类创建一......
  • 理论篇:面向对象程序设计指导
    》本文来自看过的相关知识的摘录整理,太久了,忘了主要出自哪儿里了。软件架构架构(Architecture)是指一个系统或软件的总体设计和组织结构,包括其各个组件、模块、接口和数据流等。架构设计的目的是确保系统或软件具有可扩展性、可维护性、可靠性和安全性等特性,并且能够满足业务需......