Jean's Blog

一个专注软件测试开发技术的个人博客

0%

Python常用内置函数

函数作用域

在学习Python函数时,经常会遇到变量作用域的问题,有全局变量,局部变量等,Python查询变量的顺序遵守LEGB规则,即遇到某个变量时:

  • 优先从它所属的函数(local)内查找;
  • 若找不到,并且它位于一个内嵌函数中,就再到它的父函数(enclosing)中查找;
  • 如果还是找不到,再去全局作用域(global)查找;
  • 再找不到,最后去内置作用域(build-in)查找。
  • 若还是找不到,报错。

如下例子,变量 c 在局部作用域(local)被发现;变量 b 在 parent 函数和 son 函数间(enclosing)被发现;变量 a 在全局作用域(global)被发现;min 函数属于 Python 中内置函数,所以在搜寻完 LEG 三个区域后,最终在 build-in 域被找到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
a = 10


def parent():
b = 20

def son():
# c: local
c = 30
# b: enclosing
print(b + c)
# a: global
print(a + b + c)
# min: built-in
print(min(a, b, c))

son()


parent()

如下变量 d,在 LEGB 四个域都被搜寻一遍后,还是未找到,就会抛出 d 没有被发现的异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
a = 10


def parent():
b = 20

def son():
# c: local
c = 30
# b: enclosing
print(b + c)
# a: global
print(a + b + c)
# min: built-in
print(min(a, b, c))
# 在 LEGB 四个域都未找到后,报错! ide中会线索报错,有红线信息
print(d)

son()


parent()

报错信息

1
2
3
4
5
6
7
8
9
10
11
12

Traceback (most recent call last):
File "/Users/lvjing/python-project/test_platform/test.py", line 22, in <module>
parent()
File "/Users/lvjing/python-project/test_platform/test.py", line 19, in parent
son()
File "/Users/lvjing/python-project/test_platform/test.py", line 17, in son
print(d)
NameError: name 'd' is not defined
50
60
10

类型函数

bool([x])

测试一个对象是 True,还是 False。

1
2
3
4
5
6
>>> bool([0, 0, 0])
True
>>> bool([])
False
>>> bool([1, 0, 1])
True

bytes([source[, encoding[, errors]]])

注:针对 Python 2.x 用户的说明:在 Python 2.x 系列中,允许 8 位字符串( 2.x 所提供的最接近内置二进制数据类型的对象)与 Unicode 字符串进行各种隐式转换。 这是为了实现向下兼容的变通做法,以适应 Python 最初只支持 8 位文本而 Unicode 文本是后来才被加入这一事实。 在 Python 3.x 中,这些隐式转换已被取消 —— 8 位二进制数据与 Unicode 文本间的转换必须显式地进行,bytes 与字符串对象的比较结果将总是不相等。

将一个字符串转换成字节类型(Python2的演示):

1
2
3
>>> s = 'apple'
>>> bytes(s, encoding='utf-8')
b'apple'

str(object=’’)

将字符类型、数值类型等转换为字符串类型:

1
2
3
>>> i = 100
>>> str(i)
'100'

chr(i)

查看十进制整数对应的 ASCII 字符:

1
2
>>> chr(65)
'A'

ord(c)

查看十进制整数对应的 ASCII 字符:

1
2
>>> ord('A')
65

dict()

1
2
3
class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)

创建数据字典:

1
2
3
4
5
6
7
8
>>> dict()
{}
>>> dict(a='a', b='b')
{'a': 'a', 'b': 'b'}
>>> dict(zip(['a', 'b'], [1, 2]))
{'a': 1, 'b': 2}
>>> dict([('a', 1), ('b', 2)])
{'a': 1, 'b': 2}

object()

返回一个根对象,它是所有类的基类。

1
2
3
>>> o = object()
>>> type(o)
<type 'object'>

使用魔法函数dir,查看object对象上的所有方法:

1
2
>>> dir(o)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

int(x) 

int(x, base =10),x 可能为字符串或数值,将 x 转换为一个整数。

1
2
3
4
>>> int('12')
12
>>> int('12', 16)
18

若 x 不能转化为整数,则抛出 ValueError 异常:

1
2
3
4
>>> int('ws')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'ws'

float(x)

将一个字符串或整数转换为浮点数:

1
2
>>> float('30')
30.0

frozenset([iterable])

创建一个不可修改的冻结集合,一旦创建不允许增删元素。

1
2
3
>>> s = frozenset([1, 1, 3, 2, 3])
>>> s
frozenset([1, 2, 3])

image-20220408153118147

普通集合set创建后,是可以增删元素。

创建一个普通集合s:

