小白的python笔记(进阶)

本笔记记录了python的函数式编程、模块的使用、面向对象编程以及利用特殊方法定制类


目录


函数式编程

支持高阶函数:函数可以作为变量传入
支持闭包:用于返回函数
有限度地支持匿名函数

高阶函数

高阶函数:能够接收函数作参数的函数
- 变量可以指向函数
- 函数名其实是指向函数的变量

ex(例):
    def add(x, y, f):
        return f(x) + f(y)

map()函数

map() 参数: 一个函数 f 和一个 list
通过把函数 f 依次作用在 list 的每个元素上,得到一个的 list 并返回

ex:
    def f(x):
        return x*x
    print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])

    ⇒ [1, 4, 9, 10, 25, 36, 49, 64, 81]

reduce()函数

reduce() 参数: 一个函数 f 、一个 list、[一个初始值(可选)]
对list的每个元素反复调用函数f,并返回最终结果值

ex:
    def f(x, y):
        return x + y
    reduce(f, [1, 3, 5, 7, 9], 100)

    ⇒125

filter()函数

filter() 参数: 一个函数 f 和一个 list
[这个函数 f 的作用是对每个元素进行判断,返回 True或 False]
filter()根据判断结果自动过滤掉不符合条件的元素,返回由符合条件元素组成的的list。

ex:
    def is_odd(x):
        return x % 2 == 1
    filter(is_odd, [1, 4, 6, 7, 9, 12, 17])

    ⇒[1, 7, 9, 17]

sorted()函数

sorted() 参数: list、[f() 比较函数]
比较函数的定义:传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0

#正序比较函数
ex:
    def cmp(x, y):
        if x < y:
            return -1
        if x > y:
            return 1
        return 0
ex:
>>> sorted([36, 5, 12, 9, 21], reversed_cmp)  #倒序比较函数
[36, 21, 12, 9, 5]

返回函数

变量可以指向函数,函数名本身就是指向函数的变量,所以可以返回该变量即返回函数(达到延迟计算的作用——可以在后续代码中决定是否调用该函数)
x = f() # 调用f()、 x只是f返回的函数
return abs #返回函数
return abs(x) #返回函数值

ex:
    def f():
        print 'call f()...'
        # 定义函数g:
        def g():
            print 'call g()...'
        # 返回函数g:
        return g

python闭包

在函数内部定义的函数和外部定义的函数是一样的,只是他们无法被外部访问
闭包(Closure):像这种内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况
注:确保引用的局部变量在函数返回后不能变,所以返回函数不能引用循环变量

ex:
    def calc_sum(lst):
        def lazy_sum():
            return sum(lst)
        return lazy_sum

#若lst是循环变量,那么此式子不能达到预期效果

匿名函数

匿名函数 lambda x: x * x
关键字lambda 表示匿名函数,冒号前面的 x 表示函数参数
匿名函数有个限制,就是只能有一个表达式,不写return,返回值就是该表达式的结果

ex:
    def f(x):
    return x * x
    <==> lambda x:  x * x

    >>> map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
    [1, 4, 9, 16, 25, 36, 49, 64, 81]

#极大地简化了式子

装饰器

运行时动态添加功能
极大地简化代码,避免每个函数编写重复性代码

ex:
    def f1(x):
        return x*2
    def new_fn(f):    #装饰器函数
        def fn(x):
            print 'call %s()' % f.__name__
        return fn

    >>> g1 = new_fn(f1)
    >>> g1(5)
    ⇒ 10

    >>> f1 = new_fn(f1)     #彻底隐藏f1原始定义函数
    >>> f1(5)
    等价于
    @new_fn
    def f1(x):
        return x*2
    >>> f1(5)     #直接调用已经修饰过的f1

@装饰器的几个内置用法
- @log:打印日志
- @performance:检测性能
- @transaction:数据库事务
- @post(‘/register’):URL路由

无参decorator

@log() 搞定

考察一个@log的定义:

def log(f):
    def fn(x):
        print 'call ' + f.__name__ + '()...'
        return f(x)
    return fn

@log 写死了只含一个参数的返回函数, 对于有多个参数的函数会报错,需要将fn(x)改为fn(*args,**kw)

有参decorator

@log(参数) 搞定
需要多一个参数来区分不同的log,’Debug’还是’Info’

ex:
    def log(prefix):
        # 标准装饰器
        def log_decorator(f):
            def wrapper(*args, **kw):
                print '[%s] %s()...' % (prefix, f.__name__)
                return f(*args, **kw)
            return wrapper
        #返回装饰器
        return log_decorator

    @log('DEBUG')
    def test():
        pass
    print test()

完善decorator

当装饰了f1()之后,调用f1.__name__*会返回装饰器中新函数的函数名,而非本函数!
修改:标准装饰器代码后加上@functools.wraps(f)

