PYTHON02 - 函数、内置模块、面向对象
一、函数
1.1 创建函数
1.1.1 def语句
def function_name(args):
函数体
1.1.2 内部函数
• 在函数体内创建另外一个函数是完全合法的,这种函
数叫做内部/内嵌函数
>>> def foo():
... def bar():
... print('bar() is called')
... print('foo() is called’)
... bar()
>>> foo()
foo() is called
bar() is called
>>> bar() //会报bar()方法未定义的错
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined
1.2 调用函数
1.2.1 函数操作符
1. 使用一对圆括号()调用函数,如果没有圆括号,只是
对函数的引用
2. 任何输入的参数都必须放置在括号中
>>> def foo():
... print('Hello world!')
...
>>> foo
<function foo at 0x7f19d3e69598>
>>> foo()
Hello world!
1.2.2 参数组
• python允许程序员执行一个没有显式定义参数的函数
• 相应的方法是通过一个把元组(非关键字参数)或字
典(关键字参数)作为参数组传递给函数
func(*tuple_grp_nonkw_args, **dict_grp_kw_args) //传递一个元组和字典给func函数
1.2.3 匿名函数
1. lambda
1.1 python允许用lambda关键字创造匿名函数
1.2匿名是因为不需要以标准的def方式来声明
1.3 一个完整的lambda“语句”代表了一个表达式,这
个表达式的定义体必须和声明放在同一行
lambda [arg1[, arg2, ... argN]]: expression
>>> a = lambda x, y: x + y
>>> print(a(3, 4))
2.filter()函数
2.1 filter(func, seq):调用一个布尔函数func来迭代遍历
每个序列中的元素;返回一个使func返回值为true的
元素的序列
2.2 如果布尔函数比较简单,直接使用lambda匿名函数
就显得非常方便了
>>> data = filter(lambda x: x % 2, [num for num in range(10)])
>>> print(data) #过滤出10以内的奇数
[1, 3, 5, 7, 9]
2.3 map()函数:将数据进行处理
1.2.4 加减法数学游戏
1. 随机生成两个100以内的数字
2. 随机选择加法或是减法
3. 总是使用大的数字减去小的数字
4. 如果用户答错三次,程序给出正确答案
from random import randint, choice
def exam():
cmds = {'+': lambda x, y: x + y, '-': lambda x, y: x - y}
nums = [randint(1, 10) for i in range(2)]
nums.sort(reverse=True) # 相当于是以上注释的两行
op = choice('+-')
result = cmds[op](*nums)
prompt = '%s %s %s = ' % (nums[0], op, nums[1])
counter = 0
while counter < 3:
try:
answer = int(input(prompt))
except: # 可以捕获所有异常,但是不建议
continue
if answer == result:
print('Very good!')
break
else:
print('Wrong answer.')
counter += 1
else:
print('%s%s' % (prompt, result))
if __name__ == '__main__':
while True:
exam()
try:
yn = input('Continue(y/n)? ').strip()[0]
except IndexError:
continue
except (KeyboardInterrupt, EOFError):
print('\nBye-bye')
yn = 'n'
if yn in 'nN':
break
二、函数应用
2.1 变量作用域
2.1.1 全局变量
全局变量的作用域是整个脚本文件,对所有函数有效
2.1.2 局部变量
1.局部变量的作用域是整个方法,对整个方法有效
2.如果局部与全局有相同名称的变量,函数在运行时,会使用局部变量的变量
>>> x = 4
>>> def foo():
... x = 10
... print('in foo, x =', x)
...
>>> foo()
in foo, x = 10
>>> print('in main, x =', x)
in main, x = 4
2.1.3 global语句
1. 因为全局变量的名字能被局部变量给遮盖掉,所以为了明确地
引用一个已命名的全局变量,必须使用global语句
>>> x = 4
>>> def foo():
... global x
... x = 10
... print('in foo, x =', x)
...
>>> foo()
in foo, x = 10
>>> print('in main, x =', x)
in main, x = 1
2.2 递归函数
1. 函数包含了对自身的调用,该函数就是递归的
>>> def func(num):
... if num == 1:
... return 1
... else:
... return num * func(num - 1)
...
>>> print(func(5))
120
>>> print(func(10))
3628800
2. 使用递归,实现快速排序
from random import randint
def listSort(num_list):
if len(num_list)<2:
return num_list
middle=num_list[0]
small=[]
large=[]
for i in num_list[1:]:
if i<=middle:
small.append(i)
else:
large.append(i)
return listSort(small)+[middle]+listSort(large)
if __name__ == '__main__':
arrayList=[randint(1,100) for i in range(10)]
print(arrayList)
print(listSort(arrayList))
2.3 生成器
1. 从句法上讲,生成器是一个带yield语句的函数
2. 一个函数或者子程序只返回一次,但一个生成器能暂停执行并返回一个中间的结果
3. yield 语句返回一个值给调用者并暂停执行
4 当生成器的next()方法被调用的时候,它会准确地从离开地方继续
5.当函数结束没有更多的值返回,StopIteration异常就会被抛出
2.4 闭包
闭包将内部函数的代码和作用域以及外部函数的作用结合起来
闭包也是函数,但是他们能携带一些额外的作用域
def counter(start=0):
count = start
def incr():
# 为了把外层函数的变量在内层函数中引用,需要使用关键字nonlocal
nonlocal count # count不是incr的局部变量,它也不是全局,使用nonlocal才能应用
count += 1
return count
return incr # 外层函数的返回值是内层函数
if __name__ == '__main__':
a = counter() # a本质上是函数incr
print(a()) # 执行incr()
b = counter(10)
print(b())
print(a())
print(b())
2.5 装饰器
1. 装饰器是在函数调用之上的修饰
2. 这些修饰仅是当声明一个函数或者方法的时候,才会
应用的额外调用
3. 使用装饰器的情形有:
– 引入日志
– 增加计时逻辑来检测性能
– 给函数加入事务的能力
def counter(start=0):
count = start
def incr():
# 为了把外层函数的变量在内层函数中引用,需要使用关键字nonlocal
nonlocal count # count不是incr的局部变量,它也不是全局,
使用nonlocal才能应用
count += 1
return count
return incr # 外层函数的返回值是内层函数
if __name__ == '__main__':
a = counter() # a本质上是函数incr
print(a()) # 执行incr()
b = counter(10)
print(b())
print(a())
print(b())
三、内置模块
3.1 hashlib模块
hashlib是专门提供hash算法的模块,用来做数据的校验
>>> import hashlib
>>> m = hashlib.md5()
>>> m.update('hello world!')
>>> m.hexdigest()
'fc3ff98e8c6a0d3087d515c0473f8677'
3.2 tarfile模块
tarfile模块允许创建、访问tar文件,同时支持gzip、bzip2格式
[[email protected] home]# ls /home/demo/
install.log mima
[[email protected] home]# python
>>> import tarfile
>>> tar = tarfile.open('/home/demo.tar.gz', 'w:gz')
>>> tar.add('demo')
>>> tar.close()
附:tar -cvzf 包名 查看压缩包里面有哪些文件
3.3 编写备份程序
1. 需要支持完全和增量备份
2. 周一执行完全备份
3. 其他时间执行增量备份
4. 备份文件需要打包为tar文件并使用gzip格式压缩
import time
import os
import tarfile
import hashlib
import pickle as p
def check_md5(fname):
m = hashlib.md5()
with open(fname, 'rb') as fobj:
while True:
data = fobj.read(4096)
if not data:
break
m.update(data)
return m.hexdigest()
def fullbackup(src_dir,dst_dir,md5_file):
#1.生成备份文件名称
#2.使用tarfile备份源目录
#3.生成md5文件
# 3.1 取出源目录下的文件名,对文件进行md5校验. 赋值给字典的key和value
# 3.2 通过pickle模块把字典放入md5_file
fname=os.path.basename(src_dir)
fname='%s_full_%s.tar.gz' % (fname,time.strftime('%Y-%m-%d')) #生成备份文件名称
fname=os.path.join(dst_dir,fname) #生成备份文件的绝对路径
tar=tarfile.open(fname,'w:gz') #以读方式打开fname
tar.add(src_dir) #将源目录加入到tar包中
tar.close() #关闭tar
md5_dict={}
for path,folders,files in os.walk(src_dir):
for eachfiles in files:
md5_key=os.path.join(path,eachfiles)
md5_dict[md5_key]=check_md5(md5_key)
with open(md5_file,'wb') as fobj:
p.dump(md5_dict,fobj)
def incbackup(src_dir,dst_dir,md5_file):
fname = os.path.basename(src_dir)
fname = '%s_incr_%s.tar.gz' % (fname, time.strftime('%Y-%m-%d')) # 生成备份文件名称
fname = os.path.join(dst_dir, fname)
new_md5={}
with open(md5_file,'rb') as fobj:
old_md5=p.load(fobj) #取出前一天的md5值
#更新md5文件
for path,folders,files in os.walk(src_dir):
for each_file in files:
key=os.path.join(path,each_file)
new_md5[key]=check_md5(key)
with open(md5_file,'wb') as fobj:
p.dump(new_md5,fobj) #将新md5值写入文件
tar=tarfile.open(fname,'w:gz')
for key in new_md5: #新增的文件或则已经修改了的文件就加入tar包
if old_md5.get(key) != new_md5[key]:
tar.add(key)
tar.close()
if __name__ == '__main__':
src_dir='/tmp/security'
dst_dir='/tmp/backup'
md5_file='/tmp/backup/md5.data'
if not os.path.exists(dst_dir):
os.mkdir(dst_dir)
data=time.strftime('%a')
print(data)
if data == 'Mon':
fullbackup(src_dir,dst_dir,md5_file)
else:
incbackup(src_dir,dst_dir,md5_file)
四、Python面向对象
4.1 OOP简介
4.1.2 创建类
使用class语句来创建一个新类,类名称要以:结尾
class BearToy:
pass
4.1.3 创建实例
类是模板,实例是根据模板创建出来的
tidy = BearToy()
4.2 方法
4.2.1 构造器方法
1.实例化对象时,构造器方法默认会调用
2.实例本身作为第一个i参数,传递给self
class BearToy:
__init__(self, size, color):
self.size = size
slef.color = color
if __name__ == '__main__':
tidy = BearToy('small', 'orange')
4.2.2 普通方法
普通方法需要创建实例后,通过实例来调用
class BearToy:
def __init__(self,size,color):
self.size = size
self.color = color
def speak(self):
print('hahaha')
if __name__ == '__main__':
tidy=BearToy('small','orange')
tidy.speak()
4.3 组合和派生
4.3.1 组合应用
1. 两个类明显不同,一个类的属性是另一个类的对象
class Manufacture:
def __init__(self, phone, email):
self.phone = phone
self.email = email
class BearToy:
def __init__(self, size, color, phone, email):
self.size = size
self.color = color
self.vendor = Manufacture(phone, email)
4.3.2 继承
1.子类只需要在圆括号中写明是继承哪个父类即可,可以继承父类的任何属性,不管是数据属性还是方法
class BearToy:
def __init__(self, size, color, phone, email):
self.size = size
self.color = color
self.vendor = Manufacture(phone, email)
... ...
class NewBearToy(BearToy):
def __init__(self, size, color, phone, email, date):
super(NewBearToy, self).__init__(size, color, phone, email)
self.date = date
2.python允许多重继承,即一个类可以是多个父类的子类,子类可以拥有所有父类的属性
>>> class A:
... def foo(self):
... print('foo method’)
>>> class B:
... def bar(self):
... print('bar method’)
>>> class C(A, B):
... pass
>>> c = C()
>>> c.foo()
foo method
>>> c.bar()
bar method
4.4 特殊方法
4.4.1 类方法
1.使用classmethod装饰器定义,需要用到类对象cls的时候使用
2.第一个参数cls表示类本身
class Date:
def __init__(self, year, month, date):
self.year = year
self.month = month
self.date = date
@classmethod
def create_date(cls, string_date):
year, month, date = map(int, string_date.split('-'))
instance = cls(year, month, date)
return instance
if __name__ == '__main__':
d2 = Date.create_date('2018-05-04’)
4.4.2 静态方法
1.通过staticmethod装饰器定义,不需要用到类对象cls的时候使用
2.没有cls参数
class Date:
def __init__(self, year, month, date):
self.year = year
self.month = month
self.date = date
@staDcmethod
def is_date_valid(string_date):
year,month,date =map(int,string_date.split('-'))
return 1 <= date <= 31 and 1 <= month <= 12 and year< 3999
if __name__=='__main__':
print(Date.is_date_valid('2018-02-04'))
print(Date.is_date_valid('2018-22-04'))
4.4.3 __init__方法
1. 实例化类实例时默认会调用的方法
class BearToy:
__init__(self, size, color):
self.size = size
slef.color = color
if __name__ == '__main__':
Ddy = BearToy('small', 'orange')
4.4.4 __str__方法
1. 打印/显示实例时调用方法
2. 返回字符串
class BearToy:
__init__(self, size, color):
self.size = size
slef.color = color
def __str__(self):
return '<Bear: %s %s>' % (self.size, self.color)
if __name__ == '__main__':
tidy = BearToy('small', 'orange')
print(tidy)
4.4.5 __call__方法
1. 用于创建可调用的实例,调用实例的时候默认会调用这个方法
class BearToy:
__init__(self, size, color):
self.size = size
slef.color = color
def __call__(self):
print('I am a %s bear' % self.size)
if __name__ == '__main__':
tidy = BearToy('small', 'orange')
print(tidy())