4872 2019-08-06 2020-06-25
前言:纸上得来终觉浅,绝知此事须躬行。
一、数据类型
同Java一样,Python3中有以下几种基本数据类型,分别为Number(数字)、String(字符串)、List(列表)、Tuple(元组)、Set(集合)、Dictionary(字典)、Boolean(布尔值)、None。下面将分别进行讲解
1、Boolean
Python中的布尔类型非常像js里面的布尔值,还是上代码吧,如下
def check_true(value):
typ = type(value)
if value:
print('%s 类型值为%s True' % (typ, value))
else:
print('%s 类型值为%s False' % (typ, value))
if __name__ == '__main__':
# 必须传入参数,即使是None,看来还是js比Python更加包容啊
# check_true()
check_true(None) # false
check_true(-1)
check_true(0) # false
check_true(1)
check_true(-1.1)
check_true('') # false
check_true(' ')
check_true('123')
check_true('-123')
check_true([]) # false
check_true([1, 2, 3])
check_true(()) # false
check_true((1, 2, 3))
# 注意这里的set(),{}则表示一个字典
empty_set = set() # false
check_true(empty_set)
check_true({1, 2, 3, 2, 1})
print({1, 2, 3, 2, 1})
check_true({}) # false
check_true({'name': 'name', 'age': 'age'})
大致可以总结如下,对象为空或0或None则返回False,其他均返回True。
而对于js来说,不同点在于只要对象是Object类型,即使是空对象,也是返回true,如下代码
var n = 1;
// true
console.log(!!n);
n = -1;
// true
console.log(!!n);
n = 0;
// false
console.log(!!n);
n = '-1';
// true'
console.log(!!n);
n = '0';
// true
console.log(!!n);
n = '';
// false
console.log(!!n);
n = ' ';
// true
console.log(!!n);
n = {}
// ture
console.log(!!n);
n = []
// ture
console.log(!!n)
2、Number
上代码,如下
def test_number():
n1 = 100
# 经过观察,解释器会自动转换为100.1
# 即自动省去后面不必要的空0位
n2 = 100.100
# 100.1
print(n2)
n3 = '100'
n4 = '100.100'
n11 = str(n1)
n22 = str(n2)
# int不能转'100.0'
n33 = int(n3)
# int不能转'100.100'
# n44 = int(n4)
# 原类型<class 'int'>值为100 转为 <class 'str'>类型值为100
check_number(n1, n11)
# 原类型<class 'float'>值为100.1 转为 <class 'str'>类型值为100.1
check_number(n2, n22)
# 原类型<class 'str'>值为100 转为 <class 'int'>类型值为100
check_number(n3, n33)
n55 = float(n3)
n66 = float(n4)
# 原类型<class 'str'>值为100 转为 <class 'int'>类型值为100
check_number(n3, n55)
# 原类型<class 'str'>值为100.100 转为 <class 'float'>类型值为100.1
check_number(n4, n66)
def check_number(from1, to2):
type1 = type(from1)
type2 = type(to2)
print('原类型%s值为%s 转为 %s类型值为%s' % (type1, from1, type2, to2))
Python不像Java,没有隐式转换,需要注意上面的几个点。
3、String
上代码,如下
def test_string():
str1 = '123456'
str2 = str1
str1 = '654321'
# 这个是跟Java里面的String一样的
print(str1, str2, str1 == str2)
# 1 2 3 4 5 6
for i in str2:
print(i, end=' ')
str1 = 'abcd1234321dcba'
# True
print('abcd' in str1)
# True
print(str1.startswith('abcd'))
# 类似Java中的indexOf
print(str1.find('34', 0, 8))
# 是否为全部小写
print(str1.islower())
str2 = str1.upper()
# ABCD1234321DCBA
print(str2)
tuple1 = str1.split('3')
# <class 'list'> 类型值为['abcd12', '4', '21dcba']
print('%s类型值为%s' % (type(tuple1), tuple1))
# ABCD1234321DCBA
print(str2)
str1 = str2[0]
# 第一个 A
print(str1)
str1 = str2[-1]
# 倒数第一个 A
print(str1)
str1 = str2[:-1]
# 不含最后一个A ABCD1234321DCB
print(str1)
str1 = str2[0:4]
# 前面四位 ABCD
print(str1)
str1 = str2[:4]
# 前面四位 ABCD
print(str1)
str1 = str2[-4:0]
# 为空
print(str1)
str1 = str2[-4:-1]
# 最后三位 DCB
print(str1)
str1 = str2[-4:]
# 最后四位 DCBA
print(str1)
str1 = '1234'
str2 = '5678'
str3 = str1 + str2 + "90"
# <class 'str'>类型值为1234567890
print("%s类型值为%s" % (type(str3), str3))
# 会报错
# print("%s类型值为%s" % (type(str3), str3 + 11))
# <class 'str'>类型值为123456789012345678901234567890
print("%s类型值为%s" % (type(str3 * 3), str3 * 3))
还是看得出来,使用字符串时还是有不少需要注意的地方。
4、List
Python中的List(列表)有点特别,如下
def test_list():
list1 = [1, 1.1, "111", [1, 2, 3], {1, 2, 2, '3'}, {'1': 1, '2': '2'}]
# [1, 1.1, '111', [1, 2, 3], {1, 2, '3'}, {'1': 1, '2': '2'}]
print(list1)
# [1, 1.1, '111', [1, 2, 3], {1, 2, '3'}, {'1': 1, '2': '2'}][1, 1.1, '111', [1, 2, 3],
# {1, 2, '3'}, {'1': 1, '2': '2'}]
print(list1.__str__() + list1.__repr__())
# 直接使用foreach
# 1, 1.1, '111', [1, 2, 3], {1, 2, '3'}, {'1': 1, '2': '2'}
for x in list1:
print(x, end=' ')
it = iter(list1)
# 加入三方迭代器
# <class 'int'> <class 'float'> <class 'str'> <class 'list'> <class 'set'> <class 'dict'>
for x in it:
print(type(x), end=' ')
# 需要重新初始化it
it = iter(list1)
# <class 'int'> <class 'float'> <class 'str'> <class 'list'> <class 'set'> <class 'dict'>
while True:
try:
print(type(next(it)), end=' ')
except StopIteration:
break
list2 = [1, 2, 3, '4']
# 长度为 4
print(list2.__len__())
# 4
print(len(list2))
# 会报错,__add__参数必须为列表
# list1.__add__(100)
list2 = list2.__add__([11, 22])
# 这一行返回一个新的list,不会修改list2本身
list2.__add__([33, 44])
# + 操作等同于__add__魔术方法
# 对于+号操作,可变对象和不可变对象调用的都是add操作
# 对于+=号操作,可变对象调用add,不可变对象调用的是iadd(不可变对象没有iadd) iadd是原地修改
list2 = list2 + [55, 66]
# [1, 2, 3, '4', 11, 22, 55, 66]
print(list2)
list1 = [77, 88]
list3 = list2 + list1
# [1, 2, 3, '4', 11, 22, 55, 66, 77, 88]
print(list3)
list1[0] = 67
list1.insert(0, 56)
list1.insert(-1, 99)
# [56, 67, 99, 88]
print(list1)
# [1, 2, 3, '4', 11, 22, 55, 66, 77, 88]
# 由此可知对象不是简单的引用复制,而是直接返回一个新的list
print(list3)
last = list3.pop()
# [1, 2, 3, '4', 11, 22, 55, 66, 77] 88
print(list3, last)
list3.append(3)
count = list3.count(3)
# 统计出现次数 2
print(count)
def comparator(value):
return str(value)
# [1, 2, 3, '4', 11, 22, 55, 66, 77, 3]
print(list3)
list3.sort(key=comparator, reverse=True)
# [77, 66, 55, '4', 3, 3, 22, 2, 11, 1]
print(list3)
List是最为常用的一种数据结构,还是有不少地方需要注意的,需要熟练掌握。
5、Tuple
代码如下
def test_tuple():
tuple1 = ()
# <class 'tuple'>
print(type(tuple1))
tuple2 = (1, 2, 3, 4, 2, 2)
count = tuple2.count(2)
# 3
print(count)
index = tuple2.index(4)
# 3
print(index)
list1 = [1, 2]
tuple1 = ([1, 2, 3], list1, 3)
# 修改成功
tuple1[0][0] = 11
# 修改成功
list1[0] = 999
# 虽然元组不允许修改,但是我们可以修改引用所指向的内存数据
# ([11, 2, 3], [999, 2], 3)
print(tuple1)
# list1指向内存数据发生变化,但不会影响tuple1中的指针指向
# 此时这个赋值操作可以看做Java容器类中的str = new String()
# 修改失败
list1 = [0, 0]
# ([11, 2, 3], [999, 2], 3)
print(tuple1)
# [0, 0]
print(list1)
# 可以修改整个元祖
tuple1 = (1, 2, 3)
# (1, 2, 3)
print(tuple1)
tuple2 = (4, 5, 6)
# 可以相加 (1, 2, 3, 4, 5, 6)
print(tuple1 + tuple2)
# 可以删除,tuple1变量将不存在
del tuple1
# 需要注意,一般情况下编译器会提示这是不建议的用法
tuple1 = (1)
tuple2 = (1, )
# <class 'int'> <class 'tuple'>
print(type(tuple1), type(tuple2))
6、Dict
代码如下
def test_dic():
dic1 = {}
# 以下语句为非法语句
# dic1.name = 'hk'
sex = '性别'
# 非法语句
# dic1.sex = '女'
dic1[sex] = '男'
# {'性别': '男'}
print(dic1)
# 依然是非法语句,因为字典没有sex这个属性
# dic1.sex = '女'
# 总而言之,对于dic键的读写,都是通过dic + []实现
del dic1['性别']
# {}
print(dic1)
# 以下语句为非法语句
# dic1.name = 'hk'
dic1['name'] = 'hk'
dic1['age'] = 21
# {'name': 'hk', 'age': 21}
print(dic1)
# 不存在会抛出KeyError: 't',无法读,无法删除
# print(dic1['t'])
# del dic1['t']
dic1['age'] = ['快22了吧']
# {'name': 'hk', 'age': ['快22了吧']}
print(dic1)
dic1['22'] = 22
dic1['33'] = 33
dic1['11'] = 11
# 遍历键值对,有序
# {name:hk} {age:['快22了吧']} {22:22} {33:33} {11:11}
for k, v in dic1.items():
print('{%s:%s}' % (k, v), end=" ")
# name age 22 33 11
for k in dic1.keys():
print(k, end=' ')
# hk ['快22了吧'] 22 33 11
for v in dic1.values():
print(v, end=' ')
print(len(dic1))
Python里面的字典类型其实也是一个经典的哈希实现,同Java的hashCode和equals一样,哈希键应该是不变的。
7、Set
代码如下
def test_set():
# {}代表空字典,不是空set
set1 = set()
set1.add(2)
set1.add(1)
set1.add(3)
set1.add('4')
# {'4', 1, 2, 3}
# 说明set内部是无序的,有点像Java里面的HashSet,而dic又有点像LinkedHashMap
print(set1)
set2 = {2, 3, 4, 4}
set3 = set((2, 3, 4, 4))
# True ==符号其实调用的就是__eq__,而eq方法比较的就是set中的value值
print(set2 == set3)
# True
print(set2.__eq__(set3))
# False
print(set2 is set3)
# {2, 3, 4}
print(set2)
# 一次添加多个
set2.update({2, 0, -1})
# {0, 2, 3, 4, -1}
print(set2)
# 删除4
set2.remove(4)
# {0, 2, 3, -1}
print(set2)
# 有趣的是set对于交集、并集、差集的支持
set1 = {1, 2, 3}
set2 = {3, 4, 5}
# 取交集
set3 = set1.intersection(set2)
# {3}
print(set3)
# 取并集
set3 = set1.union(set2)
# {1, 2, 3, 4, 5}
print(set3)
# 取差集
set3 = set1.difference(set2)
# {1, 2}
print(set3)
# 可以直接省略set3,
set1.difference_update(set2)
# {1, 2}
print(set3)
Set(集合)还是有一些需要注意的地方。
8、迭代器
在Java里面,只要实现了Iterable接口,就要实现接口方法,然后就可以顺理成章的获取迭代器Iterator进行迭代了。Python3中还是有些不同,具体表现在如下代码中
def test_iterable():
def print_info(i, x):
print('第' + str(i) + '个值为' + str(x) + '类型为' + str(type(x)), end=' ')
_str = '123456'
_list = [1, '2', [3, '4'], (5, 6), {'name': 'test', 'age': '22'}, {1, 2, 1}]
_set = {1, 2, 3, 4}
_tuple = (1, '2', 3.3)
_dic = {'name': 'hk', 'age': 22}
# 添加下标,也可以直接使用foreach
for i, x in enumerate(_str):
print_info(i + 1, x)
print()
for i, x in enumerate(_list):
print_info(i + 1, x)
print()
for i, x in enumerate(_set):
print_info(i + 1, x)
print()
for i, x in enumerate(_tuple):
print_info(i + 1, x)
print()
i = 0
for k, v in _dic.items():
i += 1
print('第' + str(i) + '个键为' + str(k) + '值为' + str(v), end=' ')
# 以上测试数据都可以直接使用foreach迭代,即都是Iterable-可迭代,但都不是Iterator-迭代器(本身不是迭代器)
for i in _list:
print('值为' + str(i) + '类型为' + str(type(i)) + 'is Iterable?', isinstance(i, Iterable), 'is Iterator?',
isinstance(i, Iterator))
# 但是,正因为是个可迭代对象,所以可以获取Iterable迭代器对象,以str和dic作为例子
it = iter('1234')
while True:
try:
print(next(it), end=" ")
except StopIteration:
break
# 如果不加items,默认遍历键,而非值,即22, 11, 3
it = iter({'22': 22, '11': 11, '3': '33'}.items())
while True:
try:
k, v = next(it)
print(k, v, end=" ")
except StopIteration:
break
# 其实Iterator的真正用途是生成器,即动态生成数据
# 列表生成式
_list = [x * x for x in range(1, 11)]
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
print(_list)
# 生成器,动态生成next对象,本身就是个Iterator迭代器对象
_list = (x * x for x in range(1, 11))
# <class 'generator'> True True
print(type(_list), isinstance(_list, Iterator), isinstance(_list, Iterable))
# 对于迭代器,foreach还是调用的next方法
for i in _list:
print(i, end=' ')
二、运算符
Python里面没有&&、|| 、~这种符号预算,取之替代的是and、or、not关键字。下面给出一些例子方便理解
def test_operator():
r = 1 and 0 or 1
# 1
print(r)
r = 1 and 0 or 1 and 0
# 0
# 说明运算符从左往右,依次计算过去,即具有右结合性
print(r)
# 0 0 1 1 异或运算,不同为1,相同为0
print(1 ^ 1, 0 ^ 0, 1 ^ 0, 0 ^ 1)
r = 1001 / 100
# 10.01
print(r)
# 取整除
r = 1001 // 100
# 10 <class 'int'>
print(r, type(r))
# 这就比较有意思了,可见取整除得到是一个float还是int取决于整除数
a, b, c = 4.4 // 1, 4.5 // 1, 4.6 // 1
# 4.0 4.0 4.0 <class 'float'> <class 'float'> <class 'float'>
print(a, b, c, type(a), type(b), type(c))
a, b, c = 8.8 // 2, 9.0 // 2, 9.2 // 2
# 4.0 4.0 4.0 <class 'float'> <class 'float'> <class 'float'>
print(a, b, c, type(a), type(b), type(c))
a, b, c = 8.8 / 2, 9 // 2, 9.2 / 2
# 4.4 4 4.6 <class 'float'> <class 'int'> <class 'float'>
print(a, b, c, type(a), type(b), type(c))
# 这里的in又跟js里面的in类似
# 我都有点被搞晕了:Java、Python、JS
str1 = 'abcdefg'
# True
print('f' in str1)
# True
print('z' not in str1)
str2 = '1,2'
str3 = '1,2'
list2 = [1, 2, [3, 4]]
list3 = [1, 2, [3, 4]]
# True True
print(str2 == str3, list2 == list3)
# True True
# Python中的==和equ方法一样,基本只是换个说法
# 在判断一个对象的内存地址是否相等是,还是要依靠is方法
print(str2.__eq__(str3), list2.__eq__(list3))
# False False
print(str2 != str3, list2 != list3)
# True False
# 看来,Python里面也有Java中类似常量池的概念
print(str2 is str3, list2 is list3)
# False True
print(str2 is not str3, list2 is not list3)
感觉有一个点是需要特别注意的,如is、is not与==、!=的区别。
三、类
1、object
和Java类似,Python3中所有类均继承自object,这是因为继承有着莫大的好处。以下为object的类定义
class object:
""" The most base type """
def __delattr__(self, *args, **kwargs): # real signature unknown
""" Implement delattr(self, name). """
pass
def __dir__(self, *args, **kwargs): # real signature unknown
""" Default dir() implementation. """
pass
def __eq__(self, *args, **kwargs): # real signature unknown
""" Return self==value. """
pass
def __format__(self, *args, **kwargs): # real signature unknown
""" Default object formatter. """
pass
def __getattribute__(self, *args, **kwargs): # real signature unknown
""" Return getattr(self, name). """
pass
def __ge__(self, *args, **kwargs): # real signature unknown
""" Return self>=value. """
pass
def __gt__(self, *args, **kwargs): # real signature unknown
""" Return self>value. """
pass
def __hash__(self, *args, **kwargs): # real signature unknown
""" Return hash(self). """
pass
def __init_subclass__(self, *args, **kwargs): # real signature unknown
"""
This method is called when a class is subclassed.
The default implementation does nothing. It may be
overridden to extend subclasses.
"""
pass
def __init__(self): # known special case of object.__init__
""" Initialize self. See help(type(self)) for accurate signature. """
pass
def __le__(self, *args, **kwargs): # real signature unknown
""" Return self<=value. """
pass
def __lt__(self, *args, **kwargs): # real signature unknown
""" Return self<value. """
pass
@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
""" Create and return a new object. See help(type) for accurate signature. """
pass
def __ne__(self, *args, **kwargs): # real signature unknown
""" Return self!=value. """
pass
def __reduce_ex__(self, *args, **kwargs): # real signature unknown
""" Helper for pickle. """
pass
def __reduce__(self, *args, **kwargs): # real signature unknown
""" Helper for pickle. """
pass
def __repr__(self, *args, **kwargs): # real signature unknown
""" Return repr(self). """
pass
def __setattr__(self, *args, **kwargs): # real signature unknown
""" Implement setattr(self, name, value). """
pass
def __sizeof__(self, *args, **kwargs): # real signature unknown
""" Size of object in memory, in bytes. """
pass
def __str__(self, *args, **kwargs): # real signature unknown
""" Return str(self). """
pass
@classmethod # known case
def __subclasshook__(cls, subclass): # known special case of object.__subclasshook__
"""
Abstract classes can override this to customize issubclass().
This is invoked early on by abc.ABCMeta.__subclasscheck__().
It should return True, False or NotImplemented. If it returns
NotImplemented, the normal algorithm is used. Otherwise, it
overrides the normal algorithm (and the outcome is cached).
"""
pass
__class__ = None # (!) forward: type, real value is "<class 'type'>"
__dict__ = {}
__doc__ = ''
__module__ = ''
更多特性有待后续自己体会,这里暂时跳过。以下是一个简单的例子
class Father(object):
def __new__(cls, *args, **kwargs):
print('father new')
return object.__new__(cls)
def __init__(self):
self.first_name = 'xiao'
self.last_name = 'ming'
self.name = self.first_name + self.last_name
print('father init and the fullname is ' + self.name)
class Mother(object):
def __new__(cls, *args, **kwargs):
print('mother new')
return object.__new__(cls)
def __init__(self):
self.first_name = 'xiao'
self.last_name = 'hong'
self.name = self.first_name + self.last_name
print('mother init and the fullname is ' + self.name)
def print_self(self):
print('fullname %s and name %s' % (self.first_name + self.last_name, self.name))
class Son1(Mother, Father):
def __new__(cls, *args, **kwargs):
print('son1 new')
# 必须返回一个有效的cls,否则不会执行init方法
return object.__new__(cls)
def __init__(self):
# 主动调用父类的init方法,不然将无法获取到父类init方法中定义的属性
# super用于单继承中,多继承环境只会调用第一个继承类的init方法
super(Son1, self).__init__()
self.last_name = 'long'
# 注意这里的name不是xiaolong,而是从父类继承的xiaoming
print('son1 init and the name is ' + self.name)
class Son2(Father, Mother):
def __new__(cls, *args, **kwargs):
print('son2 new')
return object.__new__(cls)
def __init__(self):
# 另一种父类调用方法,用于多继承环境调用多个父类方法
Father.__init__(self)
self.last_name = 'kang'
print('son2 init and the name is ' + self.name)
self.print_self()
if __name__ == '__main__':
son = Son1()
print()
son = Son2()
son1 new
## 输出如下
mother init and the fullname is xiaohong
son1 init and the name is xiaohong
son2 new
father init and the fullname is xiaoming
son2 init and the name is xiaoming
fullname xiaokang and name xiaoming
2、function
Python中是处处皆对象,比Java中的一切皆对象还要面向对象。最为代表的就是函数了,当然,我还是习惯叫方法。
1、特殊的参数
- 默认参数
示例代码如下
class Argument(object):
def __init__(self, _dict):
self._dict = _dict
def get(self, key, def_val=None, required=False):
val = self._get(key, def_val)
if val is None and required:
raise ArgumentError(key)
return val
def _get(self, key, def_val=None):
if self._dict:
# 如果指定键的值不存在,则返回默认值
return self._dict.get(key, def_val)
return def_val
class ArgumentError(Exception):
def __init__(self, key):
print('the error occured, required key is ' + str(key))
def test_default_argument():
people = {'name': 'huangkui', 'age': 22, 'sex': '男', 'game': 'dota2', 'girl': '', 'bogy': None}
arg = Argument(people)
name = arg.get('name', 'no noe')
# 正常输出 huangkui
print('name:' + name)
name = arg.get('QQnameQQ', 'no noe')
# 使用默认值,正常输入 no noe
print('name:' + name)
try:
arg.get('QQnameQQ', required=True)
except ArgumentError as e:
print('the error msg is:' + str(e))
finally:
print('I just deal with a exception, i\'m too difficult')
if __name__ == '__main__':
test_default_argument()
当使用默认参数时,需要注意对于默认参数,传值时一定要指定默认参数名。
- 可变参数
示例代码如下
def test_variable_argument():
def count_value(*numbers, cmp_val=100):
_sum = 0
for n in numbers:
_sum += n
print('the cmp_val is:' + str(cmp_val))
return _sum
# 参数可以为0个
print(count_value())
print(count_value(1, 2, 3, 4, 5, 6))
# *将list或tuple变为可变参数
print(count_value(*[1, 2, 3, 4, 5, 6], cmp_val=111))
- 关键字参数
示例代码如下
def test_key_argument():
def print_people(name, age, **other):
print('name', name, 'age', age, 'other', other)
print_people('huangkui', '22')
# 注意调用格式
print_people('huangkui', '22', sex='男', girl=None)
extra = {'city': 'shenzhen', 'job': 'pythoner'}
print_people('huangkui', '22', sex=extra['city'], girl=extra['job'])
# **将字典extra的拷贝传进去,不会影响原extra数据
print_people('huangkui', '22', **extra)
def test_named_key_argument():
# 命名关键字用于限制关键字参数,只接受关键词参数中city、job
# 必传且必须指定参数名
def print_people(name, age, *, city, job):
print('name', name, 'age', age, 'city', city, 'job', job)
# 报错
# print_people('huangkui', '22')
# print_people('huangkui', '22', sex='男', girl=None)
extra = {'city': 'shenzhen', 'job': 'pythoner', 'sex': '男'}
# 以下代码还是会报错,感觉这个命名关键字就是个鸡肋
# print_people('huangkui', '22', **extra)
del extra['sex']
print_people('huangkui', '22', **extra)
参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数,如下
def test_all():
def test_all_argument(required, def_val='10', *variable_val, **dic_val):
print('required', required, 'def_val', def_val, 'variable_val', variable_val, 'dic_val', dic_val)
argument1 = "这是必传的"
argument2 = "如果不指定就用默认值"
variable_val = ["一般是一个列表1", "一般是一个列表2", "一般是一个列表3"]
dic_val = {'msg1': '一般是一个字典1', 'msg2': '一般是一个字典2'}
test_all_argument(argument1, argument2, *variable_val, ** dic_val)
# 下面用法会报错,此时默认参数还是遵循常规参数定义
# test_all_argument(argument1, def_val='111111', *variable_val, ** dic_val)
# 参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数
# 这里解释一下,为什么*args, **kwargs匹配所有参数
# 首先*args匹配转换所有类list参数,**kwargs匹配转换所有类dict参数,下面是一个例子
def test(*args, **kwargs):
print('args', args)
print('kwargs', kwargs)
# args ('这是必传的', '如果不指定就用默认值', '一般是一个列表1', '一般是一个列表2', '一般是一个列表3')
# kwargs {'msg1': '一般是一个字典1', 'msg2': '一般是一个字典2'}
test(argument1, argument2, *variable_val, ** dic_val)
2、高阶函数
-
map/reduce
map方法和reduce方法的思想就是有点像分布式里面的思想,分而合,合而分,在主流语言中都得到了广泛支持与应用。如下代码
def test_map_reduce():
def double_number(x):
return x * x
_list = [1, 2, 3, 4]
# map生成的是惰性序列,即Iterator对象
numbers = map(double_number, _list)
# False <class 'map'>,注意不是dict,即生成了新对象
print(numbers is _list, type(numbers))
if isinstance(numbers, Iterator):
it = iter(numbers)
while True:
try:
print(next(it), end=' ')
except StopIteration:
break
def count_sum(sum, n):
return sum + n
_list = [1, 2, 3, 4, 5]
_sum = reduce(count_sum, _list)
# 15
print(_sum)
_list = [i - 1 for i in range(2, 102)]
# 5050
print(reduce(count_sum, _list))
-
filter
和JS里面的用法类似
def test_filter():
# 跟js里面的filter类似
def is_big(x):
return x > 100
_list = [1, 10, 90, 110, 1001, 20000]
_list1 = filter(is_big, _list)
# [1, 10, 90, 110, 1001, 20000]
print(_list)
# <filter object at 0x000001E03F741FC8>
print(_list1)
# [110, 1001, 20000],强制转换成list
print(list(_list1))
-
sorted
代码如下
def test_sorted():
_list = [5, 4, 2, 1, 3]
# 返回的一个新list
_list1 = sorted(_list)
# [5, 4, 3, 2, 1]
print(_list)
# [1, 2, 3, 4, 5],默认从小到大排序
print(_list1)
_list1 = sorted(_list, reverse=True)
# [5, 4, 3, 2, 1],反转默认排序
print(_list1)
def sort(x):
return -x
# [5, 4, 2, 1, 3]
print(_list)
# 手动实现从大到小
_list1 = sorted(_list, key=sort)
print(_list1)
3、装饰器
代理模式是一种广泛应用的模式,在Java中的经典实现是AOP,而在Python中,我想就是装饰器了吧。先看一个简单的
def log(func):
print('0.我正在消耗脑力....')
def wrapper(food):
print('1.快点,我好饿啊....')
_method = func(food)
print('3.我吃饱了,我要睡了....')
return _method
return wrapper
@log
def eat(food):
print('2.不要打扰我,我正在吃【' + str(food) + '】....')
if __name__ == '__main__':
# 在不使用装饰器的情况下,完全等同于eat = log(eat),然后调用eat()
# 但如果使用了装饰器,装饰器默认会扫描被装饰的方法,即使被装饰方法没有被调用,仍旧会触发装饰器里面的装饰代码,这点需要注意
# eat把上面的两步合成了一步,所以按顺序打印0123,
# 完整输出如下
# 0.我正在消耗脑力....
# 1.快点,我好饿啊....
# 2.不要打扰我,我正在吃【饭】....
# 3.我吃饱了,我要睡了....
# == == == == == 分割线 == == == == ==
# 0.我正在消耗脑力....
eat('饭')
print('==========分割线==========')
@log
def eat_copy():
print('我是无辜的,什么都没做,是@log自己扫描到我且主动打印的')
来个稍微复杂点的,如下
# 虽然这样写,看起来很高大上,来着不拒,但同时也说明这个函数内部必须处理好相关逻辑,且代码必须清晰易懂,最好有一定量的文字说明
# 装饰器分为eat = log(eat)、eat()两步,如果不使用@语法的话,就只能通过log2(func, some_value)调用,就有点丢失装饰器的意义了
def log2(*args, **kwargs):
print('我是最大的装饰器,你什么都可以传进来,但一般你只传一个代理函数给我,传入参数为:args', args, 'kwargs', kwargs)
def wrapper(**options):
print('我是第二大的内部装饰器,可以进一步细分逻辑,但一般你是不会传什么进来的,传入参数:options', options)
def __inner(func):
def call_():
print('函数真正调用前....')
func()
print('函数真正调用后....')
return call_
return __inner
# 根据装饰器所传入的参数,做一些处理
# 类似于eat = log(eat), eat(),所以这一步是直接装饰函数
if len(args) == 1 and callable(args[0]):
# 以下代码可以细分为
# wrapper(**kwargs)(args[0]) = __inner(func)
return wrapper(**kwargs)(args[0])
# 如果我非要在@里面加参数,如下
@log2(req='111', resp=222)
def eat2():
print('eat2真正调用')
if __name__ == '__main__':
# 当@log2不传参数等效于去掉@log2, eat2 = log2(eat2), eat2()
# eat2()
# 当@log2传入参数等效于eat2 = log2(req='111', resp=222)(eat2)
eat2()
装饰器的本质就是代理模式的应用,或者叫装饰模式的应用,也没啥特别的。
总访问次数: 382次, 一般般帅 创建于 2019-08-06, 最后更新于 2020-06-25
欢迎关注微信公众号,第一时间掌握最新动态!