1
>>> s = {1, 2, 3}

image-20220408153240578

创建 s 后,仍然能通过 add 方法,再插入元素:

1
2
3
>>> s.add(4)
>>> s
set([1, 2, 3, 4])

image-20220408153333175

普通集合也能删除元素,使用 pop 方法移除集合的第一个元素:

1
2
3
4
5
>>> s = {1, 2, 3}
>>> s.pop()
1
>>> s
set([2, 3])

image-20220408153409214

list([iterable])

返回可变序列类型:列表。如下,集合类型转列表:

1
2
3
>>> s = {1, 2, 3}
>>> list(s)
[1, 2, 3]

list函数还常用在,可迭代类型(Iterable)转化为列表。

如下,使用map函数,转化列表内每一个整形元素为字符串型。

m是可迭代类型,经过list转化后,看到列表l。

1
2
3
4
>>> m = map(lambda i:str(i), [186, 1243, 3201])
>>> l = list(m)
>>> l
['186', '1243', '3201']

image-20220408153428696

相似的一个例子:

1
2
>>> list(map(lambda x: x%2==1, [1, 3, 2, 4, 1]))
[True, True, False, False, True]

range(stop)

Python 提供两个内置的 range 函数,生成不可变序列:

  • range(stop)
  • range(start, stop[,step])
1
2
3
4
5
6
7
8
# 只有一个参数,默认初始值为 0,步长为 1
>>> range(11)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#三个参数都提供,分别是开始、终止、步长值
>>> range(0, 11, 2)
[0, 2, 4, 6, 8, 10]
>>> range(0, 11)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

set([iterable])

返回一个集合对象,并允许创建后再增加、删除元素。

集合的一大优点,容器里不允许有重复元素,因此可对列表内的元素去重。

1
2
3
>>> a = [1, 4, 2, 3, 1]
>>> set(a)
set([1, 2, 3, 4])

slice(stop)

  • slice(stop)
  • slice(start, stop[, step])

返回一个由 range(start, stop, step) 所指定索引集的 slice 对象:

1
2
3
4
5
>>> a = [1, 4, 2, 3, 1]
>>> a[slice(0, 5, 2)] # 等价于a[0:5:2]
[1, 2, 1]
>>> a[0:5:2]
[1, 2, 1]

image-20220408153455509

tuple([iterable])

创建一个不可修改的元组对象:

