《简明python教程》,python基础教程菜鸟教程
Yyds干货库存
许多开发人员的生计。面向对象编程是现代编程的支柱之一,所以Python能做到这一点并不奇怪。
但是,如果你在使用Python之前用任何其他语言做过面向对象编程,那么我几乎可以保证你做错了。
伙计们,这将是一个颠簸的旅程。请按照我的补发继续学习。
让我们创建一个新的类,并尝试一下。
级星际飞船(物体):
sound= vrrrrrrrrrrrrrrrrrrrrrrrrrrr
def __init__(self):
self.engines=False
self.engine _速度=0
self.shields=True
定义接合(自我):
self.engines=True
定义扭曲(自身,因子):
self .发动机_速度=2
self.engine_speed *=因子
@classmethod
定义声音(cls):
一旦它被声明,我们就可以从这个类创建一个新的实例或对象。所有成员函数和变量都可以使用点符号来访问。
企业号=星际飞船()
uss_enterprise.warp(4)
uss_enterprise.engage()
uss_enterprise.engines
真实的
uss_enterprise .引擎_速度
哇,你可能会说:我知道应该是“很简单”,但我觉得你只是想让我睡着。
你没发现惊喜吗?但是再看,不要看有什么,要看没有什么。
你看不出来吗?好,我们来分解一下。看你能否在我发现之前找到惊喜。
我们从类的声明开始:
Classship (object): Python可能被认为是比较真正面向对象的语言之一,因为它的设计原则是“一切都是对象”。所有其他类都继承自object。
从Python 3开始,我们也可以这样声明它:
Classship:就个人而言,考虑到Python的禅说“显式比隐式好”,我喜欢第一种方式。先说清楚,这两个方法在Python 3中的效果是一样的。别管这个了,继续走。
注意:如果希望代码在Python 2上运行,必须添加(object)。
我就跳到这里说方法了。
Def warp(self,factor):很明显,这是一个成员函数或者方法。在Python中,我们将self的第一个参数作为第一个参数传递给每个方法。之后,我们可以有任意数量的参数,就像使用其他函数一样。
我们实际上不必调用第一个参数self反正会管用的。但是作为一种风格,我们总是在那里用这个名字。没有正当的理由违反这条规则。
“但是,但是.你只是自己违反了规则!看下一个功能?”
@classmethod
DEF _ SOUND (CLS):你可能记得在面向对象编程中,类方法是在一个类的所有实例(对象)之间共享的方法。类从不接触成员变量或常规方法。
如果你没有注意到,我们总是访问成员变量:self。在类中通过点运算符。所以,为了更清楚,我们不能在类方法中这样做。我们称第一个参数为cls。事实上,当调用一个类方法时,Python将类传递给这个参数,而不是传递对象。
对于类方法,我们还必须将decorator @classmethod直接放在函数声明之上。这告诉Python您正在创建一个类方法,并且您不仅创建了参数self的名称。
以上方法可以这样调用。
uss_enterprise=Starship() #从Starship类创建我们的对象
#请注意,我们没有向“self”传递任何内容。Python隐含地做到了这一点。
uss_enterprise.warp(4)
#我们可以在对象上调用类函数,或者直接在类上调用。
uss_enterprise.make_sound()
Starship.make_sound()的最后两行将以完全相同的方式打印出“vrrrrrrrrrrrrrrrrrrr”。(请注意,我在前面的函数中提到了cls.sound。)
与类静态方法和许多其他语言不同,Python区分静态方法和类方法。从技术上讲,它们的工作方式是一样的,因为它们在对象的所有实例之间共享。只有一个关键的区别。
静态方法不访问任何类成员;它甚至不在乎它是一个类的一部分!因为它不需要访问类的任何其他部分,所以它不需要cls参数。
让我们比较一下类方法和静态方法:
@classmethod
定义声音(cls):
打印(cls.sound)
@静态方法
def beep():
Print(beep boop beep )因为beep()不需要访问这个类,所以我们可以通过使用@staticmethod decorator使它成为一个静态方法。Python不会隐式地将类传递给第一个参数,这与它的class方法(make_sound())不同。
尽管有这种不同,但您以相同的方式调用两者,并得到相同的结果。
企业号=星际飞船()
uss_enterprise.make_sound()
vrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
Starship.make_sound()
vrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
uss_enterprise.beep()
哔哔哔
Starship.beep()
哔哔boop哔初始化函数和构造函数每个Python类都需要有且只有一个__init__(self)函数。这被称为初始化函数。
def __init__(self):
self.engine _转速=1
self.shields=True
Self.engines=False如果你真的不需要初始化函数,技术上可以跳过定义,但这是一种不好的形式。至少,定义一个空的.
def __init__(self):
虽然我们倾向于像C和Java中的构造函数一样使用Pass,但它不是__init__(self)构造函数!初始化器负责初始化实例变量,我们将在后面详细讨论。
我们很少需要定义自己的构造函数。如果你真的知道自己在做什么,可以重新定义__new__(cls)函数。
def __new__(cls):
返回对象。__new__(cls)对了,如果你在找析构函数,那就是__del__(self)函数。
变量在Python中,我们的类可以有实例变量,实例变量是我们的对象(实例)所独有的,还有属于类的类变量(也称为静态变量),类变量是所有实例共享的。
我有一个坦白:在Python开发的最初几年,我做了一件绝对错误的事情!因为它来自其他面向对象的语言,我实际上认为我应该这样做:
级星际飞船(物体):
引擎=假
发动机速度=0
shields=True
def __init__(self):
self.engines=False
self.engine _速度=0
self.shields=True
定义接合(自我):
self.engines=True
定义扭曲(自身,因子):
self .发动机_速度=2
Self.engine_speed *=因子代码有效,那么这个代码有什么问题?再看一遍,看看你能不能搞清楚发生了什么。
也许这样会更明显。
企业号=星际飞船()
uss_enterprise.warp(4)
打印(uss_enterprise.engine_speed)
八
打印(Starship.engine_speed)
0你找到了吗?
类是在所有函数之外声明的,通常是在顶部。另一方面,实例变量在__init__(self)函数中声明:例如,self.engine_speed=0。
因此,在我们的示例中,我们声明了一组同名的类变量和一组同名的实例变量。当访问对象上的变量时,实例变量将覆盖类变量,使其行为符合我们的预期。但是,通过打印Starship.engine_speed可以看到,我们在类中有一个单独的类变量,只是占用了空间。
有人猜对了吗?
顺便说一下,你可以在任何实例方法中首次声明实例变量,而不是在初始化函数中。然而:不要这样。习惯上总是在初始化函数中声明所有的实例变量,以防止出现异常情况,比如访问尚不存在的变量。
作用域:私有和公共如果你来自另一种面向对象的语言,比如Java和C,那么你可能也习惯于考虑作用域(Private,protected,Public)及其传统假设:变量应该是私有的,而函数应该是私有的(通常是公共的)。收购者和设定者统治一切!
C面向对象编程我也很熟练。不得不说,我觉得Python处理范围问题的方法,远远优于典型的面向对象的范围规则。一旦你掌握了如何用Python设计类,这些原则就可以应用到其他语言的标准实践中.我坚信这是一件好事。
你准备好了吗?你的变量实际上不需要私有。
是的,我刚听到后面那个Java呆子在提问。“但是.但是.我将如何防止开发人员篡改任何对象的实例变量?”
通常,这种担心是基于三个有缺陷的假设。让我们先设置这些:
几乎可以肯定,使用你的类的开发者没有直接修改成员变量的习惯,就像他们习惯了在烤面包机里插叉子一样。如果他们真的往烤面包机里插叉子,我们都知道,后果就是他们是傻逼,不是你。“如果你知道为什么不应该用金属物体把卡住的吐司从烤面包机里拿出来,那么你就可以这样做。”换句话说,使用您的类的开发人员可能比您更清楚他们是否应该修改实例变量。
现在,有了这个,我们接近了Python中的一个重要前提:没有实际的“私有”范围。我们不能只在变量前面加一个花哨的小关键字就把它私有了。
我们能做的就是在名字前面加一个下划线,像这样:self。_发动机。
这条下划线并不神奇。对于任何使用你的类的人来说,这只是一个警告标签:“建议你不要轻易修改。我正在用它做一些特别的事情。”
现在,在您坚持使用_ all实例变量名的开头之前,请考虑这个变量实际上是什么,以及如何使用它。直接修改真的会出问题吗?在我们的示例类中,就像现在写的那样,没有。这实际上是完全可以接受的:
uss_enterprise.engine_speed=6
Uss_enterprise.engage()还有,注意到什么?我们没有编写getter或setter!在任何语言中,如果getter或setter在功能上等同于直接修改变量,那么它们绝对是一种浪费。这也是Python是如此干净的语言的原因之一。
对于不打算在类外使用的方法,也可以使用这种命名约定。
注意:在你离开和避免私有你受保护的Java和C代码之前,请知道作用域有一个时间和地点。强调是Python开发者之间的社交契约,大多数语言都没有这样的契约。因此,如果您使用的是带作用域的语言,请在Python中使用private或protected来给任何变量加下划线。
现在特殊了,在极少数情况下,你可能有一个实例变量,绝对的,明确的,永远,永远不要直接在类外修改。在这种情况下,可以在变量名前加两个下划线(_ _),而不是一个。
这实际上并没有使它成为私有的。相反,它执行一个名为名称修饰的操作:它更改变量的名称,在它前面添加一个下划线和类名。
在这种情况下,星舰类,如果我们想把self.shields改成self。__shields,名字会改成self。_星际飞船_ _护盾。
因此,如果您知道这个名称修改是如何工作的,您仍然可以访问它。
企业号=星际飞船()
企业号。_星际飞船_ _护盾
have需要注意的是,如果要这样做,也不能有多个尾随下划线。(__foo和__foo_会被销毁,但__foo__不会)。然而,PEP 8通常不鼓励使用尾随下划线,所以这有点争议。
对了,双下划线(_ _)名称修饰的目的和私有作用域无关;这一切都是为了防止与某些技术场景的名称冲突。事实上,你可能会从Python忍者那里得到一些_ _严重的问题,所以要小心使用。
属性我之前说过,getter和setter通常是没有意义的。然而,有时他们有一个目的。在Python中,我们可以这样使用属性,还可以使用一些非常漂亮的招数!
只需在方法前面加上前缀,就可以定义属性@property。
我最喜欢的属性技巧是让一个方法看起来像一个实例变量。
级星际飞船(物体):
def __init__(self):
self.engines=True
self.engine _速度=0
self.shields=True
@属性
定义引擎_应变(自身):
如果不是自带发动机:
返回0
elif自我保护:
#想象护盾使引擎压力加倍
返回self.engine_speed * 2
#否则,发动机应变与速度相同
Return.engine _ speed当我们使用这个类的时候,可以把engine_strain当做对象的一个实例变量。
企业号=星际飞船()
uss_enterprise.engine_strain
0很美不是吗?
幸运的是,我们不能用同样的方法修改engine_strain。
USS _ enterprise . engine _ strain=10
回溯(最近一次呼叫):
模块中文件 stdin 的第1行
错误:在这种情况下不能设置属性,它确实有意义,但在其他时候可能不是你想要的。只是为了好玩,让我们也定义一个setter为了我们的财产;至少有一个输出比那个可怕的错误要好。
@engine_strain.setter
def engine_strain(自身,值):
print(‘我把她所有的都给她了,船长!’)我们在方法前添加decorator @ NAME _ OF _ property . setter。我们还必须接受一个单值参数(当然是在self之后),除此之外什么都不接受。您会注意到,在这种情况下,我们实际上没有对value参数做任何事情。
USS _ enterprise . engine _ strain=10
我把她所有的都给她了,队长!这样好多了。
正如我之前提到的,我们可以将它们用作实例变量的getter和setter。这里有一个简单的例子:
级星际飞船:
def __init__(self):
#剪断
自我。_captain=让卢克皮卡德
@属性
def队长(自己):
回归自我。_船长
@captain.setter
def队长(自身,值):
打印(‘你认为这是什么,‘价值’,飞马号?“回去工作!”)我们只是强调这些函数关注的变量,以向他人表明我们打算自己管理这些变量。Getter相当繁琐和明显,只需要提供预期的行为。setter的有趣之处在于它可以响应任何值的变化!
企业号=星际飞船()
企业号,舰长
让卢克皮卡德的
企业号舰长=卫斯理
你认为这是什么,韦斯利,美国海军飞马号?回去工作!解释:如果你想为一些黑客测试创建类属性。网上有很多解决方案。如果需要这个,就去研究吧,这里不做过多阐述!
如果我没有指出来,一些Python爱好者会关注我。还有一种不使用decorators创建属性的方法。所以,为了记录在案,这也是可行的。
级星际飞船:
def __init__(self):
#剪断
自我。_captain=让卢克皮卡德
def get_captain(自己):
回归自我。_船长
def set_captain(self,value):
打印(‘你认为这是什么,‘价值’,飞马号?“回去工作!”)
Captain=property (get _ captain,set _ captain)(是的,最后一行存在于任何函数之外。)
最后,传承,我们回到第一线再看一遍。
级星舰(物体):还记得(物体)为什么会在那里吗?因为它继承了Python的object类。啊,遗产!那是它的归属。
USSDiscovery级(星际飞船):
def __init__(self):
超级()。__init__()
self.spore_drive=True
自我。_captain=Gabriel Lorca 这里唯一真正神秘的是那个超级()。__init__()行。简而言之,super()指的是我们继承的类(这里是Starship)并调用它的初始化器。我们需要调用它,所以USSDiscovery拥有Starship的所有实例变量。
当然,我们可以定义一个新的实例变量(self.spore_drive)并重新定义继承变量(self。_船长)。
我们可以称之为初始化飞船。__init__()使用,但是如果我们想改变我们继承的东西,我们也必须改变那一行。这个超级()。__init__()方法最后只是更干净,更容易维护。
注:对了,如果你用的是Python 2,那行代码有点难看:super (USS Discovery,self)。_ _ init _ _()。
在你问之前:是的,你可以用C类(A,B):它实际上比大多数语言都好用!无论如何,你可以指望一些令人头痛的事情,尤其是在使用super()的时候。
封装正如你所看到的,Python类与其他语言略有不同,但是一旦你习惯了它们,它们实际上会更容易使用。
但是,如果你使用C或Java等重类语言进行编码,并且假设你需要Python中的类,那么我来告诉你。你真的完全不需要使用类!
在Python中,类和对象只有一个目的:数据封装。如果您需要将数据和操作数据的函数放在一个方便的单元中,那么类是您的最佳选择。否则不要用!完全由函数组成的模块也可以。
总结我们来回顾一下:
__init__(self)函数是一个初始化函数,是我们初始化所有变量的地方。方法(成员函数)必须将self作为第一个参数。类必须将cls作为它们的第一个参数,decorator @classmethod位于函数定义的正上方。他们可以访问类变量,但不能访问实例变量。静态方法类似于类方法,只是它们不是cls的第一个参数,并且它们前面有一个decorator @staticmethod。他们不能访问任何类或实例变量或函数。他们甚至不知道自己是班上的一员。实例变量(成员变量)应该首先在__init__(self)中声明。与大多数其他面向对象的语言不同,我们不在构造函数之外声明它们。类或静态变量在任何函数之外声明,并在该类的所有实例之间共享。Python中没有私有成员!在成员变量或方法名前面加一个下划线(_),告诉开发人员不要误用它。如果在成员变量或方法的名称前加两个下划线(_ _),Python会用名称篡改来改变它的名称。这更多的是为了防止名字冲突,而不是隐藏事情。您可以将任何方法转换成属性(它看起来像一个成员变量),方法是将decorator放在它的声明上面的行中。@property这也可以用来创建getter。通过将decorator @foo.setter放在函数foo的顶部,可以为一个属性(例如foo)设置一个setter。一个类(如Dog)可以继承另一个类(如animal): classdog (animal):这样做的时候也要用super()。__init__()调用基类的初始化函数来启动你的初始化函数。多重遗传是可以的,但是可能会给你带来噩梦。小心处理!原创作品来自程,
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。