python学习笔记(四)

本文深入讲解Python中的高级特性,包括map、reduce、filter、sorted函数的使用,返回函数、闭包、匿名函数、装饰器、偏函数的概念及应用,动态模块导入、__future__使用、类的定义与实例化、类属性、实例方法、类方法、继承、多重继承、类的特殊方法等,帮助读者全面掌握Python高级编程技巧。

1. map()函数

高阶函数,它接收一个函数 f 和一个 list,并通过把函数 f 依次作用在 list 的每个元素上,得到一个新的 list 并返回,不改变原有列表。

def format_name(s):
    return s[0].upper()+s[1:].lower()
    
print map(format_name, ['adam', 'LISA', 'barT'])
输出:['Adam', 'Lisa', 'Bart']

2. reduce()函数

高阶函数,接收参数一个函数 f,一个list,f 必须接收两个参数,reduce()对list的每个元素反复调用函数f,并返回最终结果值。f还可以接收第三个参数,作为初始计算值。

def prod(x, y):
    return x*y

print reduce(prod, [2, 4, 5, 7, 12])
计算过程:2*4 = 8,8*4 = 32....
输出:3360

3. filter()函数

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

import math
def is_sqr(x):
    return int(math.sqrt(x))**2==x
  
print filter(is_sqr, range(1, 101))
输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

4. sorted()函数

高阶函数,对list进行排序,可以接收一个比较函数来实现自定义排序,比较函数的定义是,传入两个待比较的元素 x, y,如果 x 应该排在 y 的前面,返回 -1,如果 x 应该排在 y 的后面,返回 1。如果 x 和 y 相等,返回 0,默认从小到大排序。

#自定义排序函数
def cmp_ignore_case(s1, s2):
    if s1.upper()>s2.upper():
        return 1
    if s1.upper()<s2.upper():
        return -1
    else:
        return 0
print sorted(['bob', 'about', 'Zoo', 'Credit'],cmp_ignore_case) 
#这里函数必须放在列表后面,不然会报函数对象不是迭代错误!

5. python中返回函数

def calc_sum(lst):
    def lazy_sum():
        return sum(lst)
    return lazy_sum
#这里内层函数引用了外层函数的变量lst,称之为闭包。
>>> f = calc_sum([1, 2, 3, 4])
>>> f #f是个函数,参数已经确定
<function lazy_sum at 0x1037bfaa0>
>>> f() #调用f函数,输出值
>>> 10

返回函数不要引用任何循环变量,或者后续会发生变化的变量。

def count():
    fs = []
    for i in range(1, 4):
        def f(j): #闭包函数g没有直接引用循坏变量i,所以可以获得3个参数值不一样的函数。
            def g():
                return j*j
            return g
        fs.append(f(i))
    return fs

f1, f2, f3 = count()
print f1(), f2(), f3()
输出:149

6. 匿名函数

lambda x: x * x 匿名函数只能有一个表达式,不写return

#strip()用于去除字符串首尾的指定字符,默认空格或换行符
print filter(lambda s : s and len(s.strip())>0,['test', None, '', 'str', '  ', 'END'])

7. decorator 装饰器

当要对原有函数进行修改是,可以通过高阶函数返回新函数,并将其传给原有函数名,从而覆盖原有函数。可以减少重复性代码。
Python中的@语法是为了简化装饰器调用。
@log 打印日志
@performance 检测性能
@transaction 数据库事物
@#post(’/register’) URL路由

Python的 *args 和 kw,保证任意个数的参数总是能正常调用
args表示任何多个非关键字参数,它是一个tuple;**kwargs表示关键字参数,它是一个dict。并且同时使用args和
kwargs时,必须*args参数列要在**kwargs前

import time
#不带参数的decorator,f是要检测的函数
def performance(f):
    def fn(*args,**kw):
        t1 = time.time() #函数执行前时间
        r = f(*args,**kw)
        t2 = time.time() #函数执行后时间
        print 'call %s() in %d' %(f.__name__,t2-t1) #f.__name__  是函数名
        return r
    return fn