1
2
3
>>> t = tuple(range(10))
>>> t
(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

type(object)

这是两个查看对象的类型的函数:

  • type(object)
  • type(name, bases, dict)

自定义类 Student,创建实例 xiaoming:

1
2
3
4
>>> class Student:
... pass
...
>>> xiaoming = Student()

调用 type 查看 xiaoming 的类型:

1
2
>>> type(xiaoming)
<type 'instance'>

type 函数是非常实用的,阅读他人代码时,若函数参数类型没有显示给出,就会用到 type 函数。

1
2
>>> type((1, 2, 3))
<type 'tuple'>

zip(*iterables)

创建一个迭代器,聚合每个可迭代对象的元素。

参数前带 *,意味着是可变序列参数,可传入 1 个,2 个或多个参数。

传入 1 个参数:

1
2
3
4
5
>>> for i in zip([1, 2]):
... print(i)
...
(1,)
(2,)

传入2个参数:

1
2
3
4
5
6
>>> a = range(5)
>>> b = list('abcde')
>>> b
['a', 'b', 'c', 'd', 'e']
>>> [str(y) + str(x) for x, y in zip(a, b)]
['a0', 'b1', 'c2', 'd3', 'e4']

image-20220408153524830

类对象及属性

classmethod

classmethod 修饰符对应的函数不需要实例化,不需要 self 参数。

第一个参数需要是表示自身类的 cls 参数,能调用类的属性、方法、实例等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Student(object):
def __init__(self, id=None, name=None):
self.id = id
self.name = name

def instance_method(self):
print("这是实例方法")
return self

@classmethod
def __annotations__(cls):
return "学生类"

@classmethod
def print_type_name(cls):
print("这是类上的方法,类名为:%s,注解为:%s" % (cls.__name__, cls.__annotations__()))


Student().print_type_name()
Student().instance_method()

执行结果

1
2
3
/usr/bin/python3 /Users/lvjing/python-project/test_platform/test.py
这是类上的方法,类名为:Student,注解为:学生类
这是实例方法

image-20220408153556063

delattr(object, name)

删除对象的属性,在不需要某个或某些属性时,这个方法就会很有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> class Student():
... def __init__(self, id=None, name=None):
... self.id = id
... self.name = name
...
>>> xiaoming = Student(1, 'xiaoming')
>>> delattr(xiaoming, 'id')
>>> xiaoming.id
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Student instance has no attribute 'id'
>>> hasattr(xiaoming, 'id')
False

dir([object])

不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时返回参数的属性、方法列表。

1
2
>>> dir(xiaoming)
['__doc__', '__init__', '__module__', 'name']

getattr(object, name[, default])

获取对象的属性:

1
2
3
4
5
6
7
8
>>> class Student():
... def __init__(self, id=None, name=None):
... self.id = id
... self.name = name
...
>>> xiaoming = Student(1, 'xiaoming')
>>> getattr(xiaoming, 'name')
'xiaoming'

hasattr(object, name)

判断对象的属性是否存在

1
2
3
4
5
6
7
8
9
10
>>> class Student():
... def __init__(self, id=None, name=None):
... self.id = id
... self.name = name
...
>>> hasattr(xiaoming, 'name')
True
>>> delattr(xiaoming, 'id')
>>> hasattr(xiaoming, 'id')
False

isinstance(object, classinfo)

判断 object 是否为类 classinfo 的实例,若是,返回 true。

1
2
3
4
5
6
7
8
>>> class Student():
... def __init__(self, id=None, name=None):
... self.id = id
... self.name = name
...
>>> xiaoming = Student(1, 'xiaoming')
>>> isinstance(xiaoming, Student)
True

序列类型的基类为 Iterable,所以返回 True:

1
2
3
>>> from collections import Iterable
>>> isinstance([1,2,3],Iterable)
True

issubclass(class, classinfo)

如果 class 是 classinfo 类的子类,返回 True:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> class Student():
... def __init__(self, id=None, name=None):
... self.id = id
... self.name = name
...
>>> class undergraduate(Student):
... def studyClass(self):
... pass
... def attendActivity(self):
... pass
...
>>> issubclass(undergraduate, Student)
True
>>> issubclass(object, Student)
False
>>> issubclass(Student, object)
False

classinfo 取值也可能为元组,若 class 是元组内某个元素类型的子类,也会返回 True:

1
2
>>> issubclass(int, (int, float))
True

property(fget=None, fset=None, fdel=None, doc=None)

返回 property 属性。不适用装饰器,定义类上的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Student(object):
def __init__(self):
self._name = None

def get_name(self):
return self._name

def set_name(self, val):
self._name = val

def del_name(self):
del self._name

# 显示调用property函数
name = property(get_name, set_name, del_name, 'name property')

显示的调用 property 函数定义类上的属性:

1
2
3
xiaoming = Student()
xiaoming.name = 'xiaoming'
print(xiaoming.name)

使用 Python 装饰器 @property,同样能实现对类上属性的定义 ,并且更简洁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Student(object):
def __init__(self):
self._name = None

@property
def name(self):
return self._name

@name.setter
def name(self, val):
self._name = val

@name.deleter
def del_name(self):
del self._name


xiaoming = Student()
xiaoming.name = 'xiaoming'
print(xiaoming.name)

super([type[, object-or-type]])

返回一个代理对象,它会将方法调用委托给 type 的父类或兄弟类。

如下,子类的 add 方法,一部分直接调用父类 add,再有一部分个性的行为:打印结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Parent():
def __init__(self, x):
self.v = x

def add(self, x):
return self.v + x


class Son(Parent):
def add(self, y):
# 直接调用父类的add方法
r = super().add(y)
# 子类的add与父类相比,能实现对结果的打印功能
print(r)


Son(1).add(2)

callable(object)

判断对象是否可被调用,能被调用的对象就是一个 callable 对象,比如函数 str、int 等都是可被调用的。

1
2
3
4
>>> callable(str)
True
>>> callable(int)
True

如下,xiaoming 实例不可被调用:

1
2
3
4
5
6
7
8
9
10
11
12
>>> class Student():
... def __init__(self, id=None, name=None):
... self.id = id
... self.name = name
...
>>> xiaoming = Student('001', 'xiaoming')
>>> callable(xiaoming)
False
>>> xiaoming()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Student instance has no __call__ method

如果 xiaoming 能被调用,则必须要重写 Student 类上 __call__方法:

1
2
3
4
5
6
7
8
9
10
11
12
class Student():
def __init__(self, id, name):
self.id = id
self.name = name

def __call__(self):
print('I can be called')
print(f'my name is {self.name}')


xiaoming = Student('001', 'xiaoming')
xiaoming()

执行结果

1
2
3
4
5
/usr/bin/python3 /Users/lvjing/python-project/test_platform/test.py
I can be called
my name is xiaoming

Process finished with exit code 0