so I'm novice to Python and faced this self question. I've researched a lot of info but still don't grasp the concept. I have a simple problem from Zelle book - write a class MSDie for multisided dice (typical dice has 6 sides). Each MSDie object will know:1)how many sides it gets, 2)its current value. So the book proposes the following code:
所以我是Python的新手,面对这个自我问题。我已经研究了很多信息,但仍然没有掌握这个概念。我从Zelle的书中得到一个简单的问题 - 为多边骰子写一个MSDie类(典型的骰子有6个方面)。每个MSDie对象都知道:1)它获得了多少边,2)它的当前值。所以这本书提出了以下代码:
class MSDie:
def __init__(self,sides):
self.sides=sides
self.value=1
def roll(self):
self.value=randrange(1,self.sides+1,1)
def getValue(self):
return self.value
And i'm wondering why can't the code be the same only without self?
而且我想知道为什么代码只有在没有自我的情况下才能相同?
class MSDie:
def __init__(sides):
sides=sides
value=1
def roll():
value=randrange(1,sides+1,1)
def getValue(self):
return value
Some people say self is needed to refer to the instance object we've created. But I should say that we use object name which refers to the object we've created. Why can't I create d1=MSDie(12)
object with my code? Python will know that d1
is an MSDIe class object and that calss has those declared instance variables and methods. So when I want to setValue
of my d1
I just invoke my method (without self
) and it works. Please explain me on my example why i'm wrong.
有人说需要self来引用我们创建的实例对象。但我应该说我们使用的对象名称是指我们创建的对象。为什么我不能用我的代码创建d1 = MSDie(12)对象? Python将知道d1是一个MSDIe类对象,而calss具有那些声明的实例变量和方法。因此,当我想设置我的d1的值时,我只是调用我的方法(没有自己)并且它有效。请解释我的例子为什么我错了。
5 个解决方案
#1
You are a Person; there are many instances of the Person class walking around, but there is only one of you.
你是一个人;有很多Person类走动的例子,但只有你们中的一个。
If you want to know your eye color, you look at yourself in the mirror. If you want to know how tall you are, you measure yourself. You do not measure Person, because Person is not you.
如果你想知道你的眼睛颜色,你会在镜子里看自己。如果你想知道自己有多高,你就要衡量自己。你不衡量人,因为人不是你。
In the same way, your instance d1
needs to know about itself. MSDie does not have a specific value
; d1
must look at its own properties, and those properties are referenced via self
.
同样,您的实例d1需要了解自己。 MSDie没有特定值; d1必须查看自己的属性,并通过self引用这些属性。
If someone else wants to measure you, and if you make your personal information available, they don't have to reference self
. They can do it like this:
如果其他人想要衡量你,如果你提供个人信息,他们就不必参考自己。他们可以这样做:
Anton.height
or
Anton.weight
That works okay for very simple properties, but becomes more difficult when the task is more complex. For example, consider the act of sleeping. You have to:
这适用于非常简单的属性,但当任务更复杂时变得更加困难。例如,考虑睡觉的行为。你必须:
- lay down
- close your eyes
- slow your breathing
- activate REM
- activate delta waves
闭上你的眼睛
减慢你的呼吸
激活三角波
These tasks have a nice wrapper around them, called sleep()
. When you tell yourself to sleep()
, your body takes over from there:
这些任务有一个很好的包装器,称为sleep()。当你告诉自己睡觉时(),你的身体从那里接管:
def sleep(self):
self.position = 'horizontal'
self.eyelid = 'closed'
self.breathing_rate = 30
self.REM = True
self.brainwaves.activate('Delta')
If you had to set all of these properties and functions on yourself, you would have had a very rough childhood; you would have had to learn what all of those properties mean before you could use them. Instead, the Person class has the functionality built in, and you just have to call sleep()
on your particular instance.
如果你必须自己设置所有这些属性和功能,那么你的童年就会非常艰难;在使用它们之前,您必须了解所有这些属性的含义。相反,Person类具有内置的功能,您只需要在特定实例上调用sleep()。
What if the Person class set these properties on the class itself, rather than on self
? If that were possible, every instance of Person would lie down, close eyes, slow breathing, etc. at the same time. By referencing self
, you can take advantage of the built-in functionality without having to make the details of the functionality part of the public API (ie. something that must be learned externally).
如果Person类在类本身而不是self上设置这些属性怎么办?如果可能的话,人的每一个例子都会同时躺下,闭上眼睛,缓慢呼吸等。通过引用self,您可以利用内置功能,而无需将功能的详细信息部分公开API(即必须在外部学习的内容)。
#2
The way Python implements instance methods, every method receives a reference to the object that invoked the method as its first argument. When you write something like
Python实现实例方法的方式,每个方法都接收对调用该方法作为其第一个参数的对象的引用。当你写的东西像
d1 = MSDie(12)
d1.roll()
Python first checks what the type of d1
is so that it knows what method to call. Seeing that type(d1)
is MSDie
, it checks to see if MSDie
has a method named roll
, and finds that it does. It calls that method, passing d1
as the first argument, that is, d1.roll()
is equivalent to
Python首先检查d1的类型是什么,以便它知道要调用的方法。看到该类型(d1)是MSDie,它会检查MSDie是否有一个名为roll的方法,并发现它确实存在。它调用该方法,将d1作为第一个参数传递,即d1.roll()等效于
MSDie.roll(d1)
Inside of roll()
, the reference to d1
is accessed via the self
parameter. (The name of the parameter doesn't really matter, but self
is the convention that is nearly universally used.)
在roll()内部,通过self参数访问对d1的引用。 (参数的名称并不重要,但self是几乎普遍使用的约定。)
If you called, instead, d2.roll()
, it would be converted to MSDie.roll(d2)
, and that call would see self
as a reference to d2
.
如果你调用d2.roll(),它将被转换为MSDie.roll(d2),并且该调用将self视为对d2的引用。
If you defined roll
as
如果您将roll定义为
def roll():
value=randrange(1,sides+1,1)
Python would have to turn d1.roll()
into MSDie.roll()
, and the method wouldn't know which dice object to work with. value
is simply a local variable to the function, not related to any particular object.
Python必须将d1.roll()转换为MSDie.roll(),并且该方法不知道要使用哪个骰子对象。 value只是函数的局部变量,与任何特定对象无关。
#3
To a certain extent, this is how Python demands you to write things. Remember: A class is a blueprint, from which objects (i.e. instances of that class) are built.
在某种程度上,这就是Python要求你写东西的方式。记住:类是一个蓝图,从中构建对象(即该类的实例)。
For example cars (class) have wheels. Hence my car (an actual car, i.e. an object) has wheels. When my car was built, at some point the wheels were attached to my car. The instructions perhaps said "take wheels and put them onto the car currently being constructed". It is conceptually important to note that it would not suffice to just take the wheels from the storage and dump them somewhere in the vicinity of the car. Or onto the blueprint. However, it might say "Grab some screws and put them onto the table for later use". These would then not be delivered with the final car (unless built in at a later stage).
例如汽车(类)有*。因此我的汽车(一辆真正的汽车,即一个物体)有*。当我的汽车建成时,车轮已经安装在我的车上。这些说明可能会说“把*放到目前正在建造的汽车上”。从概念上讲,重要的是要注意仅从车库中取出车轮并将其倾倒在汽车附近的某处是不够的。或者到蓝图上。但是,它可能会说“抓一些螺丝并将它们放在桌子上供以后使用”。然后这些将不会与最终的汽车一起交付(除非在后期建造)。
In Python the thing is the same. __init__
describes what to do when an actual object is being built. It needs to distinguish between "make sides
a property of my dice" and "store a number in sides
so that I can use it later on in the construction but forget about it afterwards".
在Python中,事情是一样的。 __init__描述了构建实际对象时要执行的操作。它需要区分“使我的骰子成为一个属性”和“在侧面存储一个数字,以便我可以在以后使用它,但后来忘记它”。
In contrast to languages, where class interfaces are declared (e.g. C++, Java), Python cannot know whether a dice has sides
or not.
与声明类接口的语言(例如C ++,Java)不同,Python无法知道骰子是否有边。
In all other cases, one might think it a smart idea if python would actually check whether MSDie has an attribute names sides
and use that. However, it might lead to surprising results in more complex classes, when you wish to create a local variable but actually change your object. To prevent such errors, Python demands you to be explicit when addressing attributes.
在所有其他情况下,如果python实际上会检查MSDie是否具有属性名称side并使用它,那么可能会认为这是一个明智的想法。但是,当您希望创建局部变量但实际更改对象时,它可能会导致更复杂的类中出现令人惊讶的结果。为防止此类错误,Python要求您在处理属性时要明确。
#4
The short answer is because that is how it was designed. Accept it and move on.
简短的回答是因为它是如何设计的。接受它并继续前进。
However, there is some usefulness to the design: namespaces and readability.
但是,设计有一些用处:命名空间和可读性。
Consider the following:
考虑以下:
foo = 'some value'
class Bar():
def __init__(self):
self.foo = foo
Notice that there are two objects named foo
. One is globally defined in the module (as foo
) and the other is defined at an attribute of the class (as self.foo
). If we didn't have self
, this wouldn't be possible. Self gives us a different namespace, so that we can differentiate between an object that is assigned to a given class instance, and another one that is not with no concerns about name *es.
请注意,有两个名为foo的对象。一个是在模块中全局定义的(如foo),另一个是在类的属性中定义的(作为self.foo)。如果我们没有自己,这是不可能的。 Self为我们提供了一个不同的命名空间,以便我们可以区分分配给给定类实例的对象和另一个不关心名称冲突的对象。
The same applies when working with multiple instances of the same class. For example, when you need to compare two instances (using __eq__
and friends):
处理同一个类的多个实例时也是如此。例如,当您需要比较两个实例时(使用__eq__和friends):
class Foo():
def __eq__(self, other)
return self.bar == other.bar
Without self, it would not be so clear which bar
is which. While not terribly important in an "equal" comparison, in a "greater than" or "less than" comparison, the order matters. And by using self, it makes it clear when you write the code, but also clear when you come back to it months/years later and have to read and understand what it is doing.
没有自我,就不清楚哪个是哪个吧。虽然在“平等”比较中不是非常重要,但在“大于”或“小于”比较中,顺序很重要。通过使用self,它可以在您编写代码时清楚地表明,但是当您在几个月/几年后再次使用它时也会清楚,并且必须阅读并理解它正在做什么。
Consider a very large class with many attributes which is part of a large module with many objects. Without self, it would not always be clear which objects are class attributes and which are not without reading through the entire module. So, even if the use of self was optional (as you propose) it would still be good practice to always use it to make sure your code is clear when you (or more importantly someone else) comes back to it later. That is just good programming practice. I'm glad the language forces it. In fact, one of Python's strengths is its readability. Self adds to that readability. Embrace it.
考虑一个具有许多属性的非常大的类,它是具有许多对象的大模块的一部分。没有self,就不会总是清楚哪些对象是类属性,哪些对象不是没有读取整个模块。因此,即使自我的使用是可选的(如你所建议的那样),当你(或更重要的是其他人)稍后再回到它时,总是使用它来确保你的代码是清晰的仍然是一个好习惯。这只是一个很好的编程实践。我很高兴语言强迫它。实际上,Python的优势之一是它的可读性。自我增加了可读性。接受它。
#5
It's important to understand difference between class and object (class instance).
理解类和对象(类实例)之间的区别很重要。
Class is consisted from method declarations together and template for objects (for example class has 2 methods and 1 integer attribute). It's identified by class name only (MSDie
).
类由方法声明和对象模板组成(例如,类有2个方法和1个整数属性)。它仅由类名(MSDie)标识。
Object (class instance) is concrete evaluation of it's class, that is it has concrete values for class attributes. It is identified by class name and evaluation of it's attributes (MSDie(sides=3, value=1)
)
Object(类实例)是对它的类的具体评估,即它具有类属性的具体值。它通过类名和它的属性评估来识别(MSDie(sides = 3,value = 1))
When Python code is executed, program code (methods and functions, so "classes") are loaded into code memory. During program execution, objects are created by executed code and stored in another part of memory - data memory. There are stored values of each attribute together with identification of class for class instance, but nothing from class code (methods) is copied there. Instance can be identified by address (pointer) to data memory box where are stored it's data. It's good to mention, that data and code memory parts are strictly separated. Note there may be thousands instances of same class (so thousands instance boxes in data memory), but code for that class is present only once - in code memory.
当执行Python代码时,程序代码(方法和函数,所以“类”)被加载到代码存储器中。在程序执行期间,对象由执行的代码创建并存储在内存的另一部分 - 数据存储器中。每个属性的存储值与类实例的类的标识一起存在,但是在那里没有复制类代码(方法)。可以通过数据存储器盒的地址(指针)来识别实例,其中存储数据。值得一提的是,数据和代码存储器部分是严格分开的。注意,可能有数千个相同类的实例(数据存储器中有数千个实例框),但该类的代码只出现一次 - 在代码存储器中。
When instance method is called in Python:
在Python中调用instance方法时:
d1.setValue(3)
Name of instance (d1) is converted to pointer into d1's data memory box. But that box doesn't contain code for method MSDie.setValue(x)
. There is only identification of class, which can be used to find code for that method in code memory. But when method code is called from code memory, it has no idea what instance it is supposed to work with. This information needs to be passed somehow there.
实例名称(d1)被转换为指向d1数据存储器的指针。但该框不包含方法MSDie.setValue(x)的代码。只有类的标识,可用于在代码存储器中查找该方法的代码。但是当从代码存储器调用方法代码时,它不知道它应该使用什么实例。这些信息需要以某种方式传递到那里。
Most languages with classes handles this passing of instance to class method during code compilation into byte code and it's not visible in language syntax at all. It just may be "confusing" where this
(Java analogy to Python's self
) comes from as it's not defined anywhere.
大多数带有类的语言在代码编译到字节代码期间处理将实例传递给类方法,并且在语言语法中根本不可见。它可能是“令人困惑”的地方(Java类比Python的自我)来自它,因为它没有在任何地方定义。
Python kept this instance parameter in class methods as part of it's syntax. So it's really not big deal, it works same way in other object oriented languages, they just hide it behind compiler. On the other side, it may be a bit confusing, that class method is defined with 2 parameters (MSDie.setValue(self, x)
), but when it's called, only 1 parameter is passed (d1.setValue(3)
).
Python将此实例参数保留在类方法中作为其语法的一部分。所以它真的不是什么大问题,它在其他面向对象语言中的工作方式相同,它们只是隐藏在编译器之后。另一方面,它可能有点令人困惑,类方法是用2个参数定义的(MSDie.setValue(self,x)),但是当它被调用时,只传递1个参数(d1.setValue(3))。
So to answer your question:
所以回答你的问题:
When class method is defined like this:
当类方法定义如下:
def MSDie:
...
def roll(self):
self.value=randrange(1,self.sides+1,1)
You need to call it this way (without passing value for self
)
你需要这样调用它(没有为自己传递值)
d1.roll()
Python will find what class instance is saved in d1 variable and then it calls it's method like this
Python将在d1变量中找到保存的类实例,然后调用它的方法
MSDie.roll(d1)
But this conversion is done on background. And that is how d1 instance is available as self
inside of method roll()
.
但是这种转换是在后台完成的。这就是方法roll()中d1实例作为self的可用方式。
You can't omit self
parameter in definition of class method simply because Python will not be able to find method with correct number of parameters or values for parameters inside of method will be wrong (1st parameter in method would get 2nd parameter from call, etc). Additionally code inside of method will not get correct instance to work with.
你不能在类方法的定义中省略self参数只是因为Python无法找到具有正确参数数量的方法或者方法内部参数的值将是错误的(方法中的第一个参数将从调用获得第二个参数,等等)。此外,方法内部的代码将无法获得正确的实例。
Also you need to use self
inside of class method to access all object attributes properly (it's needed to find memory box where these values are stored).
此外,您需要在类方法中使用self来正确访问所有对象属性(需要查找存储这些值的内存框)。
#1
You are a Person; there are many instances of the Person class walking around, but there is only one of you.
你是一个人;有很多Person类走动的例子,但只有你们中的一个。
If you want to know your eye color, you look at yourself in the mirror. If you want to know how tall you are, you measure yourself. You do not measure Person, because Person is not you.
如果你想知道你的眼睛颜色,你会在镜子里看自己。如果你想知道自己有多高,你就要衡量自己。你不衡量人,因为人不是你。
In the same way, your instance d1
needs to know about itself. MSDie does not have a specific value
; d1
must look at its own properties, and those properties are referenced via self
.
同样,您的实例d1需要了解自己。 MSDie没有特定值; d1必须查看自己的属性,并通过self引用这些属性。
If someone else wants to measure you, and if you make your personal information available, they don't have to reference self
. They can do it like this:
如果其他人想要衡量你,如果你提供个人信息,他们就不必参考自己。他们可以这样做:
Anton.height
or
Anton.weight
That works okay for very simple properties, but becomes more difficult when the task is more complex. For example, consider the act of sleeping. You have to:
这适用于非常简单的属性,但当任务更复杂时变得更加困难。例如,考虑睡觉的行为。你必须:
- lay down
- close your eyes
- slow your breathing
- activate REM
- activate delta waves
闭上你的眼睛
减慢你的呼吸
激活三角波
These tasks have a nice wrapper around them, called sleep()
. When you tell yourself to sleep()
, your body takes over from there:
这些任务有一个很好的包装器,称为sleep()。当你告诉自己睡觉时(),你的身体从那里接管:
def sleep(self):
self.position = 'horizontal'
self.eyelid = 'closed'
self.breathing_rate = 30
self.REM = True
self.brainwaves.activate('Delta')
If you had to set all of these properties and functions on yourself, you would have had a very rough childhood; you would have had to learn what all of those properties mean before you could use them. Instead, the Person class has the functionality built in, and you just have to call sleep()
on your particular instance.
如果你必须自己设置所有这些属性和功能,那么你的童年就会非常艰难;在使用它们之前,您必须了解所有这些属性的含义。相反,Person类具有内置的功能,您只需要在特定实例上调用sleep()。
What if the Person class set these properties on the class itself, rather than on self
? If that were possible, every instance of Person would lie down, close eyes, slow breathing, etc. at the same time. By referencing self
, you can take advantage of the built-in functionality without having to make the details of the functionality part of the public API (ie. something that must be learned externally).
如果Person类在类本身而不是self上设置这些属性怎么办?如果可能的话,人的每一个例子都会同时躺下,闭上眼睛,缓慢呼吸等。通过引用self,您可以利用内置功能,而无需将功能的详细信息部分公开API(即必须在外部学习的内容)。
#2
The way Python implements instance methods, every method receives a reference to the object that invoked the method as its first argument. When you write something like
Python实现实例方法的方式,每个方法都接收对调用该方法作为其第一个参数的对象的引用。当你写的东西像
d1 = MSDie(12)
d1.roll()
Python first checks what the type of d1
is so that it knows what method to call. Seeing that type(d1)
is MSDie
, it checks to see if MSDie
has a method named roll
, and finds that it does. It calls that method, passing d1
as the first argument, that is, d1.roll()
is equivalent to
Python首先检查d1的类型是什么,以便它知道要调用的方法。看到该类型(d1)是MSDie,它会检查MSDie是否有一个名为roll的方法,并发现它确实存在。它调用该方法,将d1作为第一个参数传递,即d1.roll()等效于
MSDie.roll(d1)
Inside of roll()
, the reference to d1
is accessed via the self
parameter. (The name of the parameter doesn't really matter, but self
is the convention that is nearly universally used.)
在roll()内部,通过self参数访问对d1的引用。 (参数的名称并不重要,但self是几乎普遍使用的约定。)
If you called, instead, d2.roll()
, it would be converted to MSDie.roll(d2)
, and that call would see self
as a reference to d2
.
如果你调用d2.roll(),它将被转换为MSDie.roll(d2),并且该调用将self视为对d2的引用。
If you defined roll
as
如果您将roll定义为
def roll():
value=randrange(1,sides+1,1)
Python would have to turn d1.roll()
into MSDie.roll()
, and the method wouldn't know which dice object to work with. value
is simply a local variable to the function, not related to any particular object.
Python必须将d1.roll()转换为MSDie.roll(),并且该方法不知道要使用哪个骰子对象。 value只是函数的局部变量,与任何特定对象无关。
#3
To a certain extent, this is how Python demands you to write things. Remember: A class is a blueprint, from which objects (i.e. instances of that class) are built.
在某种程度上,这就是Python要求你写东西的方式。记住:类是一个蓝图,从中构建对象(即该类的实例)。
For example cars (class) have wheels. Hence my car (an actual car, i.e. an object) has wheels. When my car was built, at some point the wheels were attached to my car. The instructions perhaps said "take wheels and put them onto the car currently being constructed". It is conceptually important to note that it would not suffice to just take the wheels from the storage and dump them somewhere in the vicinity of the car. Or onto the blueprint. However, it might say "Grab some screws and put them onto the table for later use". These would then not be delivered with the final car (unless built in at a later stage).
例如汽车(类)有*。因此我的汽车(一辆真正的汽车,即一个物体)有*。当我的汽车建成时,车轮已经安装在我的车上。这些说明可能会说“把*放到目前正在建造的汽车上”。从概念上讲,重要的是要注意仅从车库中取出车轮并将其倾倒在汽车附近的某处是不够的。或者到蓝图上。但是,它可能会说“抓一些螺丝并将它们放在桌子上供以后使用”。然后这些将不会与最终的汽车一起交付(除非在后期建造)。
In Python the thing is the same. __init__
describes what to do when an actual object is being built. It needs to distinguish between "make sides
a property of my dice" and "store a number in sides
so that I can use it later on in the construction but forget about it afterwards".
在Python中,事情是一样的。 __init__描述了构建实际对象时要执行的操作。它需要区分“使我的骰子成为一个属性”和“在侧面存储一个数字,以便我可以在以后使用它,但后来忘记它”。
In contrast to languages, where class interfaces are declared (e.g. C++, Java), Python cannot know whether a dice has sides
or not.
与声明类接口的语言(例如C ++,Java)不同,Python无法知道骰子是否有边。
In all other cases, one might think it a smart idea if python would actually check whether MSDie has an attribute names sides
and use that. However, it might lead to surprising results in more complex classes, when you wish to create a local variable but actually change your object. To prevent such errors, Python demands you to be explicit when addressing attributes.
在所有其他情况下,如果python实际上会检查MSDie是否具有属性名称side并使用它,那么可能会认为这是一个明智的想法。但是,当您希望创建局部变量但实际更改对象时,它可能会导致更复杂的类中出现令人惊讶的结果。为防止此类错误,Python要求您在处理属性时要明确。
#4
The short answer is because that is how it was designed. Accept it and move on.
简短的回答是因为它是如何设计的。接受它并继续前进。
However, there is some usefulness to the design: namespaces and readability.
但是,设计有一些用处:命名空间和可读性。
Consider the following:
考虑以下:
foo = 'some value'
class Bar():
def __init__(self):
self.foo = foo
Notice that there are two objects named foo
. One is globally defined in the module (as foo
) and the other is defined at an attribute of the class (as self.foo
). If we didn't have self
, this wouldn't be possible. Self gives us a different namespace, so that we can differentiate between an object that is assigned to a given class instance, and another one that is not with no concerns about name *es.
请注意,有两个名为foo的对象。一个是在模块中全局定义的(如foo),另一个是在类的属性中定义的(作为self.foo)。如果我们没有自己,这是不可能的。 Self为我们提供了一个不同的命名空间,以便我们可以区分分配给给定类实例的对象和另一个不关心名称冲突的对象。
The same applies when working with multiple instances of the same class. For example, when you need to compare two instances (using __eq__
and friends):
处理同一个类的多个实例时也是如此。例如,当您需要比较两个实例时(使用__eq__和friends):
class Foo():
def __eq__(self, other)
return self.bar == other.bar
Without self, it would not be so clear which bar
is which. While not terribly important in an "equal" comparison, in a "greater than" or "less than" comparison, the order matters. And by using self, it makes it clear when you write the code, but also clear when you come back to it months/years later and have to read and understand what it is doing.
没有自我,就不清楚哪个是哪个吧。虽然在“平等”比较中不是非常重要,但在“大于”或“小于”比较中,顺序很重要。通过使用self,它可以在您编写代码时清楚地表明,但是当您在几个月/几年后再次使用它时也会清楚,并且必须阅读并理解它正在做什么。
Consider a very large class with many attributes which is part of a large module with many objects. Without self, it would not always be clear which objects are class attributes and which are not without reading through the entire module. So, even if the use of self was optional (as you propose) it would still be good practice to always use it to make sure your code is clear when you (or more importantly someone else) comes back to it later. That is just good programming practice. I'm glad the language forces it. In fact, one of Python's strengths is its readability. Self adds to that readability. Embrace it.
考虑一个具有许多属性的非常大的类,它是具有许多对象的大模块的一部分。没有self,就不会总是清楚哪些对象是类属性,哪些对象不是没有读取整个模块。因此,即使自我的使用是可选的(如你所建议的那样),当你(或更重要的是其他人)稍后再回到它时,总是使用它来确保你的代码是清晰的仍然是一个好习惯。这只是一个很好的编程实践。我很高兴语言强迫它。实际上,Python的优势之一是它的可读性。自我增加了可读性。接受它。
#5
It's important to understand difference between class and object (class instance).
理解类和对象(类实例)之间的区别很重要。
Class is consisted from method declarations together and template for objects (for example class has 2 methods and 1 integer attribute). It's identified by class name only (MSDie
).
类由方法声明和对象模板组成(例如,类有2个方法和1个整数属性)。它仅由类名(MSDie)标识。
Object (class instance) is concrete evaluation of it's class, that is it has concrete values for class attributes. It is identified by class name and evaluation of it's attributes (MSDie(sides=3, value=1)
)
Object(类实例)是对它的类的具体评估,即它具有类属性的具体值。它通过类名和它的属性评估来识别(MSDie(sides = 3,value = 1))
When Python code is executed, program code (methods and functions, so "classes") are loaded into code memory. During program execution, objects are created by executed code and stored in another part of memory - data memory. There are stored values of each attribute together with identification of class for class instance, but nothing from class code (methods) is copied there. Instance can be identified by address (pointer) to data memory box where are stored it's data. It's good to mention, that data and code memory parts are strictly separated. Note there may be thousands instances of same class (so thousands instance boxes in data memory), but code for that class is present only once - in code memory.
当执行Python代码时,程序代码(方法和函数,所以“类”)被加载到代码存储器中。在程序执行期间,对象由执行的代码创建并存储在内存的另一部分 - 数据存储器中。每个属性的存储值与类实例的类的标识一起存在,但是在那里没有复制类代码(方法)。可以通过数据存储器盒的地址(指针)来识别实例,其中存储数据。值得一提的是,数据和代码存储器部分是严格分开的。注意,可能有数千个相同类的实例(数据存储器中有数千个实例框),但该类的代码只出现一次 - 在代码存储器中。
When instance method is called in Python:
在Python中调用instance方法时:
d1.setValue(3)
Name of instance (d1) is converted to pointer into d1's data memory box. But that box doesn't contain code for method MSDie.setValue(x)
. There is only identification of class, which can be used to find code for that method in code memory. But when method code is called from code memory, it has no idea what instance it is supposed to work with. This information needs to be passed somehow there.
实例名称(d1)被转换为指向d1数据存储器的指针。但该框不包含方法MSDie.setValue(x)的代码。只有类的标识,可用于在代码存储器中查找该方法的代码。但是当从代码存储器调用方法代码时,它不知道它应该使用什么实例。这些信息需要以某种方式传递到那里。
Most languages with classes handles this passing of instance to class method during code compilation into byte code and it's not visible in language syntax at all. It just may be "confusing" where this
(Java analogy to Python's self
) comes from as it's not defined anywhere.
大多数带有类的语言在代码编译到字节代码期间处理将实例传递给类方法,并且在语言语法中根本不可见。它可能是“令人困惑”的地方(Java类比Python的自我)来自它,因为它没有在任何地方定义。
Python kept this instance parameter in class methods as part of it's syntax. So it's really not big deal, it works same way in other object oriented languages, they just hide it behind compiler. On the other side, it may be a bit confusing, that class method is defined with 2 parameters (MSDie.setValue(self, x)
), but when it's called, only 1 parameter is passed (d1.setValue(3)
).
Python将此实例参数保留在类方法中作为其语法的一部分。所以它真的不是什么大问题,它在其他面向对象语言中的工作方式相同,它们只是隐藏在编译器之后。另一方面,它可能有点令人困惑,类方法是用2个参数定义的(MSDie.setValue(self,x)),但是当它被调用时,只传递1个参数(d1.setValue(3))。
So to answer your question:
所以回答你的问题:
When class method is defined like this:
当类方法定义如下:
def MSDie:
...
def roll(self):
self.value=randrange(1,self.sides+1,1)
You need to call it this way (without passing value for self
)
你需要这样调用它(没有为自己传递值)
d1.roll()
Python will find what class instance is saved in d1 variable and then it calls it's method like this
Python将在d1变量中找到保存的类实例,然后调用它的方法
MSDie.roll(d1)
But this conversion is done on background. And that is how d1 instance is available as self
inside of method roll()
.
但是这种转换是在后台完成的。这就是方法roll()中d1实例作为self的可用方式。
You can't omit self
parameter in definition of class method simply because Python will not be able to find method with correct number of parameters or values for parameters inside of method will be wrong (1st parameter in method would get 2nd parameter from call, etc). Additionally code inside of method will not get correct instance to work with.
你不能在类方法的定义中省略self参数只是因为Python无法找到具有正确参数数量的方法或者方法内部参数的值将是错误的(方法中的第一个参数将从调用获得第二个参数,等等)。此外,方法内部的代码将无法获得正确的实例。
Also you need to use self
inside of class method to access all object attributes properly (it's needed to find memory box where these values are stored).
此外,您需要在类方法中使用self来正确访问所有对象属性(需要查找存储这些值的内存框)。