python复习之中级
一、函数
A、函数介绍
a.1、什么是函数
- 函数就是抽象计算过程,调用相应的函数,返回结果;
a.2、内置函数
- map
def f(x): return x*x print map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
reduce()
def prod(x, y): return x*y print reduce(prod, [2, 4, 5, 7, 12])
filter()
import math def is_sqr(x): if math.sqrt(x) % 1 == 0: return x print filter(is_sqr, range(1, 101)) #[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
sorted()
#输入:['bob', 'about', 'Zoo', 'Credit'] #输出:['about', 'bob', 'Credit', 'Zoo'] def cmp_ignore_case(s1, s2): s1 = s1.upper() s2 = s2.upper() if s1 < s2: return -1 if s1 > s2: return 1 return 0 print sorted(['bob', 'about', 'Zoo', 'Credit'], cmp_ignore_case)
a.3、定义函数
- 格式>
def function(args): print('Hello %s.' % args) function('coob') #Hello coob.
- 返回值>返回值-返回函数
def f(): print 'call f()...' # 定义函数g: def g(): print 'call g()...' # 返回函数g: return g
- 参数: 默认参数 x, 可变参数 *argrs 可传入任意个参数, 字典参数**kwargs;
- 返回值:return,如果没有return语句,函数执行完毕后也会返回结果,只是结果为 None,return None可以简写为return;
a.4、闭包
- 介绍:内层函数引用了外层函数的变量(参数也算变量),然后返回内层函数的情况,称为闭包(Closure)。
例:
def calc_sum(lst): def lazy_sum(): return sum(lst) return lazy_sum
- 特点:返回的函数还引用了外层函数的局部变量,所以,要正确使用闭包,就要确保引用的局部变量在函数返回后不能变。举例如下:
#返回闭包不能引用循环变量,请改写count()函数,让它正确返回能计算1x1、2x2、3x3的函数。 def count(): fs = [] for i in range(1, 4): def f(j): def g(): return j*j return g r = f(i) fs.append(r) return fs f1, f2, f3 = count() print f1(), f2(), f3()
a.5、匿名函数
- 介绍:只能有一个表达式,
map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
示例
# 利用匿名函数简化以下代码: def is_not_empty(s): return s and len(s.strip()) > 0 print filter(lambda s: s and len(s.strip()) > 0, ['test', None, '', 'str', ' ', 'END'])
B、装饰器
b.1、问题:
- 定义了一个函数,想在运行时动态增加功能,又不想动态改变函数本身的代码,比如说 每次运行函数我都要知道该函数运行花了多长时间,那么就用装饰器吧!
- 封装、代码复用;
def new_fn(f): def fn(x): print('call' + f.__name__ + '()') return f(x) return fn @new_fn def f1(x): return x*x # f1 = new_fn(f1) # print(f1(5)) print(f1(3)) # callf1() # 9
示例一 :
import time def performance(f): def fn(*args, **kw): t1 = time.time() r = f(*args, **kw) t2 = time.time() print 'call %s() in %fs' % (f.__name__, (t2 - t1)) return r return fn @performance def factorial(n): return reduce(lambda x,y: x*y, range(1, n+1)) print factorial(10)
示例二:
import time def performance(unit): def a(f): def b(*args,**kw): t1 = time.time() r = f(*args,**kw) t2 = time.time() t = (t2-t1)*1000 if unit == 'ms' else (t2-t1) print'call %s() in %s' % (f.__name__, t) return r return b return a @performance('ms') def factorial(n): return reduce(lambda x,y: x*y, range(1, n+1)) print factorial(10)
示例三: @functools.wraps(f) 没有该装饰器对于那些依赖函数名的代码就会失效;
import time, functools def performance(unit): def a(f): @functools.wraps(f) def b(*args,**kw): t1 = time.time() r = f(*args,**kw) t2 = time.time() t = (t2-t1)*1000 if unit == 'ms' else (t2-t1) print'call %s() in %s' % (f.__name__, t) return r return b return a @performance('ms') def factorial(n): return reduce(lambda x,y: x*y, range(1, n+1)) print factorial.__name__
C、偏函数
c.1、自我理解,即是对原函数的基础上进行改造,让原函数只实现自身某一部分的功能或者类似的功能。
示例:
>>> import functools >>> int2 = functools.partial(int, base=2) >>> int2('1000000') 64 >>> int2('1010101') 85
D、模块
d.1、介绍
d.2、包和模块区别
包就是一个文件件,里面必须要有个 "__init__.py"的文件,目的是将文件夹变为一个Python模块,
C、高阶函数
b.1、递归
- 递归函数的优点是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰;
- 使用递归函数需要注意防止栈溢出;
二、类
A、介绍
面向对象三大特性(封装、继承、多态)
B、成员
b.1、属性
- __xxx__:如果一个属性以该形式定义,这种定义被称为特殊属性、_xxx:可以在子类中使用、__xxx:不可以在子类中使用(无法被外部访问)
- 所有实例都可以访问类的属性,并且,所有实例访问的类属性都是同一个!也就是说,实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。
class Person(object): address = 'Earth' def __init__(self, name): self.name = name print Person.address # => Earth
- 直接通过类访问,当然实例也是可以直接访问类属性的,
p1 = Person('Bob') p2 = Person('Alice') print p1.address # => Earth print p2.address # => Earth
- 由于Python是动态语言,类属性也是可以动态添加和修改的,注意千万不要在实例上修改类属性,它实际上并没有修改类属性,而是给实例绑定了一个实例属性。
Person.address = 'China' print p1.address # => 'China' print p2.address # => 'China'
接收任意额外的关键字参数
class Person(object): def __init__(self, name, gender, **kw): self.name = name self.gander = gender for k,v in kw.items(): setattr(self, k, v) p = Person('Bob', 'Male', age=18, course='Python') print p.age print p.course
b.2、实例方法
- 实例的方法就是在类中定义的函数,它的第一个参数永远是 self,指向调用该方法的实例本身,其他参数和一个普通函数是完全一样的:
- 在实例方法内部,可以访问所有实例属性,这样,如果外部需要访问私有属性,可以通过方法调用获得,这种数据封装的形式除了能保护内部数据一致性外,还可以简化外部调用的难度。
class Person(object): def __init__(self, name): self.__name = name def get_name(self): return self.__name #调用 p1 = Person('Bob') print p1.get_name() # self不需要显式传入 # => Bob
b.3、类方法
- 要在class中定义类方法,需要这么写;
- 类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.count 实际上相当于 Person.count;
- 因为是在类上调用,而非实例上调用,因此类方法无法获得任何实例变量,只能获得类的引用;
class Person(object): count = 0 @classmethod def how_many(cls): return cls.count def __init__(self, name): self.name = name Person.count = Person.count + 1 print Person.how_many() p1 = Person('Bob') print Person.how_many() 0 1
b.4、调用时不用加()的装饰器
@property 装饰器:调用时不用加
b.5、属性和方法总结
- 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
- 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
- 静态方法:由类调用;无默认参数;
-
class Foo: #静态方法 @staticmethod def xo(arg1, arg2): #无默认参数,可不传参数,可传任意参数 print("xo") #类方法 @classmethod def xxoo(cls): #定义类方法,至少有一个cls参数 print(cls) #普通方法,类中 def show(self): #定义普通方法,至少有一个self参数 print("show") # 调用静态方法 Foo.xo(1,2) # 调用类方法 Foo.xxoo() # 调用普通方法 obj = Foo: obj.show()
C、类的继承
c.1、示例:
class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender
- 开始继承 注意:super(子类名, self).__init__(父类属性)的用法
class Student(Person): def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = score
- 一定要用 super(Student, self).__init__(name, gender) 去初始化父类,否则,继承自 Person 的 Student 将没有 name 和 gender。
使用super()的漂亮之处在于,你不需要明确给出任何基类名字,这意味着如果你改变了类继承关系,你只需要改一行代码(class语句本身)而不必在大量代码中去查找所有被修改的那个类的名字。 ------《Python核心编程》P358
c.2、python中判断类型
- 函数isinstance()可以判断一个变量的类型,既可以用在Python内置的数据类型如str、list、dict,也可以用在我们自定义的类,它们本质上都是数据类型。
- 自我总结,子类属于父类,父类不属于子类;
class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender class Student(Person): def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = score class Teacher(Person): def __init__(self, name, gender, course): super(Teacher, self).__init__(name, gender) self.course = course t = Teacher('Alice', 'Female', 'English') print isinstance(t, Person) #T print isinstance(t, Student) #F print isinstance(t, Teacher) #T print isinstance(t, object) #T
c.3、多态
假如父类与子类都拥有相同的方法,在调用的过程优先使用自己的方法,如果自己没有就使用父类的方法,这种行为我们称之为多态;
D、特殊方法
d.1、介绍:
- 特殊方法定义在class中
- 不需要直接调用
- Python的默写函数或操作符会调用对应的特殊方法
d.2、重写特殊方法:
- __str__ 与 __repr__ , 后者是在终端下 敲s 结果与 前者一样
class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender class Student(Person): def __init__(self, name, gender, score): super(Student, self).__init__(name, gender) self.score = score def __str__(self): return '(Student: %s, %s, %s)' % (self.name, self.gender, self.score) __repr__ = __str__ s = Student('Bob', 'male', 88) print s #(student: bob, male, 88)
E、设置类的一些方法
d.1、type
>>> type(123) <type 'int'> >>> s = Student('Bob', 'Male', 88) >>> type(s) <class '__main__.Student'>
d.2、 dir()
>>> dir(123) # 整数也有很多属性... ['__abs__', '__add__', '__and__', '__class__', '__cmp__', ...] >>> dir(s) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'gender', 'name', 'score', 'whoAmI']
d.3、filter()
d.4、getattr() 当name 不存在时,会报错;
>>> getattr(s, 'name') # 获取name属性 'Bob'
d.5、setattr()
>>> setattr(s, 'name', 'Adam') # 设置新的name属性 >>> s.name 'Adam'