• python中函数参数


    默认参数注意点

    优点:灵活,当没有指定与形参对应的实参时就会使用默认参数

    缺陷:

    例子:

    >>> def h(m, l=[]):                    #默认参数时列表,可变对象

    ... l.append(m)

    ... print id(l)

    ... return l

    ...

    >>> h(1)

    140373466854392

    [1]

    >>> h(2)

    140373466854392                    #在多次调用的过程中l的id并没有变换

    [1, 2]                                #意外的结果[1,2]

    关于默认参数,文档中是这样说的:

    Default parameter values are evaluated when the function definition is executed. This means that the expression is evaluated once, when the function is defined, and that the same "pre-computed" value is used for each call.

    大概意思:但解释器执行函数定义时,默认参数值也被计算了,这也意味着默认参数里的表达式只是被执行了一次,而且每次调用都是用同样的上面预先计算的值

     

      所以上面的例子就很容易理解,list在函数定义的时候,就被定义好了,函数的多次调用,都在用一个list

    怎么理解

    实际上,函数就是一个对象;当python执行def语句时,它会根据编译好的函数体字节码和命名空间等信息新建这个对象,并且会计算默认参数的值。函数的所有构成要素均可通过它的属性来访问,比如可以用func_name属性来查看函数的名称。所有默认参数值则存储在函数对象的__defaults__属性中,它的值为一个列表,列表中每一个元素均为一个默认参数的值

    >>> dir(h)

    ['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']

    >>> h.__defaults__

    ([1, 2],)

    >>> h(3)

    140373466854392

    [1, 2, 3]

    >>> h.__defaults__

    ([1, 2, 3],)

     

    解决办法:动态生成对象,在定义的时候使用None对象做占位符;

    前面的例子可以改写成:

    >>> def h(a,l=None):

    ... if l is None:

    ... l=[]

    ... l.append(a)

    ... print id(l)

    ... return l

    ...

    >>> h(1)

    140373466854392

    [1]

    >>> h(2)

    140373466843904

    [2]

    >>> h(2,[1,2])

    140373466854392

    [1, 2, 2]

     

    再一个例子:实时返回系统

    >>> def t1(when = time.time()):    #默认参数在函数定义的时候就被执

    ... time.sleep(1)                            行了,且多次调用都在使用同一个

    ... return when

    >>> def t2(when = time.time):                #默认参数只是对象

    ... time.sleep(1)

    ... return when

    >>> a1=t1()

    1448022680.552696

    >>> a2=t2()

    <built-in function time>

    >>> a2()

    1448022764.78878

    >>> a2()

    1448022767.4640501

    1448022790.4568429

     

    变长参数    

    使用方法:

    *args 表示任何多个无名参数,它被封装在一个tuple

        >>> def f(*a):

    ... return sum(a)

    ...

    >>> f(1,2,3)

    6

    **kwargs表示关键字参数,它被封装一个dict

        >>> def b(**kw):

    ... for i,v in kw.items():

    ... print 'key={0}, value={1}'.format(i,v)

    ...

    >>> b(n=2, name='wxl')

    key=name, value=wxl

    key=n, value=2

    args和kwargs可以随意命名。*args 要在**kwargs前面使用,否则语法错误

    适合变长参数场景:

    1. 修饰器中的使用:比如在django中使用@login_req来规定用户必须在登录状态下才能使用该函数,而修饰函数有很多,参数不同,所以变长函数很好解决问题

      def login_req(main):

      def required(request,*args,**kwargs):

      if not request.session.get('is_login', None):

      return redirect('/login/')

      else:

      return main(request,*args,**kwargs)

      return required

       

      @login_req

      def index(request):

                  return render_to_response("index.html")

    2. 参数的数目不确定,如读取配置文件test.cfg、做全局变量等:

      >>> from ConfigParser import ConfigParser

      >>> conf= ConfigParser()

      >>> conf.read('test.cfg')

      ['test.cfg']

      >>> conf.items('params')

      [('name', 'wxl'), ('age', '21'), ('height', '180')]

      >>> dict(conf.items('params'))

      {'age': '21', 'name': 'wxl', 'height': '180'}

    3. 当子类调用父类的某些方法,这种如果改变父类程序时,子程序可以不改动

      >>> class Super( object ):

      ... def __init__( self, this, that ):

      ... self.this = this

      ... self.that = that

      ...

      >>> class Sub( Super ):

      ... def __init__( self, myStuff, *args, **kw ):

      ... super( Sub, self ).__init__( *args, **kw )

      ... self.myStuff= myStuff

    函数传参既不是传值也不是传引用,而是传对象

        与c语言不同的是,python赋值的方式是引用

         >>> a=5;

      >>> b=a

    >>> id(a)

    35365592

    >>> id(b)

    35365592

    >>> b=7

    >>> id(b)

    35365544

    上面赋值a的操作实际上是将a指向5所在的内存地址

    b=a     b相当与a的别名,同样也指向5所在的内存地址

    b=7 相当于申请了一块存放有7的内存空间,再把b指向7所在的内存空间

    所以python函数中,函数参数在传递的过程中是将整个对象传入,对于可变对象的修改在函数外部及函数内部都可见,调用函数和被调函数之间共享这个对象,

    而对于不可变对象,由于并不能真正地被修改,因此,修改通常通过新建对象然后赋值指向来实现

  • 相关阅读:
    关于CSS/Grid Layout实例的理解
    关于对CSS position的理解
    接上一条博客
    搬迁声明
    自动化测试流程
    浏览器测试app-H5页面使用appium实现自动化
    RSA加密算法坑:pyasn1-error-when-reading-a-pem-string
    parameter/argument, Attribute/Property区别
    本地mysql用Navicat链接报错 Authentication plugin 'caching_sha2_password' cannot be loaded
    mysql安装忘记root密码,初始化密码
  • 原文地址:https://www.cnblogs.com/wxl-dede/p/4989427.html
Copyright © 2020-2023  润新知