The result of tag: (5 results)

Python中的默认参数

by LauCyun Jan 14,2016 17:27:02 3,842 views

Ps:前面《Python中的“小震撼”:变化的默认参数》文章中引用了本文,所以特此翻译分享给大家。

对Python默认参数值的处理方法是少有的几个容易使大多数新手Python程序员犯错的地方之一(通常只犯一次)。

导致困惑的地方是当你使用“可变”对象作为(参数的)默认值时的(程序)行为。(可变)也就是说值可以原地修改,例如:列表或字典。

先举个栗子:

>>> def function(data=[]):
...     data.append(1)
...     return data
...
>>> function()
[1]
>>> function()
[1, 1]
>>> function()
[1, 1, 1]
>>>

正如你看到的那样,列表变得越来越长。如果你查看列表的标识符,你会发现函数实际上总是返回同一个对象。

>>> id(function())
48163848L
>>> id(function())
48163848L
>>> id(function())
48163848L
>>>

原因很简单:函数在每次调用时总是使用同一个对象。我们做的修改行为是“粘性”。

 

为什么会这样?

属于函数定义的默认参数值,当且仅当def语句执行时求值。请看:

http://docs.python.org/ref/function.html (链接过期)

语言参考中的相关章节。

要注意Python中的def语句是可执行的,而且默认参数是在def语句的环境下求值的。如果def语句执行了多次,那么它每次将产生新的函数对象(对象会带着全新的默认值)。下面我们会看到这样的栗子的。

 

那要怎么做?

迂回方法是,就像其他人已经提到了的,使用占位符值来替代默认值。None是一个常用的值:

def myfunc(value=None):
    if value is None:
        value = []
    # modify value here

如果你需要处理任意对象(包括None),你可以使用哨兵对象:

sentinel = object()

def myfunc(value=sentinel):
    if value is sentinel:
        value = expression
    # use/modify value here

在很早以前,即在“object”对象引入之前,有时你会看到像下面这样的代码:

sentinel = ['placeholder']

这个代码用于创建一个具有唯一ID的对象;这对中括号([])在每次执行时产生新的列表。

 

对可变默认参数的合法(合理)使用

最后,要提到很多高级的Python代码经常使用这个机制的好处。例如,假设你要在一个循环里创建了一堆UI按钮,而你可能会使用像下面这样的代码:

for i in range(10):
    def callback():
        print "clicked button", i
    UI.Button("button %s" % i, callback)

这样你会发现所有的回调函数都打印出相同的值(在这个情况下,很可能是9)。原因是Python的嵌套作用域是绑定到变量的,而不是绑定到对象值的。所以所有的回调函数实例将会看到当前(也是最后)的变量“i”的值。为了修正这个问题,使用下面的代码:

for i in range(10):
    def callback(i=i):
        print "clicked button", i
    UI.Button("button %s" % i, callback)

那个“i=i”的步伐将绑定参数“i”(一个局部变量)到当前的外部变量“i”的值。

两个其他的例子使用的是局部缓存:

def calculate(a, b, c, memo={}):
    try:
        value = memo[a, b, c] # return already calculated value
    except KeyError:
        value = heavy_calculation(a, b, c)
        memo[a, b, c] = value # update the memo dictionary
    return value

(这对某些递归算法很好)

另一个例子,对应高度优化的代码,对全局名字的局部重新绑定:

import math

def this_one_must_be_fast(x, sin=math.sin, cos=math.cos):
    ...

 

这是怎么工作的?

当Python执行def语句时,它使用一些已有的东西(包括编译了的函数体的代码和当前的名字空间),然后创建出一个新的函数对象。当它做这个的时候,默认值也会被求值。

这些各种各样的组件也能作为函数对象的属性而访问。使用我们先前定义过的函数:

>>> function.func_name
'function'
>>> function.func_code
<code object function at 00BEC770, file "<stdin>", line 1>
>>> function.func_defaults
([1, 1, 1],)
>>> function.func_globals
{'function': <function function at 0x00BF1C30>,
'__builtins__': <module '__builtin__' (built-in)>,
'__name__': '__main__', '__doc__': None}

由于你可以访问它们,因而你也可以修改它们:

>>> function.func_defaults[0][:] = []
>>> function()
[1]
>>> function.func_defaults
([1],)

当然,这可不是我推荐的正常使用方法。

