自我的目的是什么?
Python中self
单词的目的是什么? 我明白它是指从该类创build的特定对象,但我不明白为什么它明确需要作为参数添加到每个函数。 为了说明,在Ruby中我可以这样做:
class myClass def myFunc(name) @name = name end end
我很明白,很容易。 但是在Python中我需要包含self
:
class myClass: def myFunc(self, name): self.name = name
任何人都可以通过这个说话吗? 这并不是我在我的(当然是有限的)经验中遇到的。
你需要使用self.
的原因self.
是因为Python不使用@
语法来引用实例属性。 Python决定以一种让方法所属的实例自动传递但不能自动接收的方式来执行方法:方法的第一个参数是调用该方法的实例。 这使得方法和函数完全一样,并且留下实际的名字用于你(尽pipeself
是约定,当你使用别的东西的时候,人们通常会皱起眉头) self
并不是特殊的代码,它只是另一个对象。
Python可能已经做了一些其他的事情来区分正常的名称和属性 – 像Ruby这样的特殊语法,或者像C ++和Java这样的声明,或者可能更为不同 – 但事实并非如此。 Python所有的东西都是明确的,明确了什么是什么,尽pipe它并不是完全在做,但它确实是为了实例。 这就是为什么分配给一个实例属性需要知道要分配哪个实例,这就是为什么它需要self.
。
我们来看一个简单的vector类:
class Vector: def __init__(self, x, y): self.x = x self.y = y
我们想要一个计算长度的方法。 如果我们想在课堂上定义它会是什么样子?
def length(self): return math.sqrt(self.x ** 2 + self.y ** 2)
当我们将其定义为全局方法/函数时,应该是什么样子?
def length_global(vector): return math.sqrt(vector.x ** 2 + vector.y ** 2)
所以整个结构保持不变。 我怎么能利用这个? 如果我们暂时假定我们没有为Vector
类写length
方法,我们可以这样做:
Vector.length_new = length_global v = Vector(3, 4) print(v.length_new()) # 5.0
这是length_global
,因为length_global
的第一个参数可以被重新用作length_new
的self
参数。 没有一个明确的self
这是不可能的。
了解明确的self
需求的另一种方法是看看Python在哪里添加一些语法糖。 当你记住的时候,基本上就是这样的一个电话
v_instance.length()
被内部转化为
Vector.length(v_instance)
很容易看出self
的位置。你实际上并没有用Python编写实例方法, 你写的是必须把实例作为第一个参数的类方法。 因此,你必须明确地放置实例参数。
假设您有一个类ClassA
,其中包含一个方法methodA
定义如下:
def methodA(self, arg1, arg2): # do something
ObjectA
是这个类的一个实例。
现在,当ObjectA.methodA(arg1, arg2)
,python会在内部将它转换为:
ClassA.methodA(ObjectA, arg1, arg2)
self
variables是指对象本身。
当对象被实例化时,对象本身被传递给self参数。
因此,对象的数据绑定到对象。 下面是一个如何显示每个对象的数据可能性的例子。 注意“自我”是如何replace对象名称的。 我并不是说下面的这个例子图是完全准确的,但是希望可以用来形象化使用自我。
Object被传递给self参数,以便对象可以保持自己的数据。
虽然这可能不是完全准确的,但想一下这样实例化一个对象的过程:当一个对象被创build时,它使用这个类作为它自己的数据和方法的模板。 如果不将自己的名字传递给self参数,那么类中的属性和方法将保持为通用模板,并且不会被引用(属于)该对象。 所以通过将对象的名字传递给self参数,意味着如果从一个类实例化了100个对象,他们都可以跟踪自己的数据和方法。
见下图:
我喜欢这个例子:
class A: foo = [] a, b = A(), A() a.foo.append(5) b.foo ans: [5] class A: def __init__(self): self.foo = [] a, b = A(), A() a.foo.append(5) b.foo ans: []
我将用不使用类的代码进行演示:
def state_init(state): state['field'] = 'init' def state_add(state, x): state['field'] += x def state_mult(state, x): state['field'] *= x def state_getField(state): return state['field'] myself = {} state_init(myself) state_add(myself, 'added') state_mult(myself, 2) print( state_getField(myself) ) #--> 'initaddedinitadded'
类只是一种避免传递这个“状态”事物的方法(以及诸如初始化,类组合,很less需要的元类以及支持自定义方法来重载操作符的其他好东西)。
现在让我们使用内置的python类机制来演示上面的代码,以显示它基本上是一样的东西。
class State(object): def __init__(self): self.field = 'init' def add(self, x): self.field += x def mult(self, x): self.field *= x s = State() s.add('added') # self is implicitly passed in s.mult(2) # self is implicitly passed in print( s.field )
[从重复closures的问题迁移我的答案]
除了已经提到的所有其他原因之外,它还允许更容易地访问重写的方法; 你可以调用Class.some_method(inst)
。
一个有用的例子:
class C1(object): def __init__(self): print "C1 init" class C2(C1): def __init__(self): #overrides C1.__init__ print "C2 init" C1.__init__(self) #but we still want C1 to init the class too
>>> C2() "C2 init" "C1 init"
以下摘录来自Python关于自我的文档 :
和Modula-3一样,在Python中没有用于引用对象成员的shorthands:方法函数声明了一个明确的第一个参数来表示对象,这个对象由调用隐式地提供。
通常,方法的第一个参数叫做self。 这只不过是一个惯例:名字自己对Python没有特别的意义。 但是请注意,通过不遵循惯例,您的代码对其他Python程序员来说可能会不那么可读,同样可以想象,可能会编写一个依赖于这种约定的类浏览器程序。
有关更多信息,请参阅关于类的Python文档教程 。
它的使用类似于在Java中使用this
关键字,也就是给当前对象提供一个引用。
在那里遵循Python的“明确比隐含更好”。 这确实是对你的类对象的引用。 在Java和PHP中,例如,这就是所谓的。
如果user_type_name
是您的模型上的字段,您可以通过self.user_type_name
访问它。
与Java或C ++不同,Python不是面向对象编程的语言。
当在Python中调用一个静态方法时,只需要在里面写一个带有常规参数的方法。
class Animal(): def staticMethod(): print "This is a static method"
然而,在这种情况下,需要您创buildvariables的对象方法需要自我参数
class Animal(): def objectMethod(self): print "This is an object method which needs an instance of a class"
self方法也被用来指类中的variables字段。
class Animal(): #animalName made in constructor def Animal(self): self.animalName = ""; def getAnimalName(self): return self.animalName
在这种情况下,self指的是整个类的animalNamevariables。 记住:如果你在一个方法中有一个variables,那么自己就不能工作。 该variables只是在该方法正在运行时才存在。 为了定义字段(整个类的variables),你必须在类方法之外定义它们。
如果你不明白我说的是什么,那么Google就是“面向对象编程”。 一旦你明白这一点,你甚至不需要问这个问题:)。
self
是对象本身的对象引用,因此它们是相同的。 Python方法不在对象本身的上下文中调用。 Python中的self
可能被用来处理自定义的对象模型或者其他的东西。
我很惊讶没有人带来了Lua。 Lua也使用'self'variables,但它可以省略但仍然可以使用。 C ++与“this”相同。 我没有看到任何理由必须在每个函数中声明“self”,但是您仍然可以像使用lua和C ++一样使用它。 对于一个自on为简短的语言来说,奇怪的是它要求你声明自variables。
看看下面的例子,这清楚地解释了self
的目的
class Restaurant(object): bankrupt = False def open_branch(self): if not self.bankrupt: print("branch opened") #create instance1 >>> x = Restaurant() >>> x.bankrupt False #create instance2 >>> y = Restaurant() >>> y.bankrupt = True >>> y.bankrupt True >>> x.bankrupt False
self
被用来/需要区分实例。
是因为python的devise方式的替代品将难以奏效。 Python被devise为允许方法或函数在隐式(a-la Java / C ++)或显式@
(a-la ruby)不起作用的上下文中定义。 让我们用python约定的显式方法举个例子:
def fubar(x): self.x = x class C: frob = fubar
现在, fubar
函数将不起作用,因为它会假定self
是一个全局variables(也是frob
)。 另一种方法是用一个被replace的全局范围(其中self
是对象)执行方法。
隐含的方法是
def fubar(x) myX = x class C: frob = fubar
这将意味着myX
将被解释为fubar
的局部variables(以及frob
)。 这里的另一种方法是执行一个被replace的局部范围的方法,这个方法在调用之间被保留,但是这会消除方法局部variables的可能性。
但目前情况很好:
def fubar(self, x) self.x = x class C: frob = fubar
这里作为一个方法调用时, frob
将通过self
参数接收它所调用的对象,并且仍然可以用一个对象作为参数调用fubar
,并且工作方式与fubar
相同(与我想的相同)。
在__init__
方法中,self指新创build的对象; 在其他类方法中,它指的是调用方法的实例。
自我,作为一个名字, 只是一个约定 ,随心所欲! 但是在使用它时,例如删除对象,则必须使用相同的名称: __del__(var)
,其中var
在__init__(var,[...])
你也应该看看cls
,以获得更大的图片 。 这篇文章可能会有所帮助。
它是对类实例对象的显式引用。