Python自学笔记D6

函数式编程、模块与面向对象编程

前两天事比较多,今天得专心补一补!在2021年6月之前一定要成为一个合格的自动化测试人员!
主要内容:

函数式编程

排序算法返回函数匿名函数装饰函数偏函数

模块
作用域

面向对象编程中
类和实例访问限制继承和多态静态语言与动态语言不同获取对象信息。

一、排序算法sorted

sorted可以非常方便地对字符串和dic进行排序,sorted()函数也是一个高阶函数,它还可以接收一个key函数来实现自定义的排序,例如按绝对值大小排序:

sorted([36, 5, -12, 9, -21], key=abs)
[5, 9, -12, -21, 36]
sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower,reverse = True)
['Zoo', 'Credit', 'bob', 'about']#忽略大小写,按ascii反转排序

作业,按照名字排序和按照成绩从大到小排序。

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
print(sorted(L,key= lambda x: x[0]))#按照名字
print(sorted(L,key= lambda x: x[1],reverse=True))#按照分数倒序

返回函数

即return中返回的是函数!

def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

在函数lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力。

返回的函数在其定义内部引用了局部变量args,所以,当一个函数返回了一个函数后,其内部的局部变量还被新函数引用。

作业:返回一个计数器

def createCounter():
    cnt = [0]#不能使用循环变量,因此使用数组
    def counter():
        cnt[0] = cnt[0] + 1    
        return cnt[0]
    return counter
    #以下为闭包错误写法:内部函数改变外部变量!!
    i = 0
    def counter():
        i = i + 1
        return i
    return counter

匿名函数lambda

f = lambda x:x*x
#等同于
def f(x)return x*x

匿名函数的限制是只能写一个表达式,不能有return,好处就是没有名字不起冲突。

装饰函数decorate

假设我们要增强now()函数的功能,比如,在函数调用前后自动打印日志,但又不希望修改now()函数的定义,这种在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。

因此!我们需要写一个装饰函数,再写一个内层函数(不改变原先的值)

import functools
def log(func):
    @functools.wraps(func)#修改签名以防出错
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper
@log
def now():
    print('2015-3-25')
now()
call now():
2015-3-25
#第二种:需要多一个返回参数的情况,即三层嵌套
import functools
def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator
@log('execute')
def now():
    print('2015-3-25')
now()
execute now():
2015-3-25

作业即应用:打印任意函数的执行时间!很经典

import time, functools
def metric(fn):
    @functools.wraps(fn)
    def wrapper(*args,**kwargs):
        start = time.time()
        result = fn(*args,**kwargs)
        print('%s executed in %s ms' % (fn.__name__,time.time() - start))
        return result
    return wrapperr
    #以下为检测
@metric
def fast(x, y):
    time.sleep(0.0012)
    return x + y;
@metric
def slow(x, y, z):
    time.sleep(0.1234)
    return x * y * z;
f = fast(11, 22)
s = slow(11, 22, 33)
if f != 33:
    print('测试失败!')
elif s != 7986:
    print('测试失败!')

偏函数

functools.partial的作用就是,把一个函数的某些参数给固定住(也就是设置默认值),返回一个新的函数,调用这个新函数会更简单。(简化参数的目的)

import functools
int2 = functools.partial(int, base=2)
int2('1001')
#实际相当于
kw = { 'base': 2 }
int('10010', **kw)

二、模块

为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式。在Python中,一个.py文件就称之为一个模块

为了避免模块名字重复,可以通过包来组织模块,只要顶层包名不冲突,则包下面的模块名也不会冲突,如mycompany.web.www等,不过myconpany.web指的是web中的_init_.py(必须有的一个初始文件)

不过自己命名模块的时候注意不能与系统模块名字冲突!!
完整的模块:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

' a test module '

__author__ = 'Michael Liao'

import sys

def test():
    args = sys.argv
    if len(args)==1:
        print('Hello, world!')
    elif len(args)==2:
        print('Hello, %s!' % args[1])
    else:
        print('Too many arguments!')

if __name__=='__main__':#重要!如果B调用A则A可能不能使用
    test()

作用域

有些函数和变量不希望在模块外被应用,因此可以设定作用域。
_xxx_为有特殊含义的变量,可以被直接饮用,而_xx是不应该被直接引用的,但也无法绝对限制!

def _private_1(name):
    return 'Hello, %s' % name

def _private_2(name):
    return 'Hi, %s' % name

def greeting(name):
    if len(name) > 3:
        return _private_1(name)
    else:
        return _private_2(name)

第三方模块安装

使用包管理工具pip管理,安装了Anaconda进行管理。

面向对象编程

OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。

面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行。为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度。

而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。

对象数据类型即类的概念!

#面向对象!首先创建对象,接着让对象自己吧数据打印
class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.score = score

    def print_score(self):
        print('%s: %s' % (self.name, self.score))
   #面向过程
std1 = { 'name': 'Michael', 'score': 98 }
std2 = { 'name': 'Bob', 'score': 81 }
def print_score(std):
    print('%s: %s' % (std['name'], std['score']))

三大特点:继承、封装和多态!

类和实例

面向对象最重要的两个概念!
类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

class Student(object): class之后是类名,括号中是继承自类。

bart = Student()#创建实例
bart.name = 'Bart Simpson'#可以自由给实例绑定属性
class Student(object):
#提前在类中绑定属性!(只能使用_init_)
    def __init__(self, name, score):#使用self表示本身!
        self.name = name
        self.score = score
    #再封装一个打印成绩
    def print_score(self):
        print('%s: %s' % (self.name, self.score))

和静态语言不同,Python允许对实例变量绑定任何数据,也就是说,对于两个实例

变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同!!

访问限制

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名(属性)如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,不过使用某些方法也可以访问到。

class Student(object):
    ...
    def get_name(self):
        return self.__name
def set_score(self, score):
    if 0 <= score <= 100:
        self.__score = score
    else:
        raise ValueError('bad score')

一个下划线开头则不强制规定,但是最好不要改。

继承和多态

在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base 、Super class)。

多态性:比如动物的子类猫,猫的实例加菲猫,数据类型既是猫也是动物!

多态性的好处:任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行。

静态语言与动态的区别

对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了:

动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的。

获取对象信息

可以使用type判断类型!

>>> type(abs)
<class 'builtin_function_or_method'>
>>> type(a)
<class '__main__.Animal'>

而对class的继承关系来说,可以使用isinstance(),并且也可以判断类型!

a = cat()
>>>isinstance(a,Animal)
True
>>> isinstance(abs)
<class 'builtin_function_or_method'>
>>>isinstance(a,(Animal,jiafei))#或者
True

dir()返回所有属性和方法。

通过getattr、hasattr和setattr操作对象状态

>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y'404) # 获取属性'y',不存在则返回404
19
>>> obj.y # 获取属性'y'
19
def readImage(fp):
    if hasattr(fp, 'read'):
        return readData(fp)
    return None

在__inti__中改变,则每次产生实例都会调用一次

class Student(object):#没创建一个实例+1
    count = 0
    def __init__(self, name):
        self.name = name
        Student.count += 1

猜你喜欢

转载自blog.csdn.net/qq_43517875/article/details/106853644
d6