@performance
def factorial(n):
    return reduce(lambda x,y: x*y, range(1, n+1))

print factorial(10)
输出:
call factorial() in 0
3628800
############有参数的decorator########
import time

def performance(unit): #unit参数
    def log_decorator(f): #f函数作为参数
    	@functools.wraps(f) #把原函数属性复制到新属性中,在返回的新函数前用
        def fn(*args,**kw):
            t1 = time.time()
            r = f(*args,**kw)
            t2 = time.time()
            print 'call %s() in %d%s' %(f.__name__,t2-t1,unit)
            return r
        return fn
    return log_decorator

@performance('ms')
def factorial(n):
    return reduce(lambda x,y: x*y, range(1, n+1))

print factorial(10)
输出:
call factorial() in 0ms
3628800

decorator返回的新函数函数名已经不是’factorial’,而是@log内部定义的’fn’,这对于那些依赖函数名的代码就会失效。所以需要把原函数的一些属性复制到新函数中。用functools.wraps(f)

8、偏函数

functools.partial可以把一个参数多的函数变成一个参数少的新函数,少的参数需要在创建时指定默认值,这样,新函数调用的难度就降低了。

>>> import functools
>>> int2 = functools.partial(int, base=2) #转化为二进制,这样就不用每次都输入base参数
>>> int2('1000000')
64
#cmp(a,b) 如果啊a<b 返回-1,a>b 返回1 ,否则 0
>>> sorted_ignore_case = functools.partial(sorted,cmp =  lambda s1,s2:cmp (s1.lower(),s2.lower())) #从小到大排序
>>> print sorted_ignore_case(['bob', 'about', 'Zoo', 'Credit'])
['about', 'bob', 'Credit', 'Zoo']

9. 动态模块导入

导入模块错误是执行其他导入

try:
    import json
except ImportError:
    import simplejson as json

10. 使用__future__

可以在Python旧版本中引入新版本的功能

#在Python 3.x中,字符串统一为unicode,2.7则要加u
from __future__ import unicode_literals

s = 'am I an unicode?'
print isinstance(s, unicode)

11.类

按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。
类的实例属性可以像变量一样操作。
__attr :两个下划线开头的属性是私有属性,无法被外部访问。

class Person(object):
    pass
#可以为类实例分别定义不同属性
p1 = Person()
p1.name = 'Bart' 
p2 = Person()
p2.grade = 2
#可以为Person类添加一个特殊的__init__(self)方法,这样类实例都会有方法里定义的属性
#**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(): #遍历kw关键字参数,self.k = v
            setattr(self,k,v)
xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student',age = 19)

print xiaoming.name
print xiaoming.job

类属性

当实例属性和类属性重名时,实例属性优先级高

#__init__之前写的属性,可以不用先创建实例,再访问,放入实例也可以访问这个属性
class Person(object):
    count = 0 #定义初始值
    def __init__(self,name):
        self.name = name
        Person.count += 1 #每创建一个实例都会调用一次__init__,count属性就会+1

实例方法和类实例

实例的方法就是在类中定义的函数,它的第一个参数永远是 self,调用实例方法必须在实例上调用,其他参数和一个普通函数是完全一样。
在实例方法内部,可以访问所有实例属性,这样,如果外部需要访问私有属性,可以通过方法调用获得

class Person(object):

    def __init__(self, name, score):
        self.name = name
        self.score = score
        self.get_grade = lambda: 'A' #这里的get_grade是函数,因为不需要实例传入参数

p1 = Person('Bob', 90)
print p1.get_grade
print p1.get_grade()

类方法
在class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。

class Person(object):

    __count = 0

    @classmethod #将方法绑定到Person类上
    def how_many(cls): #参数名为cls,cls.__count 相当于 Person.count
        return cls.__count 
    def __init__(self,name):
        self.name = name
        Person.__count+=1