另一个重置默认值的方法就是简单的重新执行一下那个相同的def语句。Python会重新创建一个新的到这个代码对象绑定,重新计算默认值,然后将这个函数对象赋值给同以前一样的那个变量。但是要着重指出,请在你确切知道你在做什么的时候才能这么做。

最后,如果你刚好有函数各个部分,而不是函数本身,你可以使用new模块中的function类来创建你自己的函数对象。

 

本文翻译于Default Parameter Values in Python

(全文完)

...

Tags Read More


Python中的“小震撼”:变化的默认参数

by LauCyun Jan 12,2016 17:21:47 4,233 views

许多使用很长时间Python的人也被下面的问题困扰:

def foo(a=[]):
    a.append(5)
    return a

Python新手估计可能会想这个函数返回一个只有元素[5]的列表。但是结果却出人意料:

>>> foo()
[5]
>>> foo()
[5, 5]
>>> foo()
[5, 5, 5]
>>> foo()
[5, 5, 5, 5]
>>> foo()

我的一个经理曾经碰到过这个特性并把它叫做语言的“动态设计缺陷“。这个现象应当有更深层次的解释,如果你不懂它的内部它确实非常令人困惑。然而我不能回答下面的问题:是什么原因使默认参数在函数的定义时被绑定,而不是在执行时?我怀疑这个特性在现实中有没有实际的用途(就像在C语言中有谁去用静态变量?)


事实上这并不是设计缺陷,也不是什么内部或性能原因。

原因很简单,Python中的函数是最高等级的对象,而不仅仅是一小段代码。

试着这么来理解:一个函数是一个被它自己定义而执行的对象;默认参数是一种“成员数据”,所以它们的状态和其他对象一样,会随着每一次调用而改变。

Effbot在它的 Python中的默认参数 对这种行为的原因解释的非常清楚!我强烈建议你读一读能对函数对象的工作有更深一步的了解。

...

Tags Read More


C++零基础——C++变量和常量

by LauCyun May 06,2013 19:51:19 4,608 views

变量和常量是用来在程序中表示数据的。常量是指取值在程序的执行过程中始终保持不变的量,又分为文字常量(Literal constant)和常变量(也称“符号常量”)。

1、变量

变量:在程序中是指可以改变值的量。

变量名:用于标识变量的标识符。而且变量必须用标识符进行标识。
变量的类型:变量有类型之分,如整形变量、字符变量等。
变量的说明:任何变量都必须先说明后使用。
目的:一是便于编译程序为变量分配空间,二是便于编译时进行语法检查。
格式:在C++中,变量说明的一般格式为:

[存储类型]<数据类型> <变量名1>[,<变量名2>,…,<变量名n>];
例:
int i, j, k;          //说明3个整型变量i,j,k
float x,y,z;      //说明3个实型变量x,y,z
char c1, c2;    //说明2个字符型变量c1,c2
double dx;      //说明1个双精度型变量dx
变量的使用:变量使用的第一步,是给变量赋初始值,称为“初始化”。
有两种方法:
    a. 变量说明时直接赋初值:
 int a=3, b=4, c=5;   
 float x=3.0
    b. 用赋值语句赋初值: 
float x, e;    
x=3.5;   
e=2.71828;

2、文字常量

文字常量指程序中直接给出的量。文字常量存储在程序区,而不是数据区;对它的访问不是通过数据地址进行的。

根据取值和表示方法的不同,可分为整型常量、实型常量、字符型常量和字符串常量。

  • 整型常量:即整数,可以有多种表示方法。

     a. 十进制表示法:是平时的习惯写法,例如:15 -24;

    b. 八进制表示法:以0打头,由数字0~7组成。例如:   

012      //八进制数12,即十进制数10   
-6555    //八进制数-655,即十进制数-429

    c. 十六进制表示法:以0X(大小写均可)打头,由数字0~9和字母A~F(大小写均可)组成,用来表示一个十六进制数。例如: 

0x32A       //十六进制数32A,即十进制数810   
-0x2fe0   //十六进制数-2fe0,即十进制数-12256

    d. 其他表示法:还可以表示以 L或l结尾的长整数和以U或u结尾的无符号整数。以UL或LU(大小写均可)结尾则可表示无符号长整型常数。例如:    

