1.11 函数classmethod()
在Python程序中,函数classmethod()的功能是将函数包装成类方法。其语法格式如下所示:
classmethod(function)
在Python程序中,经常使用@classmethod修饰符的用法。在声明一个类方法时,通常使用如下所示的用法:
class C:
@classmethod
def f(cls, arg1, arg2, ...): ...
修饰符@classmethod对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。@classmethod形式的用法是一个函数装饰器,用于查看函数定义中关于函数定义的详细说明。@classmethod既可以在类上调用(如C.f()),也可以在实例上调用(如C().f())。除了实例的类,实例本身被忽略。如果一个类方法在子类上调用,那么子类对象被传递为隐式的第一个参数。类方法不同于C++或Java中的静态方法,如果需要静态方法,请参考本章后面介绍的staticmethod()函数。
在下面的实例文件xiu.py中,演示了使用@classmethod修饰符的过程。
class A(object):
bar = 1
def func1(self):
print('foo')
@classmethod
def func2(cls):
print('func2')
print(cls.bar)
cls().func1() # 调用 foo 方法
A.func2() # 不需要实例化
执行后会输出:
func2
1
foo
在下面的实例文件xiu1.py中,演示了使用修饰符@classmethod修饰指定方法的过程。
class C:
@classmethod
def f(cls, arg1):
print(cls)
print(arg1)
C.f('类对象调用类方法')
c = C()
c.f('类实例对象调用类方法')
执行后会输出:
<class '__main__.C'>
类对象调用类方法
<class '__main__.C'>
类实例对象调用类方法
在类中使用修饰符@classmethod后,当类被继承后,子类也可以调用父类的类方法,但是第一个参数传入的是子类的类对象。例如下面的实例文件xiu2.py演示了这一用法。
class C:
@classmethod
def f(cls, arg1):
print(cls)
print(arg1)
class D(C):
pass
D.f("子类的类对象调用父类的类方法")
执行后会输出:
<class '__main__.D'>
子类的类对象调用父类的类方法
1.12 函数compile()
在Python程序中,函数compile()的功能是将一个字符串编译为字节代码。使用函数compile()的语法格式如下所示。
compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
- source:字符串或者AST(Abstract Syntax Trees)对象,函数compile()能够将source编译成代码对象,或者AST(Abstract Syntax Tree,抽象语法树)对象。代码对象可以由exec()或eval()执行。源可以是普通字符串,字节字符串或AST对象。
- filename:代码文件名称,如果不是从文件读取代码则传递一些可辨认的值;
- mode:指定编译代码的模式,可以指定为 exec、eval、single。如果source由语句序列组成,则它可以是'exec';如果它是单个语句,则可以使用'eval';如果它由单个交互式语句组成,则可以使用'single'。
- flags:变量作用域,局部命名空间,如果被提供,可以是任何映射对象;
- flags和dont_inherit:是用来控制编译源码时的标志。
- optimize:指定编译器的优化级别;默认值-1选择由-O选项给出的解释器的优化级别。显式级别为0(无优化; __debug__为真),1(声明被删除,__debug__为假 )或2(docstrings也被删除)。
在上述参数中,可选参数flags和dont_inherit控制哪些未来版本的语句会应用于源编译。如果两者都不存在(或两者都为零),则使用在调用compile()的代码中生效的未来语句来编译代码。如果给出了flags参数且没有给出dont_inherit参数(或者为0),除了本该使用的future语句之外,由flags参数指明的future语句也会影响编译。如果dont_inherit是非0整数,flags参数被忽略(调用compile周围的有效的future语句被忽略)。
在下面的实例文件com.py中,演示了使用函数compile()编译字符串的过程。
str = "for i in range(0,10): print(i)"
c = compile(str,'','exec') # 编译为字节代码对象
print(c)
print(exec(c))
str = "3 * 4 + 5"
a = compile(str,'','eval')
print(eval(a))
在上述代码中分别使用了函数compile()的exec和eval两种编译类型,执行后会输出:
<code object <module> at 0x0000026B6382EA50, file "", line 1>
0
1
2
3
4
5
6
7
8
9
None
17
在下面的实例文件comp.py中,演示了在交互语句中使用single的过程。
#流程语句使用exec
code1 = 'for i in range(0,10): print (i)'
compile1 = compile(code1,'','exec')
print(exec (compile1))
#简单求值表达式用eval
code2 = '1 + 2 + 3 + 4'
compile2 = compile(code2,'','eval')
print(eval(compile2))
#交互语句用single
code3 = 'name = input("please input your name:")'
compile3 = compile(code3,'','single')
①print(exec(compile3)) #执行时显示交互命令,提示输入
②print(name) #执行后name变量有值
执行后会输出:
0
1
2
3
4
5
6
7
8
9
None
10
please input your name:py
None
py
在上述代码中,当执行到①时会显示一个交互命令语句,提示我们输入一个变量值,这样变量name便会有一个值,执行②代码时不会出错。如果在执行②前变量name的值不存在,则会出现执行错误,例如下面代码的执行过程:
>>> #交互语句用single
>>> code3 = 'name = input("please input your name:")'
>>> compile3 = compile(code3,'','single')
>>> name #执行前name变量不存在
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
name
NameError: name 'name' is not defined
1.13 函数complex()
在Python程序中,函数complex()的功能是创建一个值为“real + imag * j”的复数或者转化一个字符串或数为复数。如果第一个参数为字符串,则不需要指定第二个参数。使用函数complex()的语法格式如下所示。
class complex([real[, imag]])
real:int、long、float或字符串;
imag:int、long或float类型。
函数complex()的返回值形式为“real + imag * j”的复数,或将字符串或数字转换为复数。如果第一个参数是一个字符串,它将被解释成复数,同时函数不能有第二个参数。第二个参数不能是字符串。每个参数必须是数值类型(包括复数)。如果省略参数imag,则默认为零,构造函数会像int和float一样进行转换。如果省略这两个参数,则返回0j。
在下面的实例文件compl.py中,演示了使用函数complex()创建复数的过程。
print(complex()) #当两个参数都不提供时,返回复数 0j。
print(complex(1, 2))
print(complex(1)) # 数字
print(complex("1")) # 当做字符串处理
# 注意:下面的代码在"+"号两边不能有空格,也就是不能写成"1 + 2j",应该是"1+2j",否则会报错
print(complex("1+2j"))
print(complex(2)) #当第一个参数为int或者float时,第二个参数可为空,表示虚部为0
print((2+0j)) #如果提供第二个参数,第二个参数也需为int或者float。
执行后会输出:
0j
(1+2j)
(1+0j)
(1+0j)
(1+2j)
(2+0j)
(2+0j)
在Python程序中,当函数complex()中的第一个参数为字符串时,在调用时不能提供第二个参数。此时的字符串参数,需要是一个能表示复数的字符串,而且加号或者减号左右不能出现空格。例如在下面的代码中,函数complex()的第一个参数为字符串,不能接受第二个参数。接受第二个参数时会出错。
>>> complex('1+2j',2) #第一个参数为字符串,不能接受第二个参数,
Traceback (most recent call last):
File "<pyshell#2>", line 1, in <module>
complex('1+2j',2)
TypeError: complex() can't take second arg if first is a string
在函数complex()中的"+"号两边不能有空格,否则也会出现编译错误,例如下面的代码。
>>> complex('1 + 2j') #不能有空格
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
complex('1 + 2j')
ValueError: complex() arg is a malformed string
1.14 函数delattr()
在Python程序中,函数delattr()的功能是删除指定对象的某个属性。使用函数delattr()的语法格式如下所示。
delattr(object, name)
- object:对象;
- name:是一个字符串,这个字符串必须是对象的某个属性的名字。
例如代码“delattr(x, 'foobar')”等同于“del x.foobar”,表示删除对象x中的属性foobar。在下面的实例文件del.py中,演示了使用函数delattr()删除指定属性的过程。
class Coordinate:
x = 10
y = -5
z = 0
point1 = Coordinate()
print('x = ', point1.x)
print('y = ', point1.y)
print('z = ', point1.z)
delattr(Coordinate, 'z')
print('--删除 z 属性后--')
print('x = ', point1.x)
print('y = ', point1.y)
# 因为已经删除了,所以执行后会触发错误
print('z = ', point1.z)
执行后会输出:
x = 10
Traceback (most recent call last):
y = -5
File " del.py", line 19, in <module>
z = 0
print('z = ', point1.z)
--删除 z 属性后--
AttributeError: 'Coordinate' object has no attribute 'z'
x = 10
y = -5
当使用函数delattr()删除某个属性时,如果这个属性不存在则会报错,例如下面的代码:
>>> a.name #属性name已经删掉,不存在
Traceback (most recent call last):
File "<pyshell#47>", line 1, in <module>
a.name
AttributeError: 'A' object has no attribute 'name'
>>> delattr(a,'name') #再删除会报错
Traceback (most recent call last):
File "<pyshell#48>", line 1, in <module>
delattr(a,'name')
AttributeError: name
当使用函数delattr()删除某个属性时,不能删除对象的方法,否则将会出错,例如下面的演示代码:
>>> a.sayHello
<bound method A.sayHello of <__main__.A object at 0x03F014B0>>
>>> delattr(a,'sayHello') #不能用于删除方法
Traceback (most recent call last):
File "<pyshell#50>", line 1, in <module>
delattr(a,'sayHello')
AttributeError: sayHello
>>>
1.15 函数dict()
在Python程序中,函数dict()的功能是创建一个字典。在现实中有如下三种使用函数dict()的语法格式。
class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)
- **kwargs:关键字;
- Mapping:元素的容器;
- Iterable:可迭代对象。
在下面的实例文件dict.py中,演示了使用函数dict()创建字典的过程。
#不传入任何参数时,返回空字典。
print(dict())
#可以传入键值对创建字典。
print(dict(a = 1))
print(dict(a = 1,b = 2))
#可以传入映射函数创建字典。
print(dict(zip(['a','b'],[1,2])))
#可以传入可迭代对象创建字典。
print(dict((('a',1),('b',2))))
执行后会输出:
{}
{'a': 1}
{'a': 1, 'b': 2}
{'a': 1, 'b': 2}
{'a': 1, 'b': 2}