1:匿名函数: lambda x: x * x
1:函数有个限制,就是只能有一个表达式,自动把表达式结果作为函数返回值返回,参 数可以指定,也可以不指定,在表达式中 可以使用在该处可用的变量
2:匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函 数f = lambda x: x * x f(5)=25
也可以把匿名函数作为返回值返回,比如:
def build(x, y):
return lambda: x * x + y * y
build(1,2)得到函数。build(1,2)()值为3
2:装饰器:
1:函数对象有一个__name__属性,可以拿到函数的名字:function._name_
2:def log(func):
@functools.wraps(func)
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw) #这里带括号,实际是调用func()
return wrapper
@log
def now(var):
print('2015-3-25')
@log作用相当于:now=log(now),即now指向wraper.
now('message') 其实执行的是wraper(),函数先打印一行语句,再返回调用原函数。如果now无参数,只需要去掉wrapper定义的形式参数,和返回调用的func的实际参数。
使用 @functools.wraps(func),经过装饰器后的Now函数的_name_属性仍然指向now,不加就会指向wrap
3:带参数
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)#这里带括号,实际是调用func()
return wrapper
return decorator
@log('execute')
def now( var):
print('2015-3-25')
@log('execute')作用:now=log("execute")(now),先得到decorator函数,再把now作为参数调用decorator函数,最终now 指向wrapper.调调用now('meaage'),如果now无参数,只需要去掉wrapper定义的形式参数,和返回调用的func的实际参数。
3:偏函数
1:使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单
2:newfunction= functools.partial(function, 默认 参数名称=新加的默认值数值),新创建的函数,也可在调用时传入新的默认参数值,获得不同的结果。newfunction(1,base=2)
3:创建偏函数时,实际上可以接收函数对象、`*args`和`**kw`这3个参数,
1:int2 = functools.partial(int, base=2)等价于
kw = { 'base': 2 }
int('10010', **kw)
2:max2 = functools.partial(max, 10)等价于max2(1,2)等价于 max(10,1,2)即实际上会把10作为*args的一部分自动加到左边
4:模块:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
' a test module '#任何模块代码的第一个字符串都被视为模块的文档注释
__author__ = 'Michael Liao'
第1行和第2行是标准注释,第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行,第2行注释表示.py文件本身使用标准UTF-8编码;
args = sys.argv #先导入sys模块,args用于获得命令行参数,args至少有一个参数,即.py文件名。如python test.py message args参数就是:['test.py' ,'message']
def dunc():
pass
if __name__=='__main__':
func()
当我们在命令行运行模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。
5:变量作用域
正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,PI等;
类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的 __author__,__name__就是特殊变量,hello模块定义的文档注释也可以用特殊变量 __doc__ 访问,我们自己的变量一般不要用这种变量名;
类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如 _abc,__abc等;
该规则对变量名,函数名都起作用。
6:第三方模块:
在Python中,安装第三方模块,是通过包管理工具pip完成的。
Mac或Linux上有可能并存Python 3.x和Python 2.x,因此对应的pip命令是pip3。
pip install 库名
导入第三方模块:
import 模块名称。对于在包里面的模块:from 该py文件所在的父目录名import 模块名 as newName ,as newName可加可不加,
from package_1.package_2 import moduleNmae as newName
import 模块的部分成员。
from package_1.package_2.moduleName import 模块成员名称 as newANme from week_4.module_demo import func as newFunc
当我们试图加载一个模块时,Python会在指定的路径下搜索对应的.py文件,如果找不到,就会报错:默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中:
如果我们要添加自己的搜索目录,有两种方法:
一是直接修改sys.path,添加要搜索的目录:
命令行操作:
>>> import sys
>>> sys.path.append('filepath')
这种方法是在运行时修改,运行结束后失效。
二是添加到环境变量,参考配置Python环境。
使用 Anaconda管理包时IDE要使用base模式下的Anaconda目录下的python环境
7:面向对象
1:类是抽象的模板,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同
2:定义类是通过class关键字:
class Student(object):
pass
class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。
创建实例是通过类名+()实现的:
bart = Student()
3:由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name,score等属性绑上去:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,但self不需要传,Python解释器自己会把实例变量传进去:
bart = Student('Bart Simpson', 59)
不可以定义多个___init__函数实现重载。对于含参数的初始化函数,参数要全部传入
4:和普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。除此之外,类的方法和普通函数没有什么区别,所以,你仍然可以用默认参数、可变参数、关键字参数和命名关键字参数。
对于含有默认参数的函数的调用,对默认参数的修改可以使用关键字=新值得方式,或者与位置参数一样按位置依次赋值,位置参数,不能放到关键字参数后面。对于无法匹配的关键参数传入**kw中,对于位置不匹配的位置参数归入*args中。对于即含有默认参数又含有*args的函数对默认参数的修改只能通过位置参数的赋值方式。
5:类是创建实例的模板,而实例则是一个一个具体的对象,各个实例拥有的数据都互相独立,互不影响;
方法就是与实例绑定的函数,和普通函数不同,方法可以直接访问实例的数据;
通过在实例上调用方法,我们就直接操作了对象内部的数据,但无需知道方法内部的实现细节。
和静态语言不同,Python允许对实例变量绑定任何数据,也就是说,对于两个实例变量,虽然它们都是同一个类的不同实例,但拥有的变量名称都可能不同:即python每个类的实例的成员变量是动态定义的,每个实例可以拥有不同成员变量。
默认值就是python用来实现函数重载的重要方法。通过修改默认参数执行不同功能。
6:函数重载
from functools import singledispatch
@singledispatch
def func_0(obj):
print('%r'%(obj))
@func_0.register(int)
def _func_1(obj):
print('Integer: %d'%(obj))
@func_0.register(str)
def_func_2(obj):
print('String: %s'%(obj))
有两个关键的接口: singledispatch与register. 还需要注意, 定义重载函数时, 函数名(_func_1,_func_2)不能与被重载函数(func_0)一样, 那样会覆盖被重载函数, 导致报错. 另外, singledispatch只支持根据第一个参数的类型来重载.
8:类型限制
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。
def __init__(self, name, score):
self.__name = name
self.__score = score
外部代码要获取name和score,可以给Student类增加get_name和get_score这样的方法:
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__、__score__这样的变量名。
不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量
stu.__name = 'New Name'
实际上这个__name变量和class内部的__name变量不是一个变量!内部的__name变量已经被Python解释器自动改成了_Student__name,而外部代码给bart新增了一个__name变量
stu._NewStudent__name='newName'才能正确修改。不建议
9:继承
当子类和父类都存在相同的`run()`方法时,我们说,子类的`run()`覆盖了父类的`run()`,在代码运行的时候,总是会调用子类的`run()`。这样,我们就获得了继承的另一个好处:多态。
当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样。判断一个变量是否是某个类型可以用`isinstance()`判断:isinstance(a, list)得到true 或者false。在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:
__init__也方法会被继承,子类可以访问父类init方法中定义的public 变量,而private就无法访问。
对于普通的成员方法与成员变量,只能只能访问public类型的,无法访问private类型的。可以强行通过:_类型名__变量或者函数名来访问。
对父类方法重写,或者添加方法。
编写一个函数,这个函数接受一个`Animal`类型的变量:
```python
def run_twice(animal):
animal.run()
```
方法可以接受Animal ,Cat 等等对象,只要是`Animal`类或者子类,就会自动调用实际类型的`run()`方法。
调用方只管调用,不管细节,而当我们新增一种`Animal`的子类时,只要确保`run()`方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:
对于静态语言(例如Java)来说,如果需要传入`Animal`类型,则传入的对象必须是`Animal`类型或者它的子类,否则,将无法调用`run()`方法。
对于Python这样的动态语言来说,则不一定需要传入`Animal`类型。我们只需要保证传入的对象有一个`run()`方法就可以了:
```
class Timer(object):
def run(self):
print('Start...')
```
这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
10:获取对象信息
1:拿到一个对象的引用时,如何知道这个对象是什么类型:type()函数,type(cat)返回cat所属于的class.如果一个变量指向函数或者类,也可以用`type()`判断,返回函数所属于的class.type(abs),<class 'builtin_function_or_method'>
2:判断一个对象是否是函数,可以使用`types`模块中定义的常量:
```python
>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True
```3:isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。
并且还可以判断一个变量是否是某些类型中的一种,比如下面的代码就可以判断是否是list或者tuple:
isinstance([1, 2, 3], (list, tuple))
True
4:如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法:
>>> dir('ABC')
['__add__', '__class__',..., '__subclasshook__', 'capitalize', 'casefold',..., 'zfill']
类似__xxx__的属性和方法在Python中都是有特殊用途的,比如__len__方法返回长度。在Python中,如果你调用len()函数试图获取一个对象的长度,实际上,在len()函数内部,它自动去调用该对象的__len__()方法,所以,下面的代码是等价的:
>>> len('ABC')
3
>>> 'ABC'.__len__()
3
我们自己写的类,如果也想用len(myObj)的话,就自己写在class定义时定义一个__len__()方法。原理 :鸭子类。
5:配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态,
getattr(类的实例对象,属性名称,默认值):获得属性的值,私有参数不可正常访问,可以强行访问,如果该属性不存在,就返回默认值,如果不加默认值参数,如果属性不存在,就会报错。也可以用来操作类的函数,也能加入默认值参数。
hasattr((类的实例对象,属性名称),判断该实例化对对象是否有该属性,返回true,false.也可以用来操作类的函数。对于私有成员,无法访问全部返回false,强行访问:_Animal__func_1,_Animal__name
setattr((类的实例对象,属性名称,属性值)给实例化对像添加属性并赋值。新属性名即使私有,外界也可以访问。新属性必须赋值。新属性与已有属性重名,实现值覆盖。
通过内置的一系列函数,我们可以对任意一个Python对象进行剖析,拿到其内部的数据。要注意的是,只有在不知道对象信息的时候,我们才会去获取对象信息
6:由于Python是动态语言,根据类创建的实例可以任意绑定属性。
给实例绑定属性的方法是通过实例变量,或者通过self变量:
在class中定义属性,这种属性是类属性,这个属性虽然归类所有,但类的所有实例都可以访问到。Student.name,stu.name
在实例中绑定的属性归该实例所有,类无法自动添加该属性。如果实例属性,与类属性同名,通过实例访问的该属性值被新添加的覆盖,而对类没影响。使用 del stu.name删除实例与类同名属性,实例又可以访问到初始类里面的name值。
在编写程序的时候,千万不要对实例属性和类属性使用相同的名字,因为相同名称的实例属性将屏蔽掉类属性,但是当你删除实例属性后,再使用相同的名称,访问到的将是类属性。
7
class TestClass(object):
classval1 = 100 #类变量
def __init__(self):
self.memval2 = 200 #成员变量
self.memfuntion2(600)
def memfuntion1(self,val = 400):
localval3 = 300 #函数内部的局部变量
self.nmval4 = val
self.nmval5=500
classval1是类变量,可以由类名TestClass直接调用,也可以有对象inst来调用;
memval2是成员变量,因为它是在类的构造函数内以self.开头来定义的。可以由类的对象来调用,这里可以看出成员变量一定是以self.的形式给出的,因为self的含义就是代表实例对象;
localval3 不是成员变量,它只是成员函memfuntion()内部的局部变量;
nmval4和nmval5都不是成员变量,虽是以self.给出,但并没有在构造函数中进行初始化。