python day3

python day3

  • python day3
    • 函数式编程
      • 高阶函数
        • sorted
      • 返回函数
        • 闭包
      • 匿名函数
      • 装饰器
      • 偏函数
    • 模块
      • 使用
      • 安装第三方模块
      • 安装常用模块
      • 模块搜索路径
    • 面向对象
      • 类和实例
        • 创建对象
        • 对象
        • 构造器
        • 数据封装
          • 类的方法
      • 访问限制(封装)
        • 作用域
        • 一个坑
      • 继承
      • 多态
      • 静态语言 vs 动态语言
      • 获取对象信息
        • type( )判断类型
        • isinstance()函数
        • dir()
        • getattr()、setattr()、hasattr()操作对象的状态

函数式编程

高阶函数

sorted

排序
>>> sorted([36, 5, 2])
[2, 5, 36]
按照制定规则排序
>>> sorted([36,-5, 2], key=abs)
[2, -5, 36]
反向排序
>>> sorted([36,-5, 2], key=abs, reverse = True)
[36, -5, 2]

返回函数

把函数作为返回值,存在闭包

#正常求和
def calc_sum(*args):
    sum = 0
    for i in args:
        sum += i
    return sum

要求在调用calc_sum之后,不立即产生运算结果,而是在用的时候再运算。
先不求和,用求和结果的时候再求和
那么,用的时候再调用calc_sum,先将其作为一个返回值,赋给一个变量
用的时候再去使用这个变量

# 要求在调用calc_sum之后,不立即产生运算结果,而是在用的时候再运算
def lazy_sum(*args):
    def calc_sum():
        sum = 0
        for i in args:
            sum += i
        return sum

    return calc_sum


f = lazy_sum(1, 2, 3)#返回calc_sum
print(f)
result = f()#返回sum
print(result)

calc_sum函数定义在lazy_sum函数的内部,
内部函数可以引用外部函数的参数和变量。
当外部函数lazy_sum返回内部函数calc_sum时,外部函数相关的参数和变量也被返回。即闭包。

闭包

返回函数不要使用会发生变化的变量,比如循环变量。
需要用到循环的时候可以包装成参数传入。这样会立即运算。

def count():
    def f(j):
        def g():
            return j * j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i))
    return fs

f1, f2, f3 = count()
print(f1())
print(f2())
print(f3())
# -*- coding: utf-8 -*-
def createCounter():
    i = [0]
    def counter():
        i[0] += 1#内部函数用到了外部变量,但是外部变量是一个list,内部函数没有改变外部变量的地址,所以没变。
        return i[0]
    return counter

# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
    print('测试通过!')
else:
    print('测试失败!')

匿名函数

lambda
只能有一个表达式
# -*- coding: utf-8 -*-
L = list(filter(lambda n: n % 2 == 1, range(1, 20)))

装饰器

类似的有Java的装饰模式
Decorator
思想是一致的
但是python可以从函数层面实现,当然也可以从类层面实现

# -*- coding utf-8 -*-
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('2018-05-05')


now()
# -*- coding utf-8 -*-
import functools


def log(text):
    def decotator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decotator


@log('execute')
def now():
    print('2018-05-05')


now()

请设计一个decorator,它可作用于任何函数上,并打印该函数的执行时间
time.time()的时间单位是秒

# -*- coding: utf-8 -*-
import time, functools


def metric(fn):
    functools.wraps(fn)
    def wrapper(*args,  **kw):
        bt = round((time.time()*1000))
        result = fn(*args,  **kw)
        et = round((time.time()*1000))
        print('%s executed in %s ms' % (fn.__name__, et - bt))
        return result
    return wrapper

@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('测试失败!')

再思考一下能否写出一个@log的decorator,使它既支持:

@log
def f():
pass
又支持:

@log(‘execute’)
def f():
pass

# -*- coding utf-8 -*-
import functools


