排序
>>> 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__name
,liupangzi.__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)函数。
静态语言(Java)必须严格按照继承体系。
动态语言:如果一个东西叫着像鸭子,走起路来像鸭子,我们就认为它是鸭子
也就是,Java的多态,watch_animal( )这个方法里边用到了Animal的run方法,那么传进来的必须是Animal或者其子类。
python的多态,如果有个对象,不是继承自Animal,但是也有run方法,那么传进来也可以执行。
也就是我用到了run方法,谁有谁都可以传进来。
判断对象类型
判断基本数据类型
判断变量是指向的函数或者类
返回对应的Class类型
判断某个东西的类型的时候,可以导入types模块,然后
types(abs) == types.BuiltinFunctionType
类似于Java的instanceOf()方法。
isinstance(对象, *类)
isinstance(h, Dog)
#判断h是否是Dog或其子类的对象。
也就是,如果为True,h是Dog或者Dog的子类。
h继承链往上的父类都可以返回True。
可以判断对象是否为一堆类里边的某一种(或其子类)
isinstance([1, 2], (list, tuple))
获得一个对象的属性和方法
dir(对象)
返回一个list,元素是属性名和方法名的字符串
可以操作对象的属性
也可以操作对象的方法