• Python魔术师--self


                          (原文是 Python's Magical Self ,来自 http://concentricsky.com )

                 Python的self參数有时真让人抓狂。比方,你必须在每个类的方法里显示定义self,然后,它会霸占不须要它们的地方。

                

    class Foo(object):
        x = 9
        def __init__(self,x):
            self.x = x
     
        def bar(self,y):
            return self.x + y

                假设你有C++,Java或其它语言的编程背景,你会认为 __init__ 和 bar 方法里的self 看起来非常多余,python不是常常吹嘘自己的简答和优雅吗。self究竟有什么用?

    作用域出现了

               在python里,作用域是非常easy的。Python里的一切都是对象,差点儿不论什么东西都是在对象水平的作用域里。写一个模块试试?

    # test.py
    def say_hi():
        print 'Hi!'

              你刚刚创建了一个新的带有say_hi属性的模块对象。

              定义一个类?

    class Foo(object):
        x = 9
        def __init__(self,x):
            self.x = x
     
        def bar(self,y):
            return self.x + y

             你刚刚写了一个带有一些属性的类对象,那些属性是 x。__init__ 。还有 bar。

             实例化Foo?

    foo = Foo(5)

             你创建了一个带有属性x,__init__ ,和bar的Foo 实例,请记住,foo的三个属性跟Foo的不一样。待会,你就会知道为什么。

    上下文就是一切

             把Foo拆开:

    def bar(self,y):
        return self.x + y
     
    class Foo(object):
        x = 9
        def __init__(self,x):
            self.x = x
        bar = bar

             先不理bar的第一參数self,假设我们单单把bar看作普通的函数,那么,接下来的就非常合理了。

    foo = Foo(5)
     
    print bar(foo,4) == 9
    print bar(Foo,0) == 9
             好像Foo.bar也能够这么做。

    print Foo.bar(foo,4) == 9
    print Foo.bar(Foo,0) == 9

            第一行打印出结果True,但第二行就出现了类型错误TypeError):未绑定的方法bar必须用Foo实例作为第一个參数(出现了不匹配的类型对象)。实例化一个Foo,而且改动bar。把self參数隐藏掉。

    print foo.bar(foo,4) == 9
    print foo.bar(foo,0) == 9
            两行代码都出现 类型错误(TypeError):bar() 须要两个參数(出现了3个)。

    为什么是2个。而不是3个?答案即将揭晓。

    绑定self

            假设你查一下三个bar的类型。你会发现。他们不全都一样。

    print type(bar)
    # <type 'function'>
    print type(Foo.bar)
    # <type 'instancemethod'>
    print type(foo.bar)
    # <type 'instancemethod'>
            把不论什么函数绑定到一个实例方法对象里,并把它封装在一个实例方法对象里。实例方法就会像胶水一样,粘着类、实例对象和原始的函数。终于它们都绑在一起。


    print Foo.bar.im_class == Foo
    print Foo.bar.im_func == bar
    print Foo.bar.im_self == None
    print foo.bar.im_class == Foo
    print foo.bar.im_func == bar
    print foo.bar.im_self == foo

            能够直截了当地用python写一个实例方法类。

    class myinstancemethod(object):
        def __init__(self,func,cls,instance=None):
            self.im_func = func
            self.im_class = cls
            self.im_self = instance
     
        def __call__(_self,*args,**kwargs):
            args = list(args)
            if _self.im_self is not None:
                args.insert(0,_self.im_self)
                 
            if len(args) == 0:
                raise TypeError("unbound method bar() must be called with Foo instance as first argument (got nothing instead)")
            elif not isinstance(args[0],_self.im_class):
                raise TypeError("unbound method bar() must be called with Foo instance as first argument (got %s instead)" % type(args[0]).__name__)
            else:
                return _self.im_func(*args,**kwargs)

              myinstancemethod 非常正确地模仿了实例方法类。它跟前面的foo.bar 和Foo.bar的表现一样,除了它处理了一点类边缘情况和实例方法调用。

    my_unbound(self=foo,y=4)
    # TypeError: bar() got multiple values for keyword argument 'self'
    Foo.bar(self=foo,y=4)
    # TypeError: bar() got multiple values for keyword argument 'self'
     
    my_bound(self=foo,y=4)
    # TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)
    foo.bar(self=foo,y=4)
    # TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)
    

               这就是为什么你能够传入bar的引用,而不是传入foo,然后调用foo.bar。

    闭包

               foo 是一个与Foo全然不同的野兽。Python里的任一个变量都是内存里对象的引用——对象之间都没什么不同。

    Foo.x。Foo.__init__ 和 Foo.bar这三个与foo.x。foo.__Init__, 和foo.bar不同,他们都指向不同的内存空间。

    print Foo.x is not foo.x
    print Foo.__init__ is not foo.__init__
    print Foo.bar is not foo.bar

               Foo 和foo 是全然不相关的实体,它们仅仅是碰巧在适当的时候相互引用对方。












      


  • 相关阅读:
    map映射的用法
    相似的字串(hash+二分)
    进制 /字符串 hash
    CF#632 C.Eugene and an array
    2020牛客寒假算法基础集训营6 H-云
    Educational Codeforces Round 80 (Div. 2)
    Codeforces Round #601 (Div. 2)补题
    luogu-单调队列/单调栈专题
    Comet OJ
    Comet OJ
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10799081.html
  • Copyright © 2020-2023  润新知