精华内容
参与话题
问答
  • Python中self用法详解

    万次阅读 多人点赞 2017-07-11 23:03:25
    Python中类、实例以及self的详解

    在介绍Python的self用法之前,先来介绍下Python中的类和实例……
    我们知道,面向对象最重要的概念就是类(class)和实例(instance),类是抽象的模板,比如学生这个抽象的事物,可以用一个Student类来表示。而实例是根据类创建出来的一个个具体的“对象”,每一个对象都从类中继承有相同的方法,但各自的数据可能不同。
    1、以Student类为例,在Python中,定义类如下:

    class Student(object):
        pass

    (Object)表示该类从哪个类继承下来的,Object类是所有类都会继承的类。

    2、实例:定义好了类,就可以通过Student类创建出Student的实例,创建实例是通过类名+()实现:

    student = Student()

    3、由于类起到模板的作用,因此,可以在创建实例的时候,把我们认为必须绑定的属性强制填写进去。这里就用到Python当中的一个内置方法__init__方法,例如在Student类时,把name、score等属性绑上去:

    class Student(object):
        def __init__(self, name, score):
            self.name = name
            self.score = score

    这里注意:(1)、__init__方法的第一参数永远是self,表示创建的类实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。(2)、有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器会自己把实例变量传进去:

    >>>student = Student("Hugh", 99)
    >>>student.name
    "Hugh"
    >>>student.score
    99

    另外,这里self就是指类本身,self.name就是Student类的属性变量,是Student类所有。而name是外部传来的参数,不是Student类所自带的。故,self.name = name的意思就是把外部传来的参数name的值赋值给Student类自己的属性变量self.name

    4、和普通数相比,在类中定义函数只有一点不同,就是第一参数永远是类的本身实例变量self,并且调用时,不用传递该参数。除此之外,类的方法(函数)和普通函数没啥区别,你既可以用默认参数、可变参数或者关键字参数*args是可变参数,args接收的是一个tuple**kw是关键字参数,kw接收的是一个dict)。

    5、既然Student类实例本身就拥有这些数据,那么要访问这些数据,就没必要从外面的函数去访问,而可以直接在Student类的内部定义访问数据的函数(方法),这样,就可以把”数据”封装起来。这些封装数据的函数是和Student类本身是关联起来的,称之为类的方法:

    class Student(obiect):
        def __init__(self, name, score):
            self.name = name
            self.score = score
        def print_score(self):
            print "%s: %s" % (self.name, self.score)
    >>>student = Student("Hugh", 99)
    >>>student.print_score
    Hugh: 99

    这样一来,我们从外部看Student类,就只需要知道,创建实例需要给出name和score。而如何打印,都是在Student类的内部定义的,这些数据和逻辑被封装起来了,调用很容易,但却不知道内部实现的细节。

    如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线,在Python中,实例的变量名如果以开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:

    class Student(object):
    
        def __init__(self, name, score):
            self.__name = name
            self.__score = score
        def print_score(self):
            print "%s: %s" %(self.__name,self.__score)

    改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量.__name和实例变量.__score了:

    >>> student = Student('Hugh', 99)
    >>> student.__name
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'Student' object has no attribute '__name'

    这样就确保了外部代码不能随意修改对象内部的状态,这样通过访问限制的保护,代码更加健壮。

    但是如果外部代码要获取name和score怎么办?可以给Student类增加get_name和get_score这样的方法:

    class Student(object):
        ...
    
        def get_name(self):
            return self.__name
    
        def get_score(self):
            return self.__score

    如果又要允许外部代码修改score怎么办?可以给Student类增加set_score方法:

    class Student(object):
        ...
    
        def set_score(self, score):
            self.__score = score

    需要注意的是,在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name____score__这样的变量名。

    有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。

    封装的另一个好处是可以随时给Student类增加新的方法,比如:get_grade:

    class Student(object):
        ...
        def get_grade(self):
            if self.score >= 90:
                return 'A'
            elif self.score >= 60:
                return 'B'
            else:
                return 'C'

    同样的,get_grade方法可以直接在实例变量上调用,不需要知道内部实现细节:

    >>> student.get_grade()
    'A'

    6、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:
        def ppr():
            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,未完待续…….

    展开全文
  • #_*_coding:utf-8_*_ import unittest from name_function import get_formatted_name ... self.assertEqual(formatted_name,'Bob Dylan',msg="1") if __name__=="__main__": unittest.main()
  • Python中的*self,*self._args, **kwargs

    万次阅读 2018-04-30 20:34:47
    我的机器学习教程「美团」算法工程师带你入门机器学习 已经开始更新了,欢迎大家订阅~ 任何关于算法、编程、AI行业知识或博客内容的问题,可以随时扫码关注公众号「图灵的猫」,加入”学习小组“,沙雕博主在线答疑...

    我的机器学习教程「美团」算法工程师带你入门机器学习   已经开始更新了,欢迎大家订阅~

    任何关于算法、编程、AI行业知识或博客内容的问题,可以随时扫码关注公众号「图灵的猫」,加入”学习小组“,沙雕博主在线答疑~此外,公众号内还有更多AI、算法、编程和大数据知识分享,以及免费的SSR节点和学习资料。其他平台(知乎/B站)也是同名「图灵的猫」,不要迷路哦~

     

     

     

     

     

    在python中,有些常见方法参数是:*self._args, **kwargs,如:self._target(*self._args, **self._kwargs)。经过查找一些资料,可以归纳为以下两种类型:

    • *self._args 表示接受元组类参数;
    • **kwargs     表示接受字典类参数;

    例子:

     

     

     

    def foo(*args, **kwargs):
        print 'args = ', args
        print 'kwargs = ', kwargs
        print '---------------------------------------'
    if __name__ == '__main__':
        foo(1,2,3,4)
        foo(a=1,b=2,c=3)
        foo(1,2,3,4, a=1,b=2,c=3)
        foo('a', 1, None, a=1, b='2', c=3)

     


    输出结果如下:

     

     

    args =  (1, 2, 3, 4) 
    kwargs =  {} 
    --------------------------------------- 
    args =  () 
    kwargs =  {'a': 1, 'c': 3, 'b': 2} 
    --------------------------------------- 
    args =  (1, 2, 3, 4) 
    kwargs =  {'a': 1, 'c': 3, 'b': 2} 
    --------------------------------------- 
    args =  ('a', 1, None) 
    kwargs =  {'a': 1, 'c': 3, 'b': '2'} 
    ---------------------------------------

     

    可以看到,这两个是python中的可变参数。*args表示任何多个无名参数,它是一个tuple;**kwargs表示关键字参数,它是一个dict。并且同时使用*args和**kwargs时,必须*args参数列要在**kwargs前,像foo(a=1, b='2', c=3, a', 1, None, )这样调用的话,会提示语法错误SyntaxError: non-keyword arg after keyword arg”

     

    此外,在Python类定义的方法中,有这样一种写法:

        
    class Test_(object):
        def __init__(self, x, y):
            self.__x = x
            self.__y = y
    
        def __repr__(self):
            class_name = type(self).__name__
            return '{}:({!r}, {!r})'.format(class_name, *self)
            
        def __iter__(self):
            return (i for i in (self.__x, self.__y))
        def test(*self):
            print(self)
    
        def test2(self):
            print(self)

    输出如下:

    >>>dd.test()
    (Test_:(2, 3),)
    
    >>>dd.test2()
    Test_:(2, 3)
    
    >>>dd
    Test_:(2, 3)
    

    从上面的例子可以看出,在方法中传入(*self),执行打印操作时,返回值是序列(这里是单元素元组),而传入self参数时,会返回我们期待的repr格式

    展开全文
  • Python中if __name__ == '__main__',__init__和self 的解析

    万次阅读 多人点赞 2018-09-03 10:32:21
    文章主要包括2部分内容,分别是if __name__ == '__main__'的解析和__init__与self的解析。 目录 1 if __name__ == '__main__' 1.1 摘要 1.2程序入口 1.2.1一个.py文件被其他.py文件引用 1.2.2修改const.py,...

    文章主要包括2部分内容,分别是if __name__ == '__main__'的解析和__init__与self的解析。

    目录

    1 if __name__ == '__main__'

    1.1 摘要

    1.2 程序入口

    1.2.1 一个.py文件被其他.py文件引用

    1.2.2 修改const.py,添加if __name__ == "__main__"

    2 __init__与self

    2.1 Python中self的含义

    2.2 Python中为何要有self

    2.3 首先来看一下__init__()和self对象

    2.4 如果没有在__init__中初始化对应的实例变量的话,导致后续引用实例变量会出错

    2.5 在函数中,使用对应的变量,虽然代码是可以运行的,但是实际上使用的,不是实例中的变量

    3 参考文献


    1 if __name__ == '__main__'

    1.1 摘要

    通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明');在你自己眼中,你是你自己(__name__ == '__main__')

    if __name__ == '__main__'的意思是:当.py文件被直接运行时,if __name__ == '__main__'之下的代码块将被运行;当.py文件以模块形式被导入时,if __name__ == '__main__'之下的代码块不被运行。

    1.2 程序入口

    对于很多编程语言来说,程序都必须要有一个入口,比如C,C++,以及完全面向对象的编程语言Java,C#等。如果你接触过这些语言,对于程序入口这个概念应该很好理解,C,C++都需要有一个main函数作为程序的入口,也就是程序的运行会从main函数开始。同样,Java,C#必须要有一个包含Main方法的主类,作为程序入口。

    而Python则不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口

    一个Python源码文件(.py)除了可以被直接运行外,还可以作为模块(也就是库),被其他.py文件导入。不管是直接运行还是被导入,.py文件的最顶层代码都会被运行(Python用缩进来区分代码层次),而当一个.py文件作为模块被导入时,我们可能不希望一部分代码被运行。

    1.2.1 一个.py文件被其他.py文件引用

    假设我们有一个const.py文件,内容如下:

    PI = 3.14
    
    def main():
        print("PI:", PI)
    
    main()
    
    # 运行结果:PI: 3.14

     现在,我们写一个用于计算圆面积的area.py文件,area.py文件需要用到const.py文件中的PI变量。从const.py中,我们把PI变量导入area.py:

    from const import PI
    
    def calc_round_area(radius):
        return PI * (radius ** 2)
    
    def main():
        print("round area: ", calc_round_area(2))
    
    main()
    
    '''
    运行结果:
    PI: 3.14
    round area:  12.56
    '''

    1.2.2 修改const.py,添加if __name__ == "__main__"

    我们看到const.py中的main函数也被运行了,实际上我们不希望它被运行,因为const.py提供的main函数只是为了测试常量定义。这时if __name__ == '__main__'派上了用场,我们把const.py改一下,添加if __name__ == "__main__"

    PI = 3.14
    
    def main():
        print("PI:", PI)
    
    if __name__ == "__main__":
        main()

    运行const.py,输出如下:

    PI: 3.14

    运行area.py,输出如下:

    round area:  12.56

    如上,我们可以看到if __name__ == '__main__'相当于Python模拟的程序入口,Python本身并没有这么规定,这只是一种编码习惯。由于模块之间相互引用,不同模块可能有这样的定义,而程序入口只有一个。到底哪个程序入口被选中,这取决于__name__的值。


    2 __init__与self

    2.1 Python中self的含义

    self,英文单词意思很明显,表示自己,本身。python的self,是个对象(Object),是当前类的实例。

    2.2 Python中为何要有self

    那就是:

    在类的代码(函数)中,需要访问当前的实例中的变量和函数的,即,访问Instance中的:

    • 对应的变量(属性,property):Instance.ProperyNam,去读取之前的值和写入新的值
    • 调用对应函数(function):Instance.function(),即执行对应的动作

    -> 而需要访问实例的变量和调用实例的函数,当然需要对应的实例Instance对象本身

    -> 而Python中就规定好了,函数的第一个参数,就必须是实例对象本身,并且建议,约定俗成,把其名字写为self

    -> 所以,我们需要self

    而如果没有用到self,即代码中,去掉self后,那种写法所使用到的变量,实际上不是你所希望的,不是真正的实例中的变量和函数,而是的访问到了其他部分的变量和函数了。甚至会由于没有合适的初始化实例变量,而导致后续无法访问的错误。

    下面,就通过代码,来演示,如果去掉self,或者没有合理的使用self,会出现哪些错误。

    2.3 首先来看一下__init__()和self对象 

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
     
    class Person(object):
        def __init__(self, name, lang, website):
            self.name = name
            self.lang = lang
            self.website = website
     
            print('self: ', self)
            print('type of self: ', type(self))
    '''
    未实例化时,运行程序,构造方法没有运行
    '''
     
    p = Person('Tim', 'English', 'www.universal.com')   
     
    '''实例化后运行的结果
    self:  <__main__.Person object at 0x00000000021EAF98>
    type of self:  <class '__main__.Person'>
    '''

    可以看出self为实例变量p,是一个Person类型的对象。

    class Dog(object):       
        def __init__(self,name,dog_type):
            self.name = name
            self.type = dog_type
       
        def sayhi(self):
            print("hello,I am a dog, my name is ",self.name)
       
       
    d = Dog('LiChuang',"京巴")            # 实例化
    d.sayhi()

    以下是d = Dog('LiChuang',"京巴")实例化的示意图:

    2.4 如果没有在__init__中初始化对应的实例变量的话,导致后续引用实例变量会出错

    如下代码,完整的演示了,如果没有在类Class的最初的__init__函数中,正确的初始化实例变量,则会导致后续没有变量可用,因而出现AttributeError的错误:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
     
    name = 'whole global name'
    '''
    注:此处全局的变量名,写成name,只是为了演示而用
    实际上,好的编程风格,应该写成gName之类的名字,
    以表示该变量是Global的变量
    '''
     
    class Person(object):
        def __init__(self, newPersonName):
            # self.name = newPersonName
            '''
            如果此处不写成self.name
            那么此处的name,只是__init__函数中的局部临时变量name而已
            和全局中的name,没有半毛钱关系
            '''
            name = newPersonName
            '''
            此处只是为了代码演示,而使用了局部变量name,
            不过需要注意的是,此处很明显,由于接下来的代码也没有利用到此处的局部变量name
            则就导致了,此处的name变量,实际上被浪费了,根本没有利用到
            '''
        def sayYourName(self):
            '''
            此处由于找不到实例中的name变量,所以会报错:
            AttributeError: Person instance has no attribute 'name'
            '''
            print('My name is %s' %self.name)
     
    def selfAndInitDemo():
        personInstance = Person('Tim')
        personInstance.sayYourName()
     
    if __name__ == '__main__':
        selfAndInitDemo()
     
     
    '''  未使用self.name时抛异常
    Traceback (most recent call last):
      File "E:/python14_workspace/s14/day06/test_1.py", line 18, in <module>
        selfAndInitDemo()
      File "E:/python14_workspace/s14/day06/test_1.py", line 15, in selfAndInitDemo
        personInstance.sayYourName()
      File "E:/python14_workspace/s14/day06/test_1.py", line 11, in sayYourName
        print('My name is %s' %self.name)
    AttributeError: 'Person' object has no attribute 'name'
    '''

    从上述代码可见,由于在类的初始化(实例化)的__init__函数中,没有给self.name设置值,使得实例中,根本没有name这个变量,导致后续再去访问self.name,就会出现AttributeError的错误了。

    对应的,如果写成self.name,则意思就正确了,就是初始化的时候,给实例中新增加,并且正常设置了正确的值newPersionName了,所以后续再去通过self.name,就可以访问到,当前实例中正确的变量name了。

    相应的正确写法的代码如下:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
     
    name = 'whole global name'
    '''
    注:此处全局的变量名,写成name,只是为了演示而用
    实际上,好的编程风格,应该写成gName之类的名字,
    以表示该变量是Global的变量
    '''
     
    class Person(object):
        def __init__(self, newPersonName):
            self.name = newPersonName
            '''
            此处正确的,通过访问self.name的形式,实现了:
                1.给实例中,增加了name变量
                2.并且给name赋了初值,为newPersionName
            '''
        def sayYourName(self):
            '''
            此处由于开始正确的初始化了self对象,使得其中有了name变量,
            所以此处可以正确访问了name值了
            '''
            print('My name is %s' %self.name)
     
    def selfAndInitDemo():
        personInstance = Person('Tim')
        personInstance.sayYourName()
     
    if __name__ == '__main__':
        selfAndInitDemo()
     
     
    '''My name is Tim'''

    2.5 在函数中,使用对应的变量,虽然代码是可以运行的,但是实际上使用的,不是实例中的变量

    有时候,虽然你写的代码,可以运行,但是使用到的变量,由于没有加self,实际上是用到的不是实例的变量,而是其他的变量。

    此类问题,主要和Python中的变量的作用域有关,但是此处例子中,也和是否使用self有关:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
     
    name = 'whole global name'
    '''
    注:此处全局的变量名,写成name,只是为了演示而用
    实际上,好的编程风格,应该写成gName之类的名字,
    以表示该变量是Global的变量
    '''
     
    class Person(object):
        name = 'class global name'
     
        def __init__(self, newPersonName):
            # self.name = newPersonName
            '''
            此处,没有使用self.name
            而使得此处的name,实际上仍是局部变量name
            虽然此处赋值了,但是后面没有被利用到,属于被浪费了的局部变量name
            '''
            name = newPersonName
        def sayYourName(self):
            '''
            此处,之所以没有像之前一样出现:
            AttributeError: Person instance has no attribute 'name'
            那是因为,虽然当前的实例self中,没有在__init__中初始化对应的name变量,实例self中没有对应的name变量
            但是由于实例所对应的类Person,有对应的name变量,所以也是可以正常执行代码的
            对应的,此处的self.name,实际上是Person.name
            '''
            print('My name is %s' %self.name)
            print('Name within class Person is actually the global name: %s' %name)
            print("Only access Person's name via Person.name = %s" %(Person.name))
     
    def selfAndInitDemo():
        personInstance = Person('Tim')
        personInstance.sayYourName()
        print('whole global name is %s' %name)
     
    if __name__ == '__main__':
        selfAndInitDemo()
     
     
    '''
    My name is class global name
    Name within class Person is actually the global name: whole global name
    Only access Person's name via Person.name = class global name
    whole global name is whole global name
    '''

    其中,可见,此处开始__init__中,没有给self实例初始化对应的name,

    而后面的函数sayYourName中,虽然可以调用到self.name而没有出现AttributeError错误,

    但是实际上此处的值,不是所期望的,传入的name,即"Tim",而是类中的name的值,即"class global name"。

    3 参考文献

    【1】如何简单地理解Python中的if __name__ == '__main__'

    【2】Python类中的__init__() 和 self 的解析

    展开全文
  • 读懂python中的self

    万次阅读 多人点赞 2019-04-29 23:45:42
    神奇的self: 在Python类中规定,函数的第一个参数是实例对象本身,并且约定俗成,把其名字写为self。其作用相当于java中的this,表示当前类的对象,可以调用当前类中的属性和方法。 class是面向对象的设计思想...

    神奇的self:

    在Python类中规定,函数的第一个参数是实例对象本身,并且约定俗成,把其名字写为self。其作用相当于java中的this,表示当前类的对象,可以调用当前类中的属性和方法。

    class是面向对象的设计思想,instance(也即是 object,对象)是根据 class 创建的

    一个类(class)应该包含 数据 和 操作数据的方法,通俗来讲就是 属性 和 函数(即调用方法)

    类 class 中为啥用使用 self ?

    在类的代码(函数)中,需要访问当前的实例中的变量和函数,即,访问Instance中的:

    • 对应的变量(property):Instance.ProperyNam,去读取之前的值和写入新的值

    • 调用对应函数(function):Instance.function(),即执行对应的动作

    -> 而需要访问实例的变量和调用实例的函数,当然需要对应的实例Instance对象本身

    -> 而Python中就规定好了,函数的第一个参数,就必须是实例对象本身,并且建议,约定俗成,把其名字写为self

    -> 所以,我们需要self(需要用到self)

    首先,在Python中类的定义:

    在python中,类是通过关键字 class 定义的:

    class 后面紧跟 类名,即 Person,类名通常大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的,通常,如果没有合适的 继承类,就使用 object 类,这是所有类最终都会 继承的类

    class Person(object):
        pass

    将 Person类实例化,创建实例化是通过 类名+() 实现的

    class Person(object):
        pass
    student = Person()    # 创建类的实例化
    print(student)
    print(Person)

    可以看到,变量 student指向的就是一个 Person的 object,后面的  0x0000026EE434D8D0 是内存地址,每个 object 的地址都不一样,而 Person 本身则是一个 类

    也可以给实例变量绑定属性,比如:为 student 绑定  name 和 score 属性

    class Person(object):
        pass
    student = Person()
    # print(student)
    # print(Person)
    student.name = "Gavin"     # 为实例变量 student 绑定 name 属性   类似于 赋值 操作
    student.score = 100        # 为 其绑定  score 属性
    print(student.name)
    print(student.score)

    上述的方法虽然可以为类的实例变量绑定属性,但是不够方便和elegant , 由于类 可以起到模板的作用,故在创建实例的时候,可以将我们认为必须绑定 属性 强制填写进去,在 python中,是通过 类中通常都会使用的一个方法,即def  __init__(self) 方法,在创建实例变量的时候,就把 name 和 score 等属性绑上去

    class Person(object):
        def __init__(self,name,score):
            self.name = name
            self.score = score
            
    student = Person('Gavin',100)    #  传入 __init__ 方法中需要的 参数
    print(student.name)
    print(student.score)

     传入空参数的情况,会报错:

    class Person(object):
        def __init__(self,name,score):
            self.name = name
            self.score = score
            
    student = Person()      # 此处应该有参数传入,却没有传
    print(student.name)
    print(student.score)

     

    注意:

    1、__init__ 方法的第一个参数永远是 self ,表示创建的实例本身,因此,在 __init__ 方法的内部,就可以把各种属性绑定到 self,因为 self 就指向创建的 实例本身

    2、使用了 __init__ 方法,在创建实例的时候就不能传入 空的参数了,必须传入与 __init__ 方法匹配的参数,但是 self 不需要传,python解释器会自己把实例变量传进去

    在类中定义多个函数相互调用

    class Person(object):
        def __init__(self,x,y):
            self.x = x
            self.y = y
            
        def add(self):
            sum = self.x + self.y
            return sum
        
        def square(self):
            squr = pow(self.x,2)+pow(self.y,2)
            return squr
        def add_square(self):
            c = self.add()+self.square()
            return c
            
    student = Person(3,4)
    print(student.add())
    print(student.square())
    print('--------- 我是可爱的分割线-----------')
    print(student.add_square())

    通过上述的例子可以看出,与普通的函数相比,在类中定义的函数只有两点点不同:

    1、第一个参数永远是 self ,并且调用时不用传递该参数

    2、在类中函数相互调用要加 self ,如上例中: c = self.add()+self.square(), 不加 self ,会报错: 函数未定义,看下图

    除此之外,类的方法和普通函数没甚区别,当然也可以使用 默认参数、可变参数和关键字参数,例子如下:

    class Person(object):
        def __init__(self,x,y):
            self.x = x
            self.y = y
            
            
        def add(self,z=16):         # 设置 默认变量 z =16,这只是个普通的局部变量,非实例变量,实例变量需要 self.z = z,这样定义
            sum = self.x + self.y + z
            return sum
        
        def square(self):
            squr = pow(self.x,2)+pow(self.y,2)
            return squr
        def add_square(self,z):        #  调用时传入变量,这也是个普通的局部变量,非实例变量 
            c = self.add()+self.square() + z
            return c
            
    student = Person(3,4)
    print(student.add())
    print(student.square())
    print('--------- 我是可爱的分割线-----------')
    print(student.add_square(16))

    看了上述的例子可能还是不明白 self 到底是个什么鬼,为啥要使用self这鬼东西 ?,没关系,往下看

    其实 self 这家伙简单的说就是把 class 中 定义的 变量和函数 变成 实例变量和实例函数,作为类 class 的成员,使得成员间能互相调用,而不需要从外部调用 数据(即变量)和 方法(即 函数),以实现数据的封装,以上面的 Person 类为例:

    创建实例的时候需要给出实例变量 x,y, 调用函数时给出 z ,调用很容易,却不知道内部实现的细节 

    总之,类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都相互独立、互不影响;方法是与实例绑定的函数,和普通的函数不同,方法可以直接访问实例的数据

    其实 self 中存储的是 实例变量 和 实例函数 的属性,可以理解为一个字典( dict ),如:{'name':'zhang','age':'18'}就是这些。

    注意只有数据属性,并没有创建新的类的方法。  类----->通过实例化生成----对象---->(对象只是一串类似于字典的数据,没有把类的里的方法复制给你,python没有new这个方法!)

    class Person(object):
        def __init__(self,x,y):
            self.x = x
            self.y = y
            
            
        def add(self,z=16):     # 设置 z 为实例变量,即 self.z = z, z 是 class 的一个成员了,而非普通局部变量
            self.z = z
            sum = self.x + self.y + z  # z虽然已被实例化,但是依然可以当作 普通变量来用
            return sum
        
        def square(self):
            squr = pow(self.x,2)+pow(self.y,2)
            return squr
        def add_square(self):        
            c = self.add()+self.square() + self.z  # 调用实例变量 z 
            return c
            
    student = Person(3,4)
    print(student.add())
    print(student.square())
    print('--------- 我是可爱的分割线-----------')
    print(student.add_square())
    print(student.z)          # 函数add 中的 z 被实例化以后,就可以利用实例化的方法访问它 

     

    通过这个例子可以看出, z 本来是 add() 函数的默认形参,通过将其实例化,就可以在其他函数体内调用 实例变量 z 

     被实例化以后,就可以利用实例化的方法访问它

    那么 self 到底是什么?

    class Box(object):
        def __init__(self, boxname, size, color):
            self.boxname = boxname
            self.size = size
            self.color = color  # self就是用于存储对象属性的集合,就算没有属性self也是必备的
    
        def open(self, myself):
            print('-->用自己的myself,打开那个%s,%s的%s' % (myself.color, myself.size, myself.boxname))
            print('-->用类自己的self,打开那个%s,%s的%s' % (self.color, self.size, self.boxname))
    
        def close(self):
            print('-->关闭%s,谢谢' % self.boxname)
    
    
    b = Box('魔盒', '14m', '红色')
    b.close()
    b.open(b)  # 本来就会自动传一个self,现在传入b,就会让open多得到一个实例对象本身,print看看是什么。
    print(b.__dict__)  # 这里返回的就是self本身,self存储属性,没有动作。

     

    self代表类的实例,而非类;self 就是 对象/实例 属性集合

    Box 是个类-----》self 实例化------》 b对象/ 实例

    class 抽象体------》实例化------》对象/实例,含有属性:{'boxname':'魔盒', ‘size’:‘14m’, 'color':'red'},即 self

    self 看似是整个对象,实际上清楚地描述了类就是产生对象的过程,描述了 self 就是得到了 对象,所以 self 内的键值可以直接使用

    正如自然界中一个有效的对象,必须包括:

    1、描述对象的属性;2、对象的方法

    所以 self是必须的,也是对象中重要的特性

    看下面的代码,感觉就更神奇了:

    class Box(object):
        def myInit(mySelf, boxname, size, color):
            mySelf.boxname = boxname
            mySelf.size = size
            mySelf.color = color  # 自己写一个初始化函数,一样奏效,甚至不用self命名。其它函数当中用标准self
            return mySelf  # 返回给实例化过程一个对象!神奇!并且含有对象属性/字典
    
        # def __init__(self, boxname, size, color):
        #     self.boxname = boxname
        #     self.size = size
        #     self.color = color  #注释掉原来标准的初始化
    
        def open(self, myself):
            print(self)
            print('-->用自己的myself,打开那个%s,%s的%s' % (myself.color, myself.size, myself.boxname))
            print('-->用类自己的self,打开那个%s,%s的%s' % (myself.color, myself.size, myself.boxname))
    
        def close(self):
            print('-->关闭%s,谢谢' % self.boxname)
    
    
    # 经过改造,运行结果和标准初始化没区别
    
    b = Box().myInit('魔盒', '14m', '红色')
    # b = Box('魔盒', '14m', '红色')#注释掉原来标准的初始化方法
    b.close()
    b.open(b)  # 本来就会自动传一个self,现在传入b,就会让open多得到一个实例对象本身,print看看是什么。
    print(b.__dict__)  # 这里返回的就是self本身,self存储属性,没有动作。

    换个角度来讲,对类的操作有:

    1、定义属性 ; 2、调用方法

    对类的反馈有:

    1、得到属性 ; 2、执行方法

    在 class 类的函数中,为什么 self是必要的,因为 self 是对象的载体,可以理解成一个字典,看下面代码:

    class Box(object):
        def myInit(mySelf, boxname, size, color):
            print(mySelf.__dict__)#显示为{}空字典
            mySelf.boxname = boxname
            mySelf.__dict__['aa'] = 'w'#甚至可以像字典一样操作
            mySelf.size = size
            mySelf.color = color  # 自己写一个初始化函数,一样奏效,甚至不用self命名。其它函数当中用标准self
            return mySelf  # 返回给实例化过程一个对象!神奇!并且含有对象属性/字典
    
        # def __init__(self, boxname, size, color):
        #     self.boxname = boxname
        #     self.size = size
        #     self.color = color  #注释掉原来标准的初始化
    
        def open(self, myself):
            print(self)
            print('-->用自己的myself,打开那个%s,%s的%s' % (myself.color, myself.size, myself.boxname))
            print('-->用类自己的self,打开那个%s,%s的%s' % (myself.color, myself.size, myself.boxname))
    
        def close(self):
            print('-->关闭%s,谢谢' % self.boxname)
    
    
    # 经过改造,运行结果和标准初始化没区别
    
    b = Box().myInit('魔盒', '14m', '红色')
    # b = Box('魔盒', '14m', '红色')#注释掉原来标准的初始化方法
    b.close()
    b.open(b)  # 本来就会自动传一个self,现在传入b,就会让open多得到一个实例对象本身,print看看是什么。
    print(b.__dict__)  # 这里返回的就是self本身,self存储属性,没有动作。

     注意此处的: mySelf.__dict__['aa'] = 'w'  #甚至可以像字典一样操作; 在 b.__dict__ 的结果中显示为:'aa':'w'

    故可以把 self 理解成存储 实例化对象属性的字典(dict), self 存储属性,而没有动作执行

    self总是指调用时的类的实例。

    python 中一些特殊的实例变量:

    1、私有变量(private),只有内部可以访问,外部不能访问,私有变量是在名称前以两个下划线开头,如:__name,其实私有变量也不是完全不能被外部访问,不能直接访问是因为python解释器对外把 __name 变量改成了 _类名__name,所仍然可以通过 _类名__name 来访问 __name .

    2、在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name____score__这样的变量名。

    3、以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”

     

    Reference:

    在python的class中的,self到底是什么?

    终于明白了Python中self的含义

    Python中self用法详解

    Python中self和__init__的含义与使用

    Python中:self和__init__的含义 + 为何要有self和__init__

     

    展开全文
  • 安装 Self service password @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Note: http://ltb-project.org/wiki/download self service password download page CentOS下php安装mcrypt扩展: vim /etc/yum.repos.d/...
  • justify-self 沿着 行轴线(水平方向) 对齐网格项中的内容(justify the content within individual grid items),此值适用于单个网格项内的内容(applying the justify-self property to the grid item itself)...
  • import multiprocessing import time def fun(): ... self.p.apply_async(self.fun) self.p.close() self.p.join() print('end') if __name__ == '__main__': a = T() a.run()
  • self和[self class]

    千次阅读 2013-06-05 10:37:59
    self是实例的指针,[self class]是类的指针,静态方法得用类的指针来调用 - (NSString*) pathForImageURL:(NSString*)imageURL {   if ([imageURL hasPrefix:@"http://"] || [imageURL hasPrefix:@"https://"...
  • Python中self的解释

    万次阅读 多人点赞 2019-01-04 22:39:20
    首先我们要搞明白Python的类中为要什么要用到self这个单词呢,为什么不用&amp;quot;zhangsan&amp;quot;、&amp;quot;lisi&amp;quot;这样的名字呢,这可定有他的用意。查Google翻译解释: self 名词...
  • python里的email.py中那个self.get()到底是怎么运作的。 因为用self.get('subject')来抓主题,然后发现有的邮件抓不到主题。 但是邮件用记事本打开又看得到‘Subject:’,用outlook打开也看得到。 然后就看...
  • Self Attention 自注意力机制

    千次阅读 2020-03-09 18:20:02
    self attention是提出Transformer的论文《Attention is all you need》中提出的一种新的注意力机制,这篇博文仅聚焦于self attention,不谈transformer的其他机制。Self attention直观上与传统Seq2Seq attention机制...
  • Python中的self使用注意事项

    万次阅读 2018-08-16 17:36:09
    self的使用要点 1.Python中的self等同于Java中的this,表示当前对象,当前正在操作的对象,而不是当前类 2.某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的...
  • Swift3.0 Selfself的区别

    千次阅读 2017-01-17 22:23:10
    Swift Self关键字的用法
  • python def __init__(self, name等多参数), def __init__(self)

    万次阅读 多人点赞 2018-10-08 20:19:22
    __init__(self) 初始化,__new__实例化方法,两者执行的顺序,先有实例,才能初始化。 之前一直对__init__(self)里面的参数很迷茫,一会这个地方看到别人这么写,一会看到别人那么写,自己也不知道,到底怎么回事,...
  • DL之self-attention:self-attention自注意力机制的简介、应用之详细攻略 目录 self-attention的简介 1、self-attention的影响 2、self-attention模块思路的8个步骤及其代码实现 self-attention的应用...
  • DL之self-attention:self-attention自注意力机制模块思路的8个步骤及其代码实现 目录 代码实现 相关文章DL之Attention:Attention的简介、应用领域之详细攻略DL之self-attention:self-attention的简介...

空空如也

1 2 3 4 5 ... 20
收藏数 232,766
精华内容 93,106
关键字:

self