-84L        //十进制长整数-84    
026U       //八进制表示的无符号数26    
0X32LU     //十六进制表示的无符号长整数32
  • 实型常量:包含小数点和10的幂的数,有两种表示方法:

    a. 一般形式:与平时书写形式相同,由数字0 ~9和小数点组成。例如:    

        0.23、 -125.76、 0.0、 .46、 -35.
    b. 指数形式:即科学表示法,表示为尾数乘以10的次方形式,由尾数、E或e和阶数组成。要求在E或e前面的尾数部分必须有数字,后面的指数部分必须为整数。

        判断下列实型常量表示是否合法:(答案:红色的不合法)

        123E12 、 E4 、 1.43E3.5 、 -.34e-2 ;

  • 字符型常量:用单引号引起来的单个字符。

    a. 保存形式:在内存中保存的是字符的ASCII码值。

    b. 直接表示形式:对于可显示字符,通常用单引号直接引起来表示。

    例如:  

     'a'   //字符a            '4'   //字符4               '@'   //字符@               ' '   //空格字符

     c. 转义序列表示法:对于不可显示的或无法从键盘输入的字符,如回车符、换行符、制表符、响铃、退格等;另外,还有几个具有特殊含义的字符,如反斜杠、单引号和双引号等,C++提供了一种称为“转义序列”的表示方法。例如:

      '\a'   //响铃             '\n'   //换行符                 '\\'   //字符\   
     下表给出C++中预定义的转义序列字符及其含义。

字符表示
ASCII码值
名 称
功 能 或 用 途
\a0x07
响铃
用于输出
\b0x08
退格(Backspace键)
退回一个字符
\f0x0c
换页
用于输出
\n0x0a
换行符
用于输出
\r0x0d
回车符
用于输出
\t0x09
水平制表符(Tab键)
用于输出
\v0x0b
纵向制表符
用于制表
\00x00
空字符
用于字符串结束标志等
\\0x5c
反斜杠字符
用于需要反斜杠字符的地方
\′0x27
单引号字符
用于需要单引号的地方
\″0x22
双引号字符
用于需要双引号的地方
\nnn八进制表示 用八进制ASCII码表示字符
\xnn十六进制表示 用十六进制ASCII码表示字符

     说明:
       a). 上表中最后两行是所有字符的通用表示方法,即用反斜杠加ASCII码表示。
       b). 对于可显示字符,有三种表示方法。以字母a为例: ′a′、′\141′和′\x61′
       c.) 显然,对于可见字符,第一种是最简单直观的表示方法。

  • 字符串常量:由一对双引号″″引起来的若干个字符组成。例如:″I am a Chinese.″、 ″123″、 ″a″、 ″ ″

     字符串常量与字符型常量的区别如下:

       a. 字符串常量″a″占两个字节,存放'a'和'\0',如图左半部分,值为0x6100;
       b. 字符型常量'a' 占一个字节,存放'a',如图右半部分,值为0x61。

3、常变量

用常量说明符const给文字常量命名所得的标识符就称为“标识符常量”。因为标识符常量的说明和引用形式很像变量,所以也称“常变量”。例如:
const float PI=3.14159;    //定义了常变量PI
const int Number_of_Student=100; //定义了常变量Number_of_Student

在使用常变量时应注意以下几点:
    a. 常变量必须也只能在说明时进行初始化。
    b. 常变量初始化之后,不允许再被赋值。
    c. 常变量必须先说明后使用。

...

Tags Read More


C++零基础——C++的数据类型

by LauCyun May 06,2013 15:44:05 4,650 views

C++语言是广泛使用的程序设计语言之一,因其特有的优势在计算机应用领域占有重要一席。

1、C++中的数据类型

C++中的数据类型分为两大类:基本数据类型和非基本数据类型,如图1所示。


                                          图1   C++的数据类型
说明:
图中“type”表示任一种非void的类型,英文为关键字或程序中的表达方式。

2、VC++中各种基本数据类型的详细说明

VC++中各种基本数据类型的详细说明如下表所示:

