2020-02-02python学习记录(3)-函数式编程&模块

四、函数式编程:

函数式编程,有利于代码的管理,后期的代码的迭代和修改。函数的封装参数的传递,返回值的返回。

高阶函数:

变量可以指向函数、函数名也可能是变量(abs取绝对值)

def add(x, y, f):

    return f(x) + f(y)

把函数作为参数传入,这样的函数称为高阶函数,函数式编程就是指这种高度抽象的编程范式。

map/reduce:

Python内建了map()和reduce()函数。

map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

map()传入的第一个参数是mix,即函数对象本身。由于结果r是一个Iterator,Iterator是惰性序列,因此通过list()函数让它把整个序列都计算出来并返回一个list。

一个序列求和,就可以用reduce实现:

运算可以直接用Python内建函数sum(),没必要动用reduce。

filter:

Python内建的filter()函数用于过滤序列。

通过filter去除某些不需要的值

只保留偶数

filter()的作用是从一个序列中筛出符合条件的元素。由于filter()使用了惰性计算,所以只有在取filter()结果的时候,才会真正筛选并每次返回下一个筛出的元素。

sorted:

主要是排序:

sorted()也是一个高阶函数。用sorted()排序的关键在于实现一个映射函数。

要进行反向排序,不必改动key函数,可以传入第三个参数reverse=Trues

sorted传入key函数,即可实现忽略大小写的排序:

返回函数:

高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。

def lazy_sum(*args):    def sum():        ax = 0        for n in args:            ax = ax + n        return ax    return sum

匿名函数:

在传入函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便。

list(map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9]))

相当于下面的代码:

转换代码:

def is_odd(n):    return n % 2 == 1  L = list(filter(is_odd, range(1, 20)))  x = list(filter(lambda x: x % 2 == 1, range(1,20))) print(x)

装饰器:

由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-  import time, functools  def metric(fn):    print('%s executed in %s ms' % (fn.__name__, 10.24))    return fn  @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;  if __name__ == '__main__':  f = fast(11, 22)  s = slow(11, 22, 33)

偏函数:

Python的functools模块提供了很多有用的功能,其中一个就是偏函数(Partial function)。

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

五、模块:

注意:自己创建模块时要注意命名,不能和Python自带的模块名称冲突。例如,系统自带了sys模块,自己的模块就不可命名为sys.py,否则将无法导入系统自带的sys模块。

使用模块:

Python本身就内置了很多非常有用的模块,只要安装完毕,这些模块就可以立刻使用。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-  ' a test module '  __author__ = 'Michael Liao' __age__ = '23'  import sys  def test():    args = sys.argv    if len(args)==1:        print('Hello, %s!' % args[0])    elif len(args)==2:        print('Hello, %s!' % args[1])    else:        print('Too many arguments!')  if __name__=='__main__':    test()

作用域:

在一个模块中,我们可能会定义很多函数和变量,但有的函数和变量我们希望给别人使用,有的函数和变量我们希望仅仅在模块内部使用。在Python中,是通过_前缀来实现的。

正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,PI等;

类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,__abc等;

安装第三方模块:

在Python中,安装第三方模块,是通过包管理工具pip完成的。

六、面向对象编程

主要是抽象对象的一些特性,实例化具体的一个里面的一个处理。

在Python中,所有数据类型都可以视为对象,当然也可以自定义对象。自定义的对象数据类型就是面向对象中的类(Class)的概念。

可以类比java的编程

类和实例:

面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

class Student(object):    pass

class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,继承的概念后面再讲,通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。

数据封装:

面向对象编程的一个重要特点就是数据封装。在上面的Student类中,每个实例就拥有各自的name和score这些数据.

>>> class stu(object):

...    def __init__(self,name,age):

...            self.name = name

...            self.age = age

...

>>> lisa = stu('lisa',12)

>>> lisa.name

'lisa'

访问限制:

在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问,所以,我们把Student类改一改:

>>> class stu(object):

...    def __init__(self,name,age):

...            self.__name = name

...            self.__age = age

...

前面添加两个__这个就不能外部修改内容:

改完后,对于外部代码来说,没什么变动,但是已经无法从外部访问实例变量.__name和实例变量.__age了:

