class Box(object):
    def __init__(this, boxname, size, color):
        this.boxname = boxname
        this.size = size
        this.color = color  # self就是用于存储对象属性的集合,就算没有属性self也是必备的,代表类的实例,而非类。

    def open(this, myself):
        print('-->用自己的myself,打开那个%s,%s的%s' % (myself.color, myself.__dict__['size'], myself.boxname))
        print('-->用类自己的self,打开那个%s,%s的%s' % (this.__dict__['color'], this.__dict__['size'], this.boxname))
    @classmethod
    def close(cls):
        print('-->关闭%s,谢谢' )


b = Box('魔盒', '14m', '红色')
Box.close() # close是一个类方法,可以通过类调用
b.close()# close是一个类方法,自然也可以通过实例调用

b.open(b)  # 当我们调用b.open(b)时,实际上Python解释成Box.open(b,b),也就是把self替换成了类的实例b, 另外myself也是一个实例,所以相当于两个输入实例参数。
Box.open(b,b)#上面方法实际执行就是这样的,当我们调用b.open(b)时,实际上Python解释成Box.open(b,b)。
print(b.__dict__)  # 这里返回的就是self本身,self存储属性,没有动作。

self的仔细用法。

(1)、self代表类的实例,而非类。

class Test:
    def ppr(self):
        print(self)
        print(self.__class__)

t = Test()
t.ppr()
执行结果:
<__main__.Test object at 0x000000000284E080>
<class '__main__.Test'>

从上面的例子中可以很明显的看出,self代表的是类的实例。而self.__class__则指向类。
注意:把self换成this,结果也一样,但Python中最好用约定俗成的self。
(2)、self可以不写吗?
在Python解释器的内部,当我们调用t.ppr()时,实际上Python解释成Test.ppr(t),也就是把self替换成了类的实例。

class Test:
    def ppr():
        print(self)

t = Test()
t.ppr()

 

运行结果如下:

Traceback (most recent call last):
  File "cl.py", line 6, in <module>
    t.ppr()
TypeError: ppr() takes 0 positional arguments but 1 was given

 

运行时提醒错误如下:ppr在定义时没有参数,但是我们运行时强行传了一个参数。

由于上面解释过了t.ppr()等同于Test.ppr(t),所以程序提醒我们多传了一个参数t。

这里实际上已经部分说明了self在定义时不可以省略。

当然,如果我们的定义和调用时均不传类实例是可以的,这就是类方法。

class Test:
    @classmethod
    def ppr(cls):
        print(__class__)

Test.ppr()

运行结果:
<class '__main__.Test'>

 

(3)、在继承时,传入的是哪个实例,就是那个传入的实例,而不是指定义了self的类的实例。

class Parent:
    def pprt(self):
        print(self)

class Child(Parent):
    def cprt(self):
        print(self)
c = Child()
c.cprt()
c.pprt()
p = Parent()
p.pprt()

 

运行结果:

<__main__.Child object at 0x0000000002A47080>
<__main__.Child object at 0x0000000002A47080>
<__main__.Parent object at 0x0000000002A47240>

 

解释:
运行c.cprt()时应该没有理解问题,指的是Child类的实例。
但是在运行c.pprt()时,等同于Child.pprt(c),所以self指的依然是Child类的实例,由于self中没有定义pprt()方法,所以沿着继承树往上找,发现在父类Parent中定义了pprt()方法,所以就会成功调用。

(4)、在描述符类中,self指的是描述符类的实例

class Desc:
    def __get__(self, ins, cls):
        print('self in Desc: %s ' % self )
        print(self, ins, cls)
class Test:
    x = Desc()
    def prt(self):
        print('self in Test: %s' % self)
t = Test()
t.prt()
t.x

 

运行结果如下:

self in Test: <__main__.Test object at 0x0000000002A570B8>
self in Desc: <__main__.Desc object at 0x000000000283E208>
<__main__.Desc object at 0x000000000283E208> <__main__.Test object at 0x0000000002A570B8> <class '__main__.Test'>

 

这里主要的疑问应该在:Desc类中定义的self不是应该是调用它的实例t吗?怎么变成了Desc类的实例了呢?
因为这里调用的是t.x,也就是说是Test类的实例t的属性x,由于实例t中并没有定义属性x,所以找到了类属性x,而该属性是描述符属性,为Desc类的实例而已,所以此处并没有顶用Test的任何方法。

那么我们如果直接通过类来调用属性x也可以得到相同的结果。

下面是把t.x改为Test.x运行的结果。

self in Test: <__main__.Test object at 0x00000000022570B8>
self in Desc: <__main__.Desc object at 0x000000000223E208>
<__main__.Desc object at 0x000000000223E208> None <class '__main__.Test'>

 

总结:以上是之前学习Python时的小结,现在已博客方式呈现,同时为pyspark中调用self遇到的问题做铺垫,后面也会对比java,未完待续…….

<link rel="stylesheet" href="">
                        </div>