def log(text =''):
    def decotator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            if text == '':
                print('call %s' % func.__name__)
            else:
                print('%s %s' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decotator


@log('execute')
def now():
    print('2018-05-05')


now()

偏函数

如果函数的参数多想简化使用时,用functools.partial(函数, *args, **kw)将函数参数固定,产生新的函数。

模块

一个.py文件就是一个模块
可以使用其他模块
也可以被其他模块使用
模块命名不要和系统自建模块冲突
命名模块前可以先在终端import xxx
如果成功,说明系统有该模块

__init__.py是一个模块,表明包的身份,该模块的名字就是包的名字,没有该模块就不是包而是普通目录
__init__.py可以有代码也可以是空文件

使用

import 模块

安装第三方模块

用pip: python的包管理工具
安装第三方模块:
1、先知道名字
2、去官网或者pypi搜索看看,了解一下
3、pip3 install xxxx

安装常用模块

用Anaconda,一次安装常用的。
Anaconda会把python的path指向自己带的Python。
在Anaconda上装的第三方模块在Anaconda自己的路径下,不会影响系统已安装的Python目录。

模块搜索路径

默认情况下
搜索当前目录下、已安装内置模块、第三方模块
如果要添加自己的搜索路径:
1、sys.path.append('路径')
运行时修改,运行结束后失效
2、设置环境变量PATHONPATH,会将你自己要添加的搜索路径自动添加到搜索的path变量中。

面向对象

类和实例

class Student(object)
类名后带小括号
小括号内是该类继承的父类
和Java一样
一切继承自object
注意object小写

创建对象

liupangzi = Student()
产生一个属于Student类的对象
Java需要new

Student liupangzi = new Student()//java
liupangzi = Student()#python

对象

对象可以调用属性
liupangzi.name

构造器

class Student(object):

    def __init__(self, name, age):
        self.name = name
        selt.age = age

self 代表对象,类似于Java中的this,但是需要在构造器中作为参数,将对象的变量传进来。
构造器是一个特殊的函数,必须写成__init__(self),且必须有参数self,self永远是第一个参数。但不用传参。
Java中构造器与类同名。
和Java一样,如果构造器定义了参数(self永远有,就不提了),那么产生一个对象的时候就必须给构造器传递参数。

数据封装

类的方法
class Student(object):

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


    def print_score(self):
        print('%s : %s' % (self.name, self.age))

打印成绩的方法写在类里边,用到score这个属性。与普通函数写法一样,只是第一个参数是self,且不用传参。

访问限制(封装)

__和Java的private很像
如果不想让外部直接访问到类到属性(liupangzi.name),那么属性前边加上__就成了私有属性。

class Student(object):

    def __init__(self, name, age, score):
        self.__name = name
        self.__age = age
        self.__score = score


    def print_score(self):
        print('%s : %s' % (self.__name, self.__age))

再访问:

liupangzi = Student("liupanzi", 22, 88)
liupangzi.__score

错误:

Traceback (most recent call last):
  File "/Users/tu/PycharmProjects/myFirstPythonDir/myPackage/Student.py", line 14, in 
    liupangzi.score
AttributeError: 'Student' object has no attribute '__score'

显示没有这个属性。
不是没有,是限制,不能访问。必须通过方法。

代码被封装起来了

作用域

public: 正常的函数、变量 abc
private:__abc
特殊变量: __abc__和public的权限一样,但是有特殊用途,自己的变量不要写这种变量名
_abc:和public的权限一样,但是看到的时候,假装是private
也就是,虽然我是外部可以访问的,但请你不要随意访问,假装我是私有的就好了。
这么看来,基本上分为public和private两大阵营。但是,其实__abc也有办法外部访问到:
liupangzi._Student__name
不能访问__name的原因是python的解释器对外把__name改成了Student__name
所以可以通过Student__name访问到私有的属性。
还是不安全啊。
最好不要这么访问属性,因为不同的解释器改出来的名字不一样。
也就是
python没有任何强制性的办法来规范你的行为,全靠自觉。
要干坏事,没有办法阻止。

一个坑

属性已经封装起来了
但是貌似还能访问到

liupangzi = Student("liupanzi", 22, 88)
liupangzi.__score = 77
print(liupangzi.__score)

其实,在类的外部,解释器把__name改成了Student__nameliupangzi.__score = 77是外部代码给liupangzi新增的变量,不改变属性。不是一个东西。
`liuopangzi.get_name()仍然是liupangzi。

class Student(object):

    def __init__(self, name, age, score, gender):
        self.__name = name
        self.__age = age
        self.__score = score
        self.__gender = gender

    def print_score(self):
        print('%s : %s' % (self.__name, self.__age))

    def get_gender(self):
        return self.__gender

    def set_gender(self, gender):
        if gender == 'male' or gender == 'female':
            self.__gender = gender
        else:
            raise ValueError('invalid gender')


bart = Student('Bart', 12, 88, 'male')
if bart.get_gender() != 'male':
    print('测试失败!')
else:
    bart.set_gender('female')
    if bart.get_gender() != 'female':
        print('测试失败!')
    else:
        print('测试成功!')

继承

子类继承父类
子类获得父类所有功能
子类可以重写父类方法——重写
重写带来了多态

多态

有Animal类,然后Dog、Cat、Tortoise都是它的子类,并且重写了父类的run方法。
开闭原则:
扩展开放:一个类可以有多个子类
修改封闭:不需要修改将父类Animal作为参数的watch_animal(Animal)函数。

静态语言 vs 动态语言

静态语言(Java)必须严格按照继承体系。
动态语言:如果一个东西叫着像鸭子,走起路来像鸭子,我们就认为它是鸭子
也就是,Java的多态,watch_animal( )这个方法里边用到了Animal的run方法,那么传进来的必须是Animal或者其子类。
python的多态,如果有个对象,不是继承自Animal,但是也有run方法,那么传进来也可以执行。
也就是我用到了run方法,谁有谁都可以传进来。

获取对象信息

type( )判断类型

判断对象类型
判断基本数据类型
判断变量是指向的函数或者类

返回对应的Class类型
判断某个东西的类型的时候,可以导入types模块,然后

types(abs) == types.BuiltinFunctionType

isinstance()函数

类似于Java的instanceOf()方法。

isinstance(对象, *类)

isinstance(h, Dog)
#判断h是否是Dog或其子类的对象。

也就是,如果为True,h是Dog或者Dog的子类。
h继承链往上的父类都可以返回True。

可以判断对象是否为一堆类里边的某一种(或其子类)
isinstance([1, 2], (list, tuple))

dir()

获得一个对象的属性和方法
dir(对象)
返回一个list,元素是属性名和方法名的字符串

getattr()、setattr()、hasattr()操作对象的状态

可以操作对象的属性
也可以操作对象的方法

你可能感兴趣的:(python)