>>> bart = Student('Bart Simpson', 59)

>>> bart.__name

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

AttributeError: 'Student' object has no attribute '__name'

双下划线开头的实例变量是不是一定不能从外部访问呢?其实也不是。不能直接访问__name是因为Python解释器对外把__name变量改成了_Student__name,所以,仍然可以通过_Student__name来访问__name变量:

继承和多态:

在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-  class Animal(object):    def run(self):        print('Animal is running...')  class dog(Animal):  pass  if __name__=='__main__':    dog().run()

dog 继承Animal的属性,还有类是一个object,需要调run方法。

#!/usr/bin/env python3 # -*- coding: utf-8 -*-  class Animal(object):    def run(self):        print('Animal is running...')  class dog(Animal):  def dog1(self):  print('dog is ...')  if __name__=='__main__':    dog().dog1()

继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。比如如下的继承树:

静态语言 vs 动态语言:

对于静态语言(例如Java)来说,如果需要传入Animal类型,则传入的对象必须是Animal类型或者它的子类,否则,将无法调用run()方法。

对于Python这样的动态语言来说,则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了.

小结

继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。

动态语言的鸭子类型特点决定了继承不像静态语言那样是必须的。

获取对象信息:

使用type():

使用isinstance():

使用dir():

对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数。

如果要获得一个对象的所有属性和方法,可以使用dir()函数,它返回一个包含字符串的list,比如,获得一个str对象的所有属性和方法.

实例属性和类属性:

由于Python是动态语言,根据类创建的实例可以任意绑定属性。

给实例绑定属性的方法是通过实例变量,或者通过self变量:

#!/usr/bin/env python3 # -*- coding: utf-8 -*-  class Student(object):    def __init__(self, name):        self.name = name  s = Student('Bob') s.score = 90  if __name__=='__main__':  s = Student('Bob')  s.score = 90  print(s.score)

小结

实例属性属于各个实例所有,互不干扰;

类属性属于类所有,所有实例共享一个属性;

不要对实例属性和类属性使用相同的名字,否则将产生难以发现的错误。

七、面向对象高级编程

使用__slots__

正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。

正常的情况下可以随意的添加

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性:

class Student(object):    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

>>> class student(object): ...    __slots__ = ('name','age') ... >>> stu = student() >>> stu.name = 'bob' >>> stu.age = 12 >>> stu.score = 12 Traceback (most recent call last):  File "<stdin>", line 1, in <module> AttributeError: 'student' object has no attribute 'score' >>>

由于'score'没有被放到__slots__中,所以不能绑定score属性,试图绑定score将得到AttributeError的错误。

使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的:

class stu2(student): passs s2 = stu2() s2.score = 9999

除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__————

新的继承的不要添加__slots__属性

使用@property

可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩,这样,在set_score()方法里,就可以检查参数:

注意到这个神奇的@property,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。

@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 228,119评论 6 531
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,382评论 3 415
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 176,038评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,853评论 1 309
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,616评论 6 408
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,112评论 1 323
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,192评论 3 441
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,355评论 0 288
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,869评论 1 334
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,727评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,928评论 1 369
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,467评论 5 358
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,165评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,570评论 0 26
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,813评论 1 282
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,585评论 3 390
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,892评论 2 372

推荐阅读更多精彩内容

  • 要点: 函数式编程:注意不是“函数编程”,多了一个“式” 模块:如何使用模块 面向对象编程:面向对象的概念、属性、...
    victorsungo阅读 1,542评论 0 6
  • 写在前面的话 代码中的# > 表示的是输出结果 输入 使用input()函数 用法 注意input函数输出的均是字...
    FlyingLittlePG阅读 2,791评论 0 8
  • 基础1.r''表示''内部的字符串默认不转义2.'''...'''表示多行内容3. 布尔值:True、False(...
    neo已经被使用阅读 1,706评论 0 5
  • 高阶函数:将函数作为参数 sortted()它还可以接收一个key函数来实现自定义的排序,reversec参数可反...
    royal_47a2阅读 701评论 0 0
  • pyton review 学习指南 https://www.zhihu.com/question/29138020...
    孙小二wuk阅读 1,060评论 0 2