ex:
    import functools
    def log(f):
        @functools.wraps(f)
        def wrapper(*args, **kw):
            print 'call...'
            return f(*args, **kw)
        return wrapper

python中偏函数

当一个函数有很多参数时,调用者就需要提供多个参数。如果减少参数个数,就可以简化调用者的负担。

如:int()函数还提供额外的base参数,默认值为10。如果传入base参数,就可以做 N 进制的转换:

ex:
    >>> int('12345')
    12345
    #加入base参数
    >>> int('12345', base=8)
    5349
    >>> int('12345', 16)
    74565

    #定义int2使得调用它就能直接将二进制数转换成十进制数
    def int2(x, base=2):
        return int(x, base)
    >>> int2('1000000')
    64

    # functools.partial就是帮助我们创建一个偏函数的,不需要我们自己定义int2(),可以直接使用下面的代码创建一个新的函数int2
    >>> import functools
    >>> int2 = functools.partial(int, base=2)  【函数名,可选参数】
    >>> int2('1000000')
    64

#结论:functools.partial可以把一个参数多的函数变成一个参数少的新函数,少的参数需要在创建时指定默认值,这样,新函数调用的难度就降低了。
ex:(另外一个栗子)
    import functools

    sorted_ignore_case = functools.partial(sorted,cmp = lambda x,y: cmp(x.upper(), y.upper()))

    print sorted_ignore_case(['bob', 'about', 'Zoo', 'Credit'])

模块

test.py <—— 自身模块名test
import math <——- 引用math模块
math.pow(2,5) <——– 调用math模块中的函数
注意:需要引入完整模块(ex: p1.math.pow)以防止函数名或变量名命名重复


类比于文件系统
包 <——-> 文件夹
模块 <——–> .py文件
包可以有多层
区别包和目录:包每层必须要有一个__init__*的.py文件

模块的导入及其动态导入

导入模块方法:
- import math.pow
- from math import pow,sin,cos

动态导入模块方法:

#若cStringIO模块存在,优先导入;否则导入StringIO
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO

__future__*的使用

要“试用”某一新的特性,就可以通过导入_future_模块的某些功能来实现。

ex:
    #在python2.7中引入python3.*的除法规则
    >>> from __future__ import division
    >>> print 10 / 3
    3.3333333333333335

安装第三方模块

通过pip来完成第三方模块的安装
例: pip install web.py
通过访问https://pypi.python.org来查询第三方库


面向对象编程

python之定义类并创建实例

class Person(object):
    def __init__(self, name):
        self.name = name
p1 = Person('xiaoming')

python中创建实例属性

# 由于Python是动态语言,对每一个实例,都可以直接给他们的属性赋值
class Person(object):
    pass
xiaoming = Person()
xiaoming.name = 'Xiao Ming'
xiaoming.gender = 'Male'
xiaoming.birth = '1990-1-1'

python中初始化实例属性

__init__*方法的第一个参数必须为self, python的实例方法的第一个参数也必须为self

class Person(object):
    def __init__(self, name, gender, birth):
        self.name = name
        self.gender = gender
        self.birth = birth
# 请定义Person类的__init__方法,除了接受 name、gender 和 birth 外,还可接受任意关键字参数,并把他们都作为属性赋值给实例?
# 要定义关键字参数,使用 **kw;
class Person(object):
    def __init__(self, name, gender, birth, **kw):
        self.name = name
        self.gender = gender
        self.birth = birth
        for k, v in kw.iteritems():
            setattr(self, k, v)  #设置属性
xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')
print xiaoming.name
print xiaoming.job

python中访问限制

Python对属性权限的控制是通过属性名来实现的,如果一个属性由双下划线开头(__),该属性就无法被外部访问。
例如: __score(相当于私有成员)

python中创建类属性

实例属性每个实例各自拥有,互相独立,而类属性有且只有一份
实例无法修改类属性

class Person(object):
    address = 'Earth'    # 类属性
    def __init__(self, name):
        self.name = name

# 每创建一个实例类属性count就加一
class Person(object):
    count = 0
    def __init__(self, name):
        self.name = name
        Person.count = Person.count + 1

python中定义实例方法

类中的定义方法都要比调用时一个self参数
类中方法和函数的区别在于是否需要传入self

python中定义类方法

class Person(object):

    __count = 0

    @classmethod   # 定义类方法
    def how_many(cls):  
        return cls.__count   # 相当于 Person.__count

    def __init__(self,name):
        self.name = name
        Person.__count = Person.__count + 1

print Person.how_many()

p1 = Person('Bob')

print Person.how_many()

继承

继承现有类的所有功能,只要编写现有类所缺少的功能

python继承一个类

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

# Student继承Person
class Student(Person):
    def __init__(self, name, gender, score):
        #初始化父类
        super(Student, self).__init__(name, gender)
        #将额外的score属性添上
        self.score = score