print Person.how_many() #直接访问类方法

12. 类的继承

Python从一个类继承,可以是object,class MyClass (object): pass
调用super().__init__初始化父类

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

class Teacher(Person):
#super(Teacher,self)返回Teacher继承的父类Person,然后调用__init__方法初始化父类,不然没有name,gender属性,__init__中self已经在super中隐式传入,不能写
    def __init__(self, name, gender, course):
        super(Teacher,self).__init__(name,gender)
        self.course = course
p = Person('Tim', 'Male')
t = Teacher('Alice', 'Female', 'English')
isinstance(p,Teacher) 
False #不能认为父类是子类,因为子类比父类多了写属性和方法
isinstance(t,Person) 
True #子类可以认为是父类

如果父类和子类有相同的方法,那么方法调用将作用在实际类型上,这个行为叫多态。

多重继承
从多个父类继承,称为多重继承。
dir()返回的属性是字符串列表,如果已知一个属性名称,要获取或者设置对象的属性,就需要用 getattr() 和 setattr( )函数了。
getattr(s, 'age', 20) 获取s的age属性值,没有就返回20
setattr(s, 'name', 'Adam') 设置name属性值,没有就新增属性

13.python 中的一些特殊方法

定义在类中,把类的实例变成str就需要用到__str__()特殊方法或__repr__()方法,其中__str__()是给用户看,而__repr__()是给开发人员看。

 class Student(Person):

    def __init__(self, name, gender, score):
        super(Student, self).__init__(name, gender)
        self.score = score

    def __str__(self):#定义print实例时的输出形式
        return '(Student:%s,%s,%s)' %(self.name,self.gender,self.score) 
    def __cmp__(self, s): #对类的实例进行排序需要用到__cmp__()
        if self.score == s.score:
            return cmp(self.name, s.name) #成绩一样的按名字排序,列表元素仅是类实例,否则会报错
        return -cmp(self.score, s.score)

如果一个类表现得像一个list,要获取有多少个元素,就得用__len()__ 函数。

#斐波那契数列
class Fib(object):

    def __init__(self, num):
        a,b = 0,1
        l = []
        for i in range(num):
            l.append(a)
            a,b = b,a+b
        self.numbers = l #初始化numbers属性,并复制l
        
    def __str__(self): #把实例变成字符串格式,不然print f时不是列表形式,不过这也不影响计算实例元素个数!
        return str(self.numbers)
    def __len__(self):
        return len(self.numbers)

f = Fib(10)
print f
print len(f)
from __future__ import division
class Rational(object):
    def __init__(self, p, q):
        self.p = p
        self.q = q

    def __int__(self):
        return self.p // self.q

    def __float__(self):
        return self.p / self.q


print int(Rational(7, 2))
print float(Rational(1, 3))

@property

class Student(object):

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

    @property
    def score(self): #获取成绩,不需要参数
        return self.__score

    @score.setter #是@property 的副产品,设置成绩,要有一个score参数
    def score(self,score):
        if score < 0 or score > 100:
            raise ValueError('invalid score')
        self.__score = score
        
    @property
    def grade(self): #相当于新增属性grade
        if self.score >= 80:
            return 'A'
        elif self.score >= 60:
            return 'B'
        return 'C'

s = Student('Bob', 59)
print s.grade

s.score = 60
print s.grade

s.score = 99
print s.grade

Python是动态语言,任何实例在运行期都可以动态地添加属性。如果要限制添加属性的范围,可以用__slots__来实现。

class Person(object):
	#限制属性范围,放在__init__之前
    __slots__ = ('name', 'gender')
    def __init__(self, name, gender):
        self.name = name
        self.gender = gender

所有的函数都是可调用对象,一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()。

class Fib(object):

    def __call__(self,num):
        a,b,l = 0,1,[]
        for i in range(num):
            l.append(a)
            a, b = b, a + b
        return l
    

f = Fib()
print f(10) #调用实例对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值