对象
对象是被称为面向对象编程(简称OOP)的庞大编程范式的构建模块。类是python的主要面向对象编程工具,因此我们将在python的基础上研究对象类
.类是用来创建和管理新对象和支持的继承——面向对象编程(OOP)领域的关键组成部分和重用代码的机制。
历史上的注意
当SIMULA编程语言的设计者Ole-Johan Dahl和Kristen Nygaard认为类、对象、继承和动态绑定的概念是设计离散事件模拟程序的巧妙方法时,对象的想法首次出现在SIMULA编程语言中。
值得注意的是,使用OOP是完全可选的,大多数程序都可以不用它编写。你可以用函数和变量做很多事情。使用OOP的主要优点是,它是组织代码的一种非常有用的方法,特别是对于非常大的项目。因为使用类需要一些事先的计划,所以通常情况下,在战略模式下工作的人比在战术模式下工作的人更感兴趣。
类
在面向对象编程中,类是用于创建对象的可扩展程序代码模板,为状态(成员变量)和行为(成员函数、方法)的实现提供初始值。方法创建用户定义的对象类
关键字。该类是定义未来对象的性质的蓝图。我们从类中构造实例。实例是从特定类创建的特定对象。
下面是一个简单的python类的例子,它定义了brilliant社区中的人:
1 2 3 4 5 6 7 8 9 10 |
|
以上是一个类
语句,它定义了一个新类,就像def
语句定义一个新函数。这个类的名字是才华横溢的
.
Instance是从特定类创建的特定对象。要创建类的实例,您可以使用类名调用类,并传入它的任何参数__init__
方法接受。
1 |
|
的新实例才华横溢的
类。或者换句话说,我们实例化才华横溢的
类
1 |
|
以上定义了方法为才华横溢的
类。方法用于属于类的函数。
这个名字__init__ ()
用于类的“构造函数”。虽然类是新数据类型的蓝图,但您仍然需要创建此数据类型的值,以便拥有可以存储在变量中或传递给函数的内容。
调用时,构造函数创建新对象,运行构造函数中的代码,并返回新对象。这就是user =brilliant ('Mursalin', 17,4)
线。无论类名是什么,构造函数总是命名的__init__
.
另一个常用术语是属性。属性是对象的特征。调用的方法__init__ ()
用于初始化对象的属性。就像方法是定义在类中的函数一样,属性是定义在类中的变量。
类定义中的每个方法都以对实例对象的引用开始。按照惯例,它被命名为“自我”。
在Python中,方法的第一个参数自我
.的自我
参数用于创建成员变量。
构造函数的主体是:
1 2 3 |
|
这看起来有点重复,但这段代码的作用是为构造函数创建的对象创建成员变量。成员变量将从自我
.表明它们是属于对象的成员变量,而不仅仅是方法中的常规局部变量。
数据
数据引用的属性只是我们定义的类的变量。它们也被称为类变量。它们可以像任何其他变量一样使用,因为它们是在创建类时设置的,并且可以通过类内的方法或程序主体部分的其他地方进行更新。Java程序员将这类变量称为静态
.
它们也可以成为类的唯一属性。这些类型的类数据称为实例变量.这意味着它们与类相关联,Java程序员将它们称为非静态变量。
使用静态类数据属性的示例
1 2 3 4 5 6 7>>>类酒吧(对象):...喷火=2>>>打印酒吧.喷火2>>>酒吧.喷火=酒吧.喷火+1>>>打印酒吧.喷火101
类是数据结构定义类型,而实例是该类型变量的声明。实例本质上是赋予生命的类。一个类
声明基本上描述了应该存在的框架。如果任何房子的单个总体建设计划是一个类,那么实例就是实际的特定类型的房子,它有自己的属性,但仍然遵循一般结构。尽管许多其他OOP语言提供了新的关键字来创建实例类,但python只需要使用参数调用类。
创建类实例的示例
1 2 3 4 5 6 7 8 9类房子(对象):颜色=没有一个大小=没有一个bluehouse=房子()bluehouse.颜色=“蓝”redhouse=房子()redhouse.颜色=“红色”打印bluehouse.颜色#打印“蓝”打印redhouse.颜色#打印“红色”
方法
方法相当于面向对象世界中的函数。如果您有过程编程的背景,也就是说,您已经在程序中使用过函数,那么您就知道方法在调用时应该产生一些输出。方法也可以接受参数并对其进行操作,然后根据这些参数生成输出,就像函数一样。但是,为什么不直接称它们为“函数”呢?“方法”一词的使用并不局限于某种花哨的术语,因为方法不是“仅仅”用于执行简单的计算,而是根据它们在类设计中的用途进行分类。
接口方法
接口方法的目的是提供对象与外部环境的接口(可以是其他对象的方法、来自用户的数据输入、来自另一个对象的数据,以及不在同一对象内部的任何东西)。OO设计的原则之一是封装:将该对象构建为一个胶囊,其中包含其所有数据和方法。然而,正如您所猜测的,一个与所有事物隔离的对象是毫无用处的,它应该是更大系统的一部分。这时接口方法就派上用场了:它们为对象提供获得外部输入和提供输出所需的最小接口,因此它既可以成为更大系统的一部分,又可以成为更小系统的一部分。
例如,为属性定义getter和setter方法是一种非常好的OO实践,主要是出于安全和代码完整性的考虑。getter和setter方法以间接的方式提供对外部代理的内部属性访问(在下面的“对象变量类型和作用域”一节中,您将看到这个方法的有用性的示例)。让我们看看它们是如何实现的:
Java中的Getter和Setter接口方法:
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40//如果你不知道为什么在这里使用keywork 'public',它的用途将在下面的“对象变量类型和作用域”部分中清楚地说明。公共类广场{// 'double'是属性的数据类型,必须声明。私人双sideLength;// 'double'是方法返回的数据类型,必须声明。/ /获取:公共双getSideLength(){返回这.sideLength;}// 'void'用于表示该方法不返回任何值。必须声明参数数据类型。/ /赋值:公共无效setSideLength(双sideLength){这.sideLength=sideLength;}公共广场(双sideLength){这.sideLength=sideLength;}公共静态无效主要(字符串[]arg游戏){//保存对象的变量的“数据类型”是该对象的类。广场广场=新广场(10.0);系统.出.println(广场.getSideLength());//打印10.0到屏幕上广场.setSideLength(3.0);系统.出.println(广场.getSideLength());//打印3.0到屏幕上}}
记住Main()方法是Java标准;它的内容是当Java程序运行时要执行的代码。
Python中的Getter和Setter接口方法:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20类广场(对象):def__init__(自我,sideLength):自我.sideLength=sideLength# Getter:defgetSideLength(自我):返回自我.sideLength# Setter:defsetSideLength(自我,sideLength):自我.sideLength=sideLength广场=广场(10.0)打印广场.getSideLength()#打印10.0到屏幕上广场.setSideLength(3.0)打印广场.getSideLength()#打印3.0到屏幕上
这两个代码片段做了完全相同的事情:定义一个Square类,该类的实例具有sideLength属性,可通过getter方法'getSideLength'访问,该方法将提供该属性的值,并可通过setter方法'setSideLength'访问,该方法将提供改变该属性值的方法。然后,创建一个'Square'类的实例,sideLength的初始值为10.0,并将该实例赋值给'Square'变量。然后在屏幕上打印sideLength变量的值,然后更新sideLength的值,最后将更新后的sideLength变量的值打印到屏幕上。
如果你对面向对象编程完全陌生,可能会使用'Square()' Java方法和初始化()你不知道Python方法的含义。这是因为它们是另一种类型的方法构造函数.
构造函数方法
构造函数方法用于实例化类,这是有效地创建对象的方法(请记住,类是对象的形式,而对象是类的实例)。它们通常以类命名(如在Java和c#中)或以关键字命名(如在Python和Ruby中)。构造函数方法的参数在出现时,通常是分配给该对象的部分或所有属性的初始值。您已经在上面的方框中看到了一个分配属性的构造函数方法的示例。让我们看一个构造函数的例子,它不接受任何参数,而是将对象属性初始化为一些默认值:
Python中的构造函数方法:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19类广场(对象):构造函数:def__init__(自我):自我.sideLength=5.0defgetSideLength(自我):返回自我.sideLengthdefsetSideLength(自我,sideLength):自我.sideLength=sideLength广场=广场()//调用的构造函数方法打印广场.getSideLength()#打印5.0到屏幕上广场.setSideLength(3.0)打印广场.getSideLength()#打印3.0到屏幕上
该程序的结构基本相同,只是构造函数方法现在不接受参数,并在为没有单独设置值的属性调用getter时返回默认值。正如您所看到的,属性的默认值并不意味着该属性对对象是静态的(这个Java按键工作将很快更深入地解释),只是您有点决定了“我想我将稍后定义这个属性,但我希望我的实例现在完全工作”。还要注意,不仅构造函数实现需要遵守一些特定于语言的约定,构造函数调用也需要遵守。在Java中,在调用带(或不带)形参的构造函数之前,通过添加键工作'new'来调用构造函数方法。在Python中,构造函数是通过向类传递参数来调用的(这实际上会触发初始化方法)。
实现方法
实现方法是最类似于标准过程函数的方法。顾名思义,这是一种实现对象功能的方法。这通常是通过操纵对象的属性并提供一些输出来实现的(或者以特定的方式改变一些内部属性而不提供任何直接输出,这是没有限制的)。让我们在Square对象中实现'outputArea'功能:
Python的实现方法:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21类广场(对象):构造函数:def__init__(自我):自我.sideLength=5.0defgetSideLength(自我):返回自我.sideLengthdefsetSideLength(自我,sideLength):自我.sideLength=sideLength实现的功能:defoutputArea():返回自我.getSideLength()*自我.getSideLength()广场=广场()广场.setSideLength(3.0)打印广场.outputArea()#打印9.0到屏幕上
那么,这里发生了什么?'outputArea()'方法的输出显示边长等于该正方形的sideLength属性的正方形的面积。对象内部方法的基本指导原则是在其数据内部操作以提供实际功能。任何具有更通用功能而不局限于单个类(或类层次结构)的方法通常都在模块中定义(可以将模块视为旨在提供可应用于许多不同类的功能的方法的集合)。如果Square的sideLength属性是4.0而不是3.0,那么输出将是16.0而不是9.0。该方法也不局限于对其属性执行一些封闭操作,我们可以使用对象的属性和一些任意参数来操作输出,像这样:
Python中outputArea方法的新实现:
1 2 3 4defoutputAreaTimesN(n):返回(自我.getSideLength()*自我.getSideLength())*n打印广场.outputAreaTimesN(2)#打印18.0到屏幕上
对象变量类型和作用域
在面向对象编程中,方法和变量具有不同的作用域。作用域意味着方法或变量可以直接被其他对象或类访问,也可以不直接被其他对象或类访问。系统可以访问没有实例的类。
类作用域:类变量和类方法与类关联。类(对象)的实例不需要使用这些变量或方法节点。类方法不能访问实例变量或方法,只能访问类变量和方法。
实例范围:实例变量和实例方法与特定对象关联。他们可以访问类变量和方法。
私人空间:私有变量和私有方法只能被包含它们的对象访问。因此,如果出现了问题,通常只有一个源文件可以查看。如果您的项目中有100万行代码,但类保持较小,这将大大减少错误跟踪的工作量。
公共空间:公共变量和公共方法可以在包含它们的对象之外访问,这在实际考虑中意味着“可能在任何地方”。如果某个公共字段出了问题,罪魁祸首可能在任何地方,因此为了跟踪错误,您可能需要查看大量代码
保护范围:受保护变量和受保护方法可由它们所在的类和继承的类(子类)访问。
封装:提供与对象交互的公共接口,同时将其他信息隐藏在对象内部的过程。封装意味着对象的内部表示通常隐藏在对象定义之外的视图中。的米ain way that encapsulation helps reduce rippling effects of change is by keeping as many of the implementation details private to the class. By limiting the interface only to those members needed to use the class, many changes can be made to the implementation without affecting any code that uses the class.
继承
不同种类的物体之间通常有一定的共同点。例如,优秀的员工和用户都具有相同的特征(姓名、年龄、级别)。然而,每一个都定义了使它们不同的附加特性:for工作人员
我们可能想要增加工资、专业领域等等。
面向对象编程允许类从其他类继承常用的状态和行为。在本例中,staff成员现在成为用户的超类。
1 2 3 4 5 |
|
这实际上是在说,“A工作人员
和a一样吗用户
,带有一些附加的方法和成员变量
继承的重要好处是代码重用和减少程序的复杂性。派生类(后代类)覆盖或扩展基类(祖先类)的功能。
在使用继承时应该小心,因为它可能被滥用。我们必须确定您对。的任何可能的更改或更新用户
类也是你想要的工作人员
类的每个其他子类用户
也有。
继承描述派生类如何继承基本用例的属性。子类继承其任何基类的属性,无论它们是数据属性还是方法。
下面是一个例子。父
是一个没有属性的简单类。孩子
派生的类是父
因此是一个子类。
1 2 3 4 5类父(对象):#父类通过类孩子(父):#子类通过
1 2 3 4 5 |
|
让我们在里面创建一个方法父
将在它的子类中重写:
1 2 3 4 5 6 |
|
现在让我们创建子类
1 2 3 4 5 6 |
|
虽然孩子
继承的父
的有趣的
方法时,它将被重写,因为孩子
定义了自己的有趣的
方法。重写方法的一个原因是向子类添加特殊而独特的功能。
如果你想调用你在子类中重写的基类方法,你可以调用一个未绑定的基类方法,显式地提供子类的实例:
1 2 |
|
模块
为了避免一些繁琐的工作,通常需要使用模块。一个模块是一个不同的东西,它可能有一个或24个密切相关的类。诀窍在于,模块是你要导入的东西,你需要这个导入对阅读、维护和扩展你的软件的人来说是完全合理的。
模块被导入进口
声明。
1 |
|
在Python中,每个以.py结尾的文件都是一个模块
1 2 3 4 5 6 7 8 |
|
我们将这个文件保存为basic.py
1 2 3 4 5 6 7 |
|
我们将这个文件保存为us more.py。
1 2 3 4 5 6 7 8 9 10 |
|
将输出
1 2 3 4 5 6 |
|
在上面的例子中,模块basic.py和more.py各自只包含一个类,但这是不必要的。把导入看作是在概念或块中组织代码的方法。每个导入中究竟有多少个类并不重要。重要的是您用导入语句描述的整体组织。
问题
考虑以下用Python实现的类:
class A(object): def __init__(self, A =None, b=None): self。自我。b = b
这个类可以用来创建列表,如下例所示:
#列表1,2,3 one_two_three = A(1, A(2, A(3))) one_two_three。#返回1
Jenny编写了下面的函数来创建一个包含1000个元素的列表,并返回最后163个元素的子列表。为了得到正确的答案,她必须用输入调用它n而且米:get_sublist_last_163 (n,米).
n而且米非负整数。的价值是什么n + m?
def get_sublist_last_163(N, M): #创建一个包含1000个元素的列表big_list = a (1000) i = 999 while (i>0): big_list = a (i, big_list) i = i - 1 #获取最后163个元素的子列表sublist_last_163 = big_list #调用"b" N次i = 0 while (i < N): sublist_last_163 = sublist_last_163。当(i < M): sublist_last_163 = sublist_last_163时,调用“a”M乘以i = 0。A I = I + 1返回sublist_last_163