精华内容
下载资源
问答
  • Python-10】构造函数

    2019-05-11 15:29:50
    自己写构造函数 class FooBar: somevar= 0 def init(self): self.somevar = 100 ...在Python中,创建构造函数很容易,只需将方法 init 的名称从普通的 init 改为魔法版 __init__即可。 class FooBa...

    自己写构造函数

    class FooBar:
    	somevar= 0
        def  init(self):
            self.somevar = 100
    foo = FooBar()
    print(foo.somevar)
    100
    

    调用内置方法

    在Python中,创建构造函数很容易,只需将方法 init 的名称从普通的 init 改为魔法版 __init__即可。

    class FooBar:
        def __init__(self):
            self.somevar = 25
            
    foo = FooBar()
    print(foo.somevar)
    25
    

    超类的构造函数

    # 基类
    class Bird:
        def __init__(self):
            self.hungry = True
        def eat(self):
            if self.hungry:
                print('Aaaah ... nice')
                self.hungry = False
            else:
                print('No, thanks!')
    
    bird = Bird()
    bird.hungry
    bird.eat()
    # Aaaah ... nice
    
    # SongBird 类继承了 Bird  类
    class SongBird(Bird):
        def __init__(self):
            self.sound = 'Sing a song!'
        def sing(self):
            print(self.sound)
    songB = SongBird()
    songB.sing()
    
    # 超类调用基类的方法
    songB.eat()
    
    # 运行报错
    '''
    Sing a song!
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-107-800cd686db7a> in <module>
         10 
         11 # 超类调用基类的方法
    ---> 12 songB.eat()
    
    <ipython-input-105-3615908d8440> in eat(self)
          4         self.hungry = True
          5     def eat(self):
    ----> 6         if self.hungry:
          7             print('Aaaah ... nice')
          8             self.hungry = False
    
    AttributeError: 'SongBird' object has no attribute 'hungry'
    '''
    

    因为在SongBird 中重写了构造函数,但新的构造函数没有包含任何初始化属性 hungry 的代码。要消除这种错误, SongBird 的构造函数必须调用其超类( Bird )的构造函数,以确保基本的初始化得以执行。为此,有两种方法:调用未关联的超类构造函数,以及使用函数 super 。接下来的两节将介绍这两种方法。

    调用未关联的超类构造函数

    class SongBird(Bird):
        def __init__(self):
            Bird.__init__(self)
            self.sound = 'Sing a song!'
        def sing(self):
            print(self.sound)
    songB = SongBird()
    songB.sing()
    
    # 对实例调用方法时,方法的参数 self 将自动关联到实例(称为关联的方
    # 法),这样的示例你见过多个。然而,如果你通过类调用方法(如 Bird.__init__ ),就没有实例
    # 与其相关联。在这种情况下,你可随便设置参数 self 。这样的方法称为未关联的。
    

    使用函数 super

    class SongBird(Bird):
        def __init__(self):
            # Bird.__init__(self)
            super().__init__()
            self.sound = 'Sing a song!'
        def sing(self):
            print(self.sound)
    songB = SongBird()
    songB.sing()
    

    总结

    相比较直接对超类调用未关联的方法(Bird.init(self), 不是调用一个示例的方法,而是直接使用类名调用方法),使用函数super更直观。但这并非其唯一的优点。实际上,函数 super 很聪明,因此即便有多个超类,也只需调用函数 super 一次(条件是所有超类的构造函数也使用函数 super )。

    展开全文
  • Python笔记之构造函数__init__

    千次阅读 2018-10-21 20:33:35
    构造函数 __init__初学者看着很吓人,...在Python中,创建构造函数很简单,只需要将方法init的名称从普通的init改成魔法版的__init__即可。如示例1 #示例1 &gt;&gt;&gt; class My: ... def __init__(...

    构造函数

    __init__初学者看着很吓人,其实它就是一个初始化方法,只是命名为__init__。然而,构造函数不同于普通方法的地方就在于,将在对象创建后自动调用它们。

    在Python中,创建构造函数很简单,只需要将方法init的名称从普通的init改成魔法版的__init__即可。如示例1

    #示例1
    >>> class My:
    ...     def __init__(self):
    ...             self.number = 45
    ...
    >>> F = My()
    >>> F.number
    45

    构造函数中也可以添加参数,由于参数是可选的,所有你也可以指定这个参数具体如示例2

    #示例2
    >>> class My:
    ...     def __init__(self, value=45):
    ...             self.number = value
    ...
    >>> F = My()
    >>> F.number
    45
    >>> F = My(" this")
    >>> F.number
    ' this'

    编写构造函数

    现在,我们来创建一个实例来尝试编写一个构造函数。编写一个Person类。具体见示例3

    >>> class Person:
    ...     def __init__(self, name, job=None, pay=0):
    ...         self.name = name
    ...         self.job = job
    ...         self.pay = pay
    ...
    >>> bob = Person('Bob Smith')
    >>> sue = Person('Sue Jones', job='dev', pay=10000)
    >>> print(bob.name, bob.job, bob.pay)
    Bob Smith None 0
    >>> print(sue.name, sue.job, sue.pay)
    Sue Jones dev 10000
    
    #这里的bob对象针对job和pay接受了默认值,但是sue显式地提供了值。
    #注意在创建sue时是如何使用关键字参数的

    赋给实例属性第一个值的通常方法是,在__init__构造函数方法中将它们赋给self,构造函数方法包含每次创建一个实例的时候Python会自动运行代码。在OO术语中,self就是新创建的实例对象,而name, job, pay变成了状态信息,即保存在对象中供随后使用的描述性数据。

    关于构造函数的疑惑解答

    1. 为什么类方法函数中的第一个参数特殊?        类方法中函中的第一个参数之所以特殊,是因为它总是接受将方法调用视为隐含主体的实例对象,按照惯例,通常称为self。因为方法函数默认总是有这个隐含的主体对象环境,所以我们说这是”面向对象“,也就是设计用来处理或修改对象的。
    2. __init__方法是做什么用的?        如果类中编写了或者继承了__init__方法,每次类实例创建时,Python会自动调用它。这也称为构造函数。除了明确传入类的名称的任何参数外,还会隐性的传入新实例。这也是最常见的运算符重载方法。如果没有__init__方法,实例刚创建时就是一个简单的空的命名空间。
       
    3. 怎么创建实例?       你可以调用类名称来创建类实例。任何传给类名称的参数都要出现在__init__构造函数中第二和其后的参数。新的实例会记得创建它的类,从而可以实现继承目的。

     

    展开全文
  • 一、使用函数构建抽象 1.1 基本元素 程序必须为人类阅读而编写,...最简单语句就是赋值语句了,赋值语句执行作用就是负责将某个值和某个名字相关联,即“名称被绑定到了值上”,并将这种绑定存放在环境。而表

    一、使用函数构建抽象

    1.1 基本元素

    程序必须为人类阅读而编写,并且仅仅碰巧可以让机器执行

    编程语言都应该具有基本的元素,即表达式和语句,数据和函数是这两种基本元素的代表。有了基本元素之后,还要有合适的方式将他们进行组合以完成简单到复杂的构造。最后,可以对内容进行抽象,已完成复杂到简单的指代。

    首先要区分代码中的语句表达式,这两者分别负责执行某个操作或者计算某个值。最简单的语句就是赋值语句了,赋值语句的执行作用就是负责将某个值和某个名字相关联,即“名称被绑定到了值上”,并将这种绑定存放在环境中。而表达式则会计算出一个结果,最简单的表达式就是一个字面量或者一个环境中已有的名字。最常见以及最重要的表达式是调用表达式。表达式是递归的,就是说通过调用运算可以将表达式构造成更大的表达式。解释器会以递归的方式计算复杂表达式:深入到子表达中,直到遇到字面量或者变量名称,进行计算并向上返回。注意不同于表达式,语句不返回任何值。最后,解释器负责关联起这些东西:存储对象与名字之间的关联、计算表达式、执行语句。

    通过这些简单的基本元素,我们了解了编程语言是如何提供在本章开头时提到的基本能力的:(1)数值是内建数据,算数运算是函数。(2)嵌套提供了组合操作的手段。(3)名称到值的绑定提供了有限的抽象手段。但是这还远远不够,一个编程语言还需要更加强大的抽象技巧,即定义函数。定义函数可以将一个名称绑定到一个操作序列上,然后就可以将其作为一个整体来引用。

    函数中的一个重要概念是纯函数,纯函数具有一个特性:调用它们时除了返回一个值之外没有其它效果。而非纯函数除了返回一个值之外,会产生副作用,即改变解释器或计算机的一些状态。一个普遍的副作用就是在返回值之外生成额外的输出,比如打印一些内容到屏幕上。函数的可接受参数的描述叫做签名

    在有了定义函数的能力后,实际上我们也有了划分局部环境的能力,因为通常函数自身具有局部环境。那么,什么是环境?之前我们提到,环境可以简单的看做一块内存,用于将名字绑定到值(要注意值并不属于环境帧),这种概念实际上是环境的“帧”。不同粒度的环境帧会构成帧序列,或者说是帧“链”。赋值语句和导入语句会再最上面的环境帧中新增绑定。而函数定义语句同样会新增绑定————将函数名称绑定到函数自身。此时函数名会出现在两个地方,环境帧与函数自身中。考虑到不同的名字可能会绑定到同一个函数体,因此这种重复是有意义的。注意,通常环境中的函数名上绑定的是函数地址,函数地址处存放有函数具体代码。

    如果对Python的实现有所了解,可以知道,运行时环境和静态编译出的字节码对象其实是分别存放的,前者为PyFrameObject,后者为PyCodeObject,而PyFrameObject中会保存指向PyCodeObject的指针以及当前执行的字节码在PyCodeObject中的偏移。

    定义了函数的目的是为了使用,使用的方式是通过调用,调用步骤会先求出参数表达式,但是对计算好的实参上调用具名函数。这个调用就会产生一个局部帧并将该帧链入当前的环境帧链上,在新的局部帧上,将实参绑定到函数的形式参数上,然后在当前帧的开头以及全局帧的末尾求出函数体。对于局部环境中的名字对应的值为,最先发现该名称的帧中绑定到这个名称的值(这句话实际上有着很严重的误导性,考虑一下,名字搜索时真的会沿着帧链一层层的搜索吗?后面会详细说明这一点。)。更具体地说,局部帧中维护了指向其前驱的指针(通常是更大的局部帧或者全局帧),通过这种形式,帧序列表现为链表。

    函数自身拥有局部环境使得,函数的形参名称可以是任意的————局部名字的作用域被限制在定义它的函数的函数体中。当一个名称不能再被访问时,它就离开了作用域。

    1.2 高阶函数与作用域

    觉得已经掌握了吗?考虑这段代码(可以参考我的另一篇文章)。

    # 代码片1.2.1
    # 例子 0
    a = 1
    def f():
    	return a
    print(f())
    
    # 例子 1
    a = 1
    def f():
    	return a
    def g():
    	a = 2
    	return f()
    print(g()) # output: 1
    
    # 例子2
    def g():
        def f():
            return a
        a=2
        return f()
    a=1
    print(g()) # output:2
    

    总的来说,函数给了我们更强大的抽象能力,我们可以将操作序列抽象到函数背后而不去了解其实现,只需要确定其“合约”(参考《程序员修炼之道》)符合我们的要求即可。这种抽象可以称为函数式抽象。函数提供了我们使用一个名字指代一段操作的能力,因此,我们要遵守 DRY 原则(同样参考《程序员修炼之道》),当你在复制粘贴的时候,你脑子中的“DRY警报”应该响起并提示你:“应该抽象了”。

    函数的强大还不止于此,因为一个函数可以作为另一个函数的返回值或者参数,这种方式允许我们以层次化的方式对复杂的逻辑进行多次抽象。另外,函数内部还可以嵌套的定义函数。在函数内使用def语句定义函数,此时函数名绑定在函数的局部帧中。回想一下,在代码片1.2.1的例子0中,直接执行f,输出 1 ,没有任何问题。调用函数,会创建新的栈帧,当需要查找名字的时候在局部环境中找不到,然后便会找前一个帧,找到a,并输出。那么例子 1 中按理说,进入到f后,局部执行环境中没有a,会向上找,然后再g的局部环境中会找到a,然后应该输出2呀?这个问题的原因在于,在Python中,一个名字绑定在程序正文的某个位置是否起作用,是由该名字在文本中的位置唯一决定的,而不是运行时动态决定的。因此Python的作用域是静态作用域,也称为词法作用域

    名字空间就是与作用域对应的动态的东西,作用域可以认为就是一段代码的范围,作用域在Python运行时就会转化为名字空间。因此对于例子1中的 f 函数,由于其定义在全局空间内而不是嵌套定义,因此其作用域规则为LGB规则。而在例子2中我们使用了嵌套定义函数,内层定义的函数与其“直接外围作用域”被捆绑到一起,因此即使我们把代码中函数g的返回值改为return f,然后执行g的返回值,结果依然不变,这就是所谓的闭包。

    对于词法作用域:

    • 局部函数的名称并不影响定义所在函数外部的名称,因为局部函数的名称绑定到了定义处的当前局部环境中,而不是全局环境。
    • 局部函数可以访问外层函数的环境。这是因为局部函数的函数体的求值环境扩展于定义处的求值环境。

    这种方式使得内部函数会额外绑定一些信息,即定义处的直接外围局部环境的数据。因此,带有词法作用域的编程语言的一个重要特性就是,嵌套定义函数在它们返回时仍旧持有所关联的环境。前面我们讨论过纯函数,但是闭包可能对导致以相同参数多次调用闭包却得到不同的结果,那闭包是纯函数吗?它们仍旧是纯函数,因为它们并不允许修改任何在局部环境帧之外的东西。

    最后,再多说一点所谓的“最内嵌套作用域规则”。看一下代码片1.2.2,预测一下结果是怎样的?运行的话会提示函数g中的第一个print语句出错“local variable ‘a’ referenced before assignment”。怎么f中运行没问题,到了g中就有问题了?

    # 代码片1.2.2
    a = 1
    def f():
        print(a)
    
    def g():
        # global a
        print(a)
        a=2
        print(a)
    
    f()
    g()
    

    要回答这个原因,就需要再逐字逐句的看一下作用域规则:由一个赋值语句引起的名字在这个赋值语句所在的作用域内是可见的。在g中的a=2这一句话对于其所在的整个作用域都是有影响的,因此第一个print知道自己的局部空间中有a这个变量,但是a却是在自己的后面定义的,所以会上面的报错。

    如果有兴趣可以使用dis.dis看一下下面的代码中,函数f和函数g生成的字节码就会发现,二者对于变量a的查找使用了不同的字节码指令,前者是LOAD_GLOBAL,而后者是LOAD_FAST。这就意味着通过作用域的静态信息,函数知道a是局部空间中的变量,因此直接使用LOAD_FAST,但是只有在运行时才会发现在该条语句执行失败,这意味着对于该变量,python在编译时就已经知道了名字应该到哪里去搜索。

    因此我们此时对nonlocalglobal关键字的理解就更深入一层了,可以知道这两个关键字的本质是控制名字引用使用的字节码指令。我们可以做实验看一下是不是这样的,把代码片1.2.2中的放到一个单独的文件中,使用compile函数编译出code对象,然后执行import dis;dis.dis(code.co_consts[3])来查看函数g的代码编译出的字节码。可以发现对变量a的查找指令从LOAD_GLOBAL变成了LOAD_FAST,后者会查找代码函数栈帧的静态变量区,而前者会查找栈帧对象的global和buildin字典中依次查询。

    我们发现,python中的函数具有十分灵活的使用方式,这是因为,python将函数视为“一等公民”。通常,编程语言会限制操作计算元素的途径。带有最少限制的元素被称为具有一等地位。一些一等元素的“权利和特权”是:

    1. 它们可以绑定到名称。
    2. 它们可以作为参数向函数传递。
    3. 它们可以作为函数的返回值返回。
    4. 它们可以包含在数据结构中。

    二、python虚拟机中的函数机制

    写这一章之前,几个问题很是困扰了我。

    第一是,上面代码片1.2.2中函数g体现的行为是,运行时直接在快速区进行查找,查找失败就是失败了,那么沿着作用域链向上查找的这种行为是在哪里出现的。是在编译字节码的时候出现的吗?如果是的话,可以说通函数f中对a的查找直接使用了LOAD_GLOBAL,而不是从局部开始查找。但是又可以看到LOAD_NAME中是有LGB规则的,具体见《python源码剖析》P167,这到底是咋回事?而且注意到LOAD_GLOBAL字节码中也有GB规则。目前的猜测是对于函数的静态信息使用快速查找,其他的情况使用LGB规则。那又有一个问题,LOAD_NAME中是只可以发现LGB规则的,LEGB中的E又是怎么实现的?

    第二是就是函数的调用栈与函数的作用域链的关系是什么,这两个概念我似乎有些混淆。我想了下面这个代码帮助清晰的展示这个问题。

    import sys
    from functools import wraps
    
    def show_frame(func):
        @wraps(func)
        def wrapped(*args, **kwargs):
            # print current frame chain
            f = sys._getframe()
            print("\n>"+"="*20, func.__name__)
            while f:
                print(f.f_code.co_name, end=" -> ")
                f = f.f_back
            print()
            print("="*20+"<\n")
            return func(*args, **kwargs)
        return wrapped
    
    a = 1
    
    @show_frame
    def g(n):
        if n < 3: # 3是随便选的,只是为了让该函数递归的调用多次
            g(n+1)
        else:
            print(a)
    
    def f():
        a = 2
        g(1)
    
    f()
    

    运行f之后可以发现,g函数在打印出变量a的值的时候,环境栈帧中已经压了三个g的不同参数的调用。然而根据我的理解,函数中对于a的查找过程应该是这个调用链的深度无关的,应该是在local作用域中找不到该变量的绑定之后,直接到global作用域中去查找,而不是穿过栈帧链中的三个g函数的调用到全局环境中找到变量a,那么名字空间是怎么实现的呢?

    后面咱们就带着这几个问题来看函数对象。

    1. 函数对象

    typedef struct {
        PyObject_HEAD
        PyObject *func_code;    /* 函数代码编译后的 PyCodeObject 对象 */
        PyObject *func_globals; /* global名字空间 */
        PyObject *func_defaults;    /* 默认参数(NULL or tuple) */
        PyObject *func_closure; /* NULL or a tuple of cell objects */
        PyObject *func_doc;     /* The __doc__ attribute, 是PyStringObject */
        PyObject *func_name;    /* The __name__ attribute, 是PyStringObject  */
        PyObject *func_dict;    /* The __dict__ attribute, a dict or NULL */
        PyObject *func_weakreflist; /* List of weak references */
        PyObject *func_module;  /* The __module__ attribute, can be anything */
    } PyFunctionObject;
    

    其中函数的代码段会编译为一个PyCodeObject对象,这个对象是对 python 源码的静态反映,但是不是说这个对象里面就是一行行的代码而别无他物。这个对象会保存可以从代码中获得的静态信息,比如常量表co_const、符号表co_names以及编译好的字节码序列co_code。关于这个对象可以参考前面讲PyCodeObject的文章,这里简单的复习一下:字节码对象是代码编译的结果,是静态分析得到的信息,常量表和符号表都是元组,存放了这块Code Block内出现过的常量与名字,没有任何的绑定信息,因此名字空间肯定不在这里。而PyFunctionObject是一个函数运行时产生的动态对象,是在执行def子句的时候创建的。这个对象通过保存PyCodeObject来获得函数的静态信息。除此之外,PyFunctionObject还会保存函数执行时的动态信息,比如func_globalsfunc_closure。因为global作用域中的符号和值的对应关系一定是运行时才能知道,因此这部分必须要运行时动态创建。因此,一段python函数,其PyCodeObject是唯一的,而PyFunctionObject对象可能有多个,每次调用都会生成一个,并保存指向那个唯一的PyCodeObject的指针。

    在上面看到func_globalsfunc_closure时,心中一抖!(哎?这个好像和名字空间有关?)的确,这两个字段与名字空间是有关系的,但不是真正的名字空间,具体原因是在这里简单提一句:名字空间是存放在Frame中的,这两个字段是负责给Frame传递内容的“信使”,而不是真正的负责人。

    在函数定义的时候,会将当前的global放到函数的global中,然后在函数被调用的时候,函数对象中的global又会用于新的栈帧的global的初始化。思考一下,函数是允许嵌套的,那函数自身的名字应该是在global中的,是什么时候放进去的呢?定义函数是通过MAKE_FUNCTION指令做的,然后这个函数对象会在栈顶,然后要通过STORE_NAME把函数名和函数对象放到当前的local环境中,而全局函数的localglobal是一个字典对象,因此STORE_NAME把当前函数名放到local环境的同事也就放到了global环境中,再通过函数对象对global环境的传递功能,函数内部就也可以使用自己的名字了。那如果是非全局函数呢?内部嵌套函数的名字的确在其自身的LGB环境中都找不到,这个就涉及到闭包了,比较复杂,我也还有点乱,就不在这里写了。

    第二个问题差不多可以解答了,LGB名字空间都是存在于每一个Frame内的,不用沿着栈帧往回搜索。函数在定义的时候会打包当前的global空间,等到被执行的时候在传递给新的帧。而buildin空间应该是共享的,local空间在新建的栈帧中应该为空。但是函数的局部变量怎么办?这个是放在frame的静态堆栈中,因为局部变量以及位置参数是一开始就可以确定个数的,因此是可以静态处理的。看python的源码,在ceval.c文件中,LOAD_FASTSTORE_FAST就是处理这种“快速局部变量”,他们会操作frame栈帧中localplus指向的部分。也就是说,frame的栈一部分是用于计算的,一部分是用来存储数据的,二者虽然形式上是一段连续的内存,一衣带水,但是永远是互不相见,“白天不懂夜的黑”的。

    第二个问题解决了,那第一个问题呢?LGB规则什么时候发生的?LEGB规则又是什么时候发生的?

    首先这个问题我现在没有明确的答案,不过我的猜测是,在全局空间内,LGB规则体现在LOAD_NAME字节码指令中,在函数的局部栈帧内,L规则被LOAD_FAST取代,不会使用LGB规则查找名字,而是静态的在localplus栈的指定位置读取,而GB规则还在,体现在LOAD_GLOBAL中。至于LEGB呢,要更细的说一下。

    E是闭包,在python中闭包就要用到嵌套函数。嵌套函数的静态得到的code对象中,co_cellvarsco_freevars是和闭包相关的,前者保存嵌套的作用域中使用的变量名,后者保存使用到的外层作用域中的变量名。而在frame对象中,和闭包有关的属性是f_localsplus。没错,又是这个老铁。这段内存实际上属于四个部分,运行时栈、局部变量(包括位置参数)、cell对象和free对象。

    和局部变量自身直接存在localplus中不同,cell变量是以PyCellObject对象的形式存在localplus中的,cell对象被指就是一个指针的封装,静态分析的时候只能知道这里有一个变量用到了外面的变量,但是不知道具体值是什么,就将一个cell放到静态数据区(localplus)的指定位置,等到外层的变量所在行运行的时候再通过STORE_DEREF指令,让cell对象指向外层的值。

    在内层嵌套函数的def语句执行的时候,会将通过LOAD_CLOSURE指令将外层的cel对象取出,封装到内层函数的function对象中。此时在内层函数完成定义时的状态时,外层的函数是运行时,拥有自己的栈帧,该栈帧的local空间中有一个函数对象,函数对象中的func_closure属性指向了当前栈帧中的其他变量。

    而当内层函数执行的时候,通过PyEval_EvalCodeEx函数,会将cell对象逐个拷贝到localplus中的指定位置(即freevars)。这就是闭包的基本原理。

    因此,对于全局函数,LGB规则的L体现在localplus静态区中,而对于内层嵌套函数,LEGB规则的LE都体现在localplus静态区中。这也就可以解答我们在本节开始提出的第一个问题。


    参考

    轻松7步,导出Y结合子
    Python进阶之路:operator模块
    SICP 第一章
    Python源码剖析 第十一章
    python中的函数式编程
    Python函数式编程指南(4):生成器
    Python源码剖析笔记6-函数机制
    深入理解python之函数系统
    python开启尾递归优化
    深入理解python之函数系统
    Python 中的作用域准则

    展开全文
  • python构造/析构函数

    千次阅读 2011-06-27 16:37:00
     Python中所有的类成员(包括数据成员)都是 公共的 ,所有的方法都是 有效的 。只有一个例外:如果你使用的数据成员名称以 双下划线前缀 比如__privatevar,Python的名称管理体系会有效地把它作为私有变量。这样就...

    python用__init__ 和 __del__ 作为构造和析构函数,标新立异?

     

    Python中所有的类成员(包括数据成员)都是 公共的 ,所有的方法都是 有效的
    只有一个例外:如果你使用的数据成员名称以 双下划线前缀 比如__privatevar ,Python的名称管理体系会有效地把它作为私有变量。
    这样就有一个惯例,如果某个变量只想在类或对象中使用,就应该以单下划线前缀。而其他的名称都将作为公共的,可以被其他类/对象使用。记住这只是一个惯例,并不是Python所要求的(与双下划线前缀不同)。

    展开全文
  • Python中的魔法函数

    2020-11-25 21:20:16
    函数名称构造函数:init() 函数使用:使用类创建对象时自动调用,如果不显示写出的构造函数,默认会自动添加一个空的构造函数,内置pass语句 self代表类实例,而不是类本身 哪个对象调用方法,那么该方法中的...
  • 构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。类似于 Python的 __init__() 函数。 1.1 声明和实现构造函数 通过下面示例理解构造...
  • 1、super()函数做什么用? super 用于继承父类方法、属性,使用 super 可以提高代码复用性、和可维护性, 是用来解决多重继承问题,直接用类名...如果子类定义构造函数,那么在子类的构造函数中,调用父类
  • 如果名称表示作为函数对象有效类属性,则通过将实例对象和刚在抽象对象一起找到的函数对象打包(指向)来创建方法对象:这是方法对象。当使用实参列表调用方法对象时,将从实例对象和实参列表构造一个新实参...
  • python自定义函数

    2021-03-18 15:07:47
    Python中有一种自定义函数为匿名函数,可以用lambda关键字定义。通过lambda构造的函数可以没有名称,最大特点是在自定义匿名函数时所有代码只能在一行内完成,语法如下: lambda parameters : function_...
  • python函数

    2019-07-22 19:24:18
    函数 ‘’’ print(‘zhangtao’) print(‘zhang’) ...- 定义函数的语法格式 def 函数名称 (): def代表函数的关键字 - 操作函数 例如:给函数赋值、给函数定义变量、常量等 调用函数必须有 - 作用:...
  • Python-类的构造

    2020-11-23 14:14:29
    在这个方法的名称中,开头和末尾各有两个下划线,这是一种约定,旨在避免Python默认方法与普通方法发生名称冲突。 #类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它...
  • 受保护封装是将对象成员进行一定级别封装,然后在类或者子类中都可以访问,但外部不可以 封装方法: 在成员名称前添加一个下划线即可 公开,公共 public 公共封装实际对成员没有任何操作,任何地方...
  • __init__ :可以定义一个对象初始化操作,但是,__init__并不是第一个被自动调用函数,实际上,还有一个 __new__, 两个函数构成了“构造函数” # 1. 只定义init class Check1: # 构造函数 # 1.init:self...
  • Python中,有些名称很特别,开头和结尾都是两个下划线。如__future__。这样的拼写表示名称有特殊意义,因此绝不要在程序中创建这样的名称。在这样的名称中,很大一部分都是魔法(特殊)方法的名称。如果你的对象...
  • Python中所有类成员(包括数据成员)都是 公共 ,所有方法都是 有效.可在其它类中使用. 若变量名称为双下划线前缀,则为私有变量.如 __private,可以只在类 或 函数中使用,有效. __init__在类中被用做构造...
  • Python内建函数(F)

    2013-08-02 11:47:03
    说明:file类型的构造函数,作用为打开一个文件,如果文件不存在且mode为写或追加时,文件将被创建。添加‘b’到mode参数,将对文件以二进制形式操作。添加‘+’到mode参数,将允许对文件同时进行读写操作。 ...
  • Python中没有专门定义结构体方法,但可以使用class标记定义类来代替结构体,其成员可以在构造函数__init__中定义,具体方法如下。 复制代码 代码如下:class item: def __init__(self): self.name = ” # 名称 ...
  • 如果类编写了或继承了__init__方法,每次类实例创建时,Python会自动调用它,这被称为构造函数。除了明确传入类的名称的任何参数外,还会隐性的传入新实例。 任何传给类名称的参数都要出现在__init__构造函数中第...
  • Python中class简单介绍

    千次阅读 2018-01-22 11:15:13
    _ init _ 构造函数:初始化对象 _ del_ 析构函数:销毁对象 定义类的成员函数时,必须默认一个变量代表类定义的对象本身,这个变量的名称可自行定义,下面的程序使用self变量表示类对象的变量 Python-class简单...
  • Python中的重载方法

    千次阅读 2017-08-08 13:52:41
    在类,对内置对象(例如:整数和列表)所能做事,几乎都有相应特殊名称的重载方法。最常见就是重载类的构造函数(__init__函数) 方法 重构 调用 __init__ 构造函数 对象...
  • Python中初始化对象方法 Python中的对象包括以下几个部分 id(identity识别码) type(对象类型) value(对象值) (1)属性 (2)方法 构造方法_init_()用于执行“实例对象初始化工作”,及对象创建后,...
  • 类的方法与普通的函数只有一个特别的区别:它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self,在实际调用过程,self可不用不用传入相应的参数 未对类进行实例化: 类的函数方法,第一个参数必须是...
  • Python 类和实例通俗讲解

    千次阅读 多人点赞 2016-10-12 11:59:23
    这篇文章是我看到讲解Python类与实例文章比较通俗易懂,因此我将其转载过来,供大家共同学习!...接下来,一般都要编写构造函数,在写这个函数之前,先解释一下什么是构造函数。class Per
  • 我们了解到,模块是包含Python语句和定义(如函数和类定义)文件。...包是通过使用“点分模块名称”来构造Python模块名称空间一种方式。AB代表名为A程序包名为B子模块。两个不同程序包(如P1和P2...
  • Java中也叫静态变量都有构造函数都有实例方法异语法写时候Python class名称后面带(),而Java声明类需要指定类类型java中实例变量需要声明,而Python中不用声明直接在构造函数中用self.name指定就可以了...
  • 这篇文章主要介绍了python中class定义及使用,本文通过实例代码给大家介绍非常详细,具有一定参考借鉴价值,需要朋友可以参考下。 类定义 class classname[(父类名)]: – 成员函数及成员变量 _ init _ ...
  • JAVA和Python的异同

    2018-09-06 16:11:00
    JAVA和Python异同 ...java中实例变量需要声明,而Python中不用声明直接在构造函数中用self.name指定就可以了 python貌似没有类方法 声明一个对象时候Java 在声明一个新对象时候,先执行类变量加...
  • python中魔法属性和魔法方法

    千次阅读 2015-10-11 18:13:30
     在python总,有的名称会在前面和后面都加上两个下划线,例如__future__、__init__、__del__以及__new__等等,这些特殊的名称,在python中就称为魔法方法或魔法属性。  例如:  (1)__new__ 是创建类的对象的...
  • 简单的python GUI例子,写一个简单界面

    万次阅读 多人点赞 2019-04-16 20:05:25
    写一个简单界面很容易,即使是什么都不了解情况下,这个文本转载了最简单界面编写,下个文本介绍了TK简单但具体应用 ...而Tk()是一个Tkinter库之中的函数(其实是类的构造函数,构造...

空空如也

空空如也

1 2 3 4 5 ... 8
收藏数 151
精华内容 60
关键字:

python中构造函数的名称

python 订阅