类 型
名 称
占用字节数
取 值 范 围
bool布尔型
true,false
(signed) char有符号字符型
1
-128~127
unsiged char无符号字符型
1
0~255
(signed)short(int)有符号短整型
2
-32768~32767
unsignedshort(int)无符号短整型
2
0~65535
(signed) int有符号整型
4
-(2的31次方)~2的31次方-1
unsigned (int)无符号整型
4
0~(2的32次方-1)
(signed)long (int)有符号长整型
4
-(2的31次方)~(2的31次方-1)
unsigned long(int)无符号长整型
4
0~(2的32次方-1)
float实型
4
-(10的38次方)~10的38次方
double双精度型
8
-(10的308次方)~10的308次方
long double长双精度型*
8
-(10的308次方)~10的308次方
void无值型
0
无值

说明:

  • IEEE754定义长双精度型为10个字节,-(10的4932次方) ~ 10的4932次方。
  • 表中用( )括起来的部分在书写时可以省略。例如:int和char默认为有符号的,等同于加修饰词signed。
  • short、long、signed和unsigned修饰int时,int可以省略。例如:unsigned short即是说明无符号短整型。

...

Tags Read More


C++零基础——C++的词法单位

by LauCyun May 06,2013 13:04:03 4,759 views

介绍C++的字符集、关键字、标识符及标点符号。

 

1、C++的字符集

  • ASCII码字符集是计算机中的常用字符集。它包括英文字母及阿拉伯数字等128个字符,存储一个ASCII码占用一个字节单元。
  • 由于汉字处理的需要,又出现了汉字国标码等对应于不同语言的字符集。国标码的存储占用两个字节单元。
  • 为了对各类字符进行统一编码,Unicode字符集应运而生。它包括了世界上多种语言的基本字符,共有65536个字符。 ASCII码字符集国标码字符集都是它的子集。Unicode字符集对所有字符进行统一的双字节编码。

C++语言使用下列基本字符来构成词法单位:

26个小写字母 abcdefghijklmnopqrstuvwxyz
26个大写字母 ABCDEFGHIJKLMNOPQRSTUVWXYZ
10个阿拉伯数字 0 1 2 3 4 5 6 7 8 9
其他符号  + - * / = , . _ : ; ? \ " ' ~ | ! # % & () [] {} ^ < > 空格

 

2、C++关 键 字

关键字(keyword)又称保留字,是系统定义的具有特定含义的英文单词,不能另作它用。C++区分大小写,关键字全部由小写字母组成。标准C++(ISO14882)定义了74个关键字,具体的C++编译器还会做一些增删。

常用关键字及分类见下表:

数据类型说明符与修饰符 bool、char、wchar_t、class、const、double、enum、float、int、long、short、signed、struct、union、unsigned、void、volatile
存储类型说明符 auto、extern、inline、register、static
访问说明符 friend、private、protected、public
其它说明符 asm、operator、template、this、typedef、virtual
语句与标号 break、case、catch、continue、default、do、else、for、goto、if、return、switch、throw、try、while
运算符及逻辑值 delete、false、new、sizeof、true

VC++中还有一些专用的关键字,它们都以双下划线开头:

_ _asm、_ _based、_ _cdecl、_ _emit、_ _export、_ _far、_ _fastcall、
_ _fortran、_ _huge、_ _interrupt、_ _loadds、_multipile_inheritance、
_ _near、_ _pascal、_ _saveregs、_ _segment、_ _signal_inheritance、
_ _self、_ _stdcall、_ _virtual、_ _inheritance

除以上之外的一些关键字本书不作介绍,可查阅相关手册。

 

3、C++标识符

标识符(Identifier,ID)是程序员定义的英文单词,用来给变量、常量、数据类型、函数等命名。合法标识符由字母或下划线开始,由字母、数字、下划线组成,其有效长度为1-31个字符,长度超过31个字符者只识别前31个字符,VC++标识符长度为1-247个字符。

建议使用有一定含义的英文单词或拼音序列作标识符,以提高可读性;另外,尽量不用下划线或双下划线打头,以免与系统定义的关键字冲突。

例如:

判断下面哪些是合法的标识符(非 标红 部分之外均为合法的标示符)

94Salary  $amount f3.5 Num_of_Student
Salary 94 amount MyFile      void
Salary94      

 

4、标点符号

c++中的标点符号包括 #、 (、 )、 {、 }、 ,、 :、 ;、 " 、 '等。标点符号的作用:

  • 有一定的语法意义。例如字符和字符串常量分别用 ' ' 和 " "引起来。
  • 对语法符号起分隔作用。例如 ;等。

...

Tags Read More