python中判断类型

函数isinstance()可以判断一个变量的类型,既可以用在Python内置的数据类型如str、list、dict,也可以用在我们自定义的类

p = Person('Tim', 'Male')
s = Student('Bob', 'Male', 88)
>>> isinstance(p, Person)       --> True
>>> isinstance(s, Person)       --> True(子类是父类类型)
>>> isinstance(p, Student)       --> False
>>> isinstance(s, Student)       --> True

多态:方法的覆盖

python中多重继承

Python允许从多个父类继承,称为多重继承。

class D(B, C):    #继承自两个父类
    def __init__(self, a):
        super(D, self).__init__(a)
        print 'init D...'

python中获取对象信息

用 type() 函数获取变量的类型
用 dir() 函数获取变量的所有属性
用 getattr() 和 setattr( )函数获取和设置属性

>>> s = Student('Bob', 'Male', 88)
>>> type(s)
<class '__main__.Student'>

>>> dir(123)   # 整数也有很多属性...
['__abs__', '__add__', '__and__', '__class__', '__cmp__', ...]


>>> getattr(s, 'name')  # 获取name属性
'Bob'
>>> setattr(s, 'name', 'Adam')  # 设置新的name属性

定制类

python的特殊方法

特殊方法定义在class中,不需要我们直接调用,而python的某些函数或者操作符会调用这些特殊方法
正确实现特殊方法:1、编写用到的特殊方法。2、有关联性的方法都得实现,例如:__setattr__*,__getattr__*,__delattr__*
常见的特殊方法:1、用于print的__str__*; 2、用于len的__len__*;3、用于cmp的__cmp__*。

__str__*、 __repr__*、__cmp__*和__len__*

如果要把一个类的实例变成str,就得实现__str__*
因为 Python 定义了 _str_*()和_repr_*()两种方法,_str_*()用于显示给用户,而_repr_*()用于显示给开发人员。
偷懒地定义__repr__*的方法: __repr__ = __str__

def __cmp__(self, s):
        if self.score == s.score:
            return cmp(self.name, s.name)
        return -cmp(self.score, s.score)

def __len__(self):
        return len(self.names)
斐波那契数列是由 0, 1, 1, 2, 3, 5, 8...构成。

请编写一个Fib类,Fib(10)表示数列的前10个元素,print Fib(10) 可以打印出数列的前 10 个元素,len(Fib(10))可以正确返回数列的个数10?

class Fib(object):
    def __init__(self, num):
        a,b,L = 0,1,[]
        for n in range(num):
            L.append(a)
            a,b = b,a+b
        self.numbers = L

    def __str__(self):
        return str(self.numbers)

    __repr__ = __str__

    def __len__(self):
        return len(self.numbers)

f = Fib(10)
print f
print len(f)

python中数学运算(类)

  • 加法运算: __add__*
  • 减法运算: __sub__*
  • 乘法运算: __mul__*
  • 除法运算: __div__*
    外部调用时直接用操作符+、-、*和/调用

python中类型转换

  • (有理数实例)转换为整型: __int__*
  • 转换为浮点数: __float__*

python中 @property

考虑到直接给属性赋值无法检查(属性)分数的有效性

# 用装饰器将getter和setter函数装饰成属性调用
class Student(object):
    def __init__(self, name, score):
        self.name = name
        self.__score = score
    @property
    def score(self):
        return self.__score
    @score.setter
    def score(self, score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score

# 结果
>>> s = Student('Bob', 59)
>>> s.score = 60
>>> print s.score
60
>>> s.score = 1000
Traceback (most recent call last):
  ...
ValueError: invalid score

python中 __slots__*

slots是指一个类允许的属性列表:用于限制实例自行添加属性

class Student(object):
    #类的实例只能操作这三个属性
    __slots__ = ('name', 'gender', 'score')
    def __init__(self, name, gender, score):
        self.name = name
        self.gender = gender
        self.score = score

python中 __call__*

一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法call()。

class Person(object):
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

    # Person实例可以接受一个参数(字符串)进行调用
    def __call__(self, friend):
        print 'My name is %s...' % self.name
        print 'My friend is %s...' % friend

>>> p = Person('Bob', 'male')
>>> p('Tim')         # 调用p
My name is Bob...
My friend is Tim...

单看 p(‘Tim’) 你无法确定 p 是一个函数还是一个类实例,所以,在Python中,函数也是对象,对象和函数的区别并不显著


注:s.strip() #删去字符串s中首部和尾部的空字符(\n, \r等)
__str__*等这些特殊方法的*号没有任何意义,只是去掉后在markdown中直接显示为粗体的str,万分抱歉
while len(L) < num :
⇒ 等价于
for n in range(num) :

猜你喜欢

转载自blog.csdn.net/tedone_lz/article/details/53151119