Python知识点

1.知识点总结

Python中的self和cls
Python类中的方法可以分为

  • 实例方法
  • 类方法
  • 静态方法

实例方法的第一个参数需要为self,指代实例本身,也可以是其他写法,但是默认通用的写法是self,在方法调用时不用传入,而定义时必须存在。
类方法的第一个参数需要为cls,指代类本身,也可以是其他写法,但是默认通用的写法是cls,在方法调用时不用传入,而定义时必须存在。

实例可以调用以上三中方法,而类只能调用除实例方法外的其他两种方法。

三种方法的区别Python 实例方法、类方法和静态方法
类变量和实例变量的区别类变量和实例变量
self和cls的区别self和cls的区别
__new__和__init__的区别区别
Python中type和object区别和联系

  • __bases__属性获取到的是对象的基类
  • __class__属性获取到的是对象的类型

在pycharm中看到的库中的“源码”,可能不是真的源码:说明
构造方法的继承关系Python子类继承父类构造函数详解

Python list嵌套的问题:

sub_list = [1, 2, 3]
list = []
list.append(sub_list)
print(list)
print(id(list[0]))
print(id(sub_list))
sub_list.clear()
print(list)

执行结果:

[[1, 2, 3]]
4356477408
4356477408
[[]]

Q1:在sub_list被清空后list也编程了空,4356477408是变量地址的十进制显示,可以发现list[0]sub_list的地址是相同的,所以这里的list中可能是用指针实现的,有时间需要研究一下。
A1:在python中有浅拷贝和深拷贝的问区别,在python中一切皆为对象,list的append操作实际上是在list中追加了可变对象sub_list的一个引用,所以list[0]sub_list指向的实际是同一个可变对象,所以导致了上述问题。要想避免上述问题可以使用深拷贝:list.append(copy.deepcopy(sub_list)),深拷贝后list[0]sub_list指向的是不同的两个可变对象。

python中的__name__python中__name__

2.廖雪峰教程学习记录

  1. 字符串编码
    在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
    在最新的Python 3版本中,字符串是以Unicode编码的。

  2. 使用list和tuple
    list里面的元素的数据类型可以不同

    >>> L = ['Apple', 123, True]
    

    tuple,不能修改的有序表:元组。
    不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。
    tuple的陷阱:当你定义一个tuple时,在定义的时候,tuple的元素就必须被确定下来。
    注意,定义只有1个元素的tuple定义时必须加一个逗号,

    >>> t = (1,)
    

    tuple所谓的“不变”是说,tuple的每个元素,指向永远不变

  3. 使用dict和set
    1.对于dict,要避免key不存在的错误,有两种办法:一是通过in判断key是否存在,二是通过dict提供的get方法,如果key不存在,可以返回None,或者自己指定的value。
    2.请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。
    3.要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。
    4.set和dict的唯一区别仅在于没有存储对应的value,但是,set的原理和dict一样,所以,同样不可以放入可变对象。

  4. 函数
    1.函数入参数据类型检查可以用内置函数isinstance()实现
    2.Python的函数返回多值其实就是返回一个tuple
    3.定义默认参数要牢记一点:默认参数必须指向不变对象! 如果定义默认参数使用一个可变对象,此对象在方法定义时就已经初始化了,多次调用此方法,默认参数的内容可能会互相影响。
    4.对于函数的可变参数,可以将其组成一个list后传入;对于函数的关键字参数,可以将多个kw组织成一个dict后传入。
    5.如果函数要限制关键字参数的名字,就可以用命名关键字参数
    6.在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数
    7.要注意定义可变参数和关键字参数的语法:*args是可变参数,args接收的是一个tuple;**kw是关键字参数,kw接收的是一个dict。
    8.使用递归函数时要注意避免栈溢出,如果某种语言对尾递归做了优化,可以避免出现栈溢出,但是很多语言并没有做优化,python也没有优化。

  5. 高级特性
    1.默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()
    2.列表生成式:[x * x for x in range(1, 11)],for循环后面还可以加上if判断做筛选。
    3.生成器:在Python中,这种一边循环一边计算的机制,称为生成器:generator,其对象不会一次全部生成,而是每次获取时才计算,可以极大节省内存空间。
    4.迭代器:
    可以直接作用于for循环的对象统称为可迭代对象:Iterable,判断是否是可迭代对象,可以使用isinstance()判断一个对象是否是Iterable对象:isinstance([], Iterable)
    可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator,可以使用isinstance()判断一个对象是否是Iterator对象,isinstance([], Iterator)
    生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。

    你可能会问,为什么list、dict、str等数据类型不是Iterator?
    这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。
    可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,
    所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
    Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
    
  6. 函数式编程
    1.高阶函数
    2.返回函数
    3.匿名函数
    4.装饰器
    5.偏函数

  7. 模块
    1.每一个包目录下面都会有一个__init__.py的文件,这个文件是必须存在的,否则,Python就把这个目录当成普通目录,而不是一个包。__init__.py可以是空文件,也可以有Python代码。
    2.类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,我们自己的变量一般不要用这种变量名。
    3.类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,但是请注意并不是不能直接引用。

  8. 面向对象编程
    1.访问限制:
    如果要让类的内部属性(变量或方法)不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private)。
    在Python中,变量名类似__xxx__的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量。
    一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
    2.实例属性和类属性
    同名的实例属性比类属性的优先级高,所以不要命名相同的实例属性和类属性

  9. 面向对象编程高级编程
    1.Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性。
    2.Python内置的@property装饰器可以负责把一个方法变成属性调用。
    3.通过多重继承,一个子类就可以同时获得多个父类的所有功能。
    4.定制类、枚举类、元类

  10. 错误、调试和测试
    1.try可以用来捕获错误,如果错误没有被捕获,它就会一直往上抛,最后被Python解释器捕获,打印一个错误信息,然后程序退出。
    2.因为错误是class,捕获一个错误就是捕获到该class的一个实例,所以我们可以自定义一个错误的class,选择好继承关系,然后raise抛出
    3.logging的使用
    4.单元测试
    Python自带的unittest模块可以用来做单元测试,编写单元测试时,我们需要编写一个测试类,从unittest.TestCase继承。
    以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。
    对每一类测试都需要编写一个test_xxx()方法。由于unittest.TestCase提供了很多内置的条件判断,我们只需要调用这些方法就可以断言输出是否是我们所期望的。最常用的断言就是assertEqual()
    self.assertEqual(abs(-1), 1) # 断言函数返回的结果与1相等
    运行单元测试
    最简单的运行方式是在测试代码中加上:

    if __name__ == '__main__':
        unittest.main()
    

    另一种方法是在命令行通过参数-m unittest直接运行单元测试。
    setUp与tearDown,可以在单元测试中编写两个特殊的setUp()和tearDown()方法。这两个方法会分别在每调用一个测试方法的前后分别被执行。
    5.文档测试
    Python内置的“文档测试”(doctest)模块可以直接提取注释中的代码并执行测试。

  11. IO编程
    1.open()打开一个文件对象,调用read()方法可以一次读取文件的全部内容,为了防止文件过大,要保险起见,可以反复调用read(size)方法,每次最多读取size个字节的内容。另外,调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list。因此,要根据需要决定怎么调用。
    如果文件很小,read()一次性读取最方便;如果不能确定文件大小,反复调用read(size)比较保险;如果是配置文件,调用readlines()最方便。
    文件对象使用完后都需要调用close方法关闭。
    Python引入了with语句来自动帮我们调用close()方法。
    2.StringIO和BytesIO是在内存中操作str和bytes的方法,使得和读写文件具有一致的接口。
    3.操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中。
    4.把两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()函数,这样可以正确处理不同操作系统的路径分隔符;同样的道理,要拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数。
    5.Python提供了pickle模块来实现序列化。

  12. 进程和线程
    1.多进程
    (1)通过OS 模块中的fork创建子进程,但是此中方法只能在类linux操作系统上使用,winodws中没有fork
    (2)multiprocessing模块是一个跨平台的多进程模块,其提供了一个Process类来代表一个进程对象,创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动,join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。
    (3)还可以使用multiprocessing中的Pool来实现进程池,可以指定进程池的大小,若不指定则Pool的默认大小是CPU的核数
    (4)subprocess模块可以让我们非常方便地启动一个子进程,然后控制其输入和输出。
    (5)Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。
    2.多线程
    (1)Python的标准库提供了两个模块:_thread(低级)和threading(高级,大多数用这个模块)
    (2)启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行,join等待所有线程执行完成。
    (3)threading.Lock(),线程锁的实现。
    (4)因为Python的线程虽然是真正的线程,但解释器执行代码时,有一个GIL锁:Global Interpreter Lock,任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。所以,在Python中,可以使用多线程,但不要指望能有效利用多核。如果一定要通过多线程利用多核,那只能通过C扩展来实现,不过这样就失去了Python简单易用的特点。
    (5)Python虽然不能利用多线程实现多核任务,但可以通过多进程实现多核任务。多个Python进程有各自独立的GIL锁,互不影响。
    3.ThreadLocal
    threading.local()
    一个ThreadLocal变量虽然是全局变量,但每个线程都只能读写自己线程的独立副本,互不干扰。ThreadLocal解决了参数在一个线程中各个函数之间互相传递的问题。
    4.进程 vs. 线程
    多进程模式最大的优点就是稳定性高
    多进程模式的缺点是创建进程的代价大
    5.分布式进程
    (1)对于分布式任务,在Thread和Process中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。
    (2)Python的multiprocessing模块不但支持多进程,其中managers子模块还支持把多进程分布到多台机器上。一个服务进程可以作为调度者,将任务分布到其他多个进程中,依靠网络通信。由于managers模块封装很好,不必了解网络通信的细节,就可以很容易地编写分布式多进程程序。

  13. 常用内建模块
    1.collections
    (1)namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。
    (2)deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈,deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。
    (3)使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict,除了在Key不存在时返回默认值,defaultdict的其他行为跟dict是完全一样的。
    (4)使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序,如果要保持Key的顺序,可以用OrderedDict。
    (5)Counter实际上是dict的一个子类,是一个简单的计数器。
    2.Base64是一种任意二进制到文本字符串的编码方法,常用于在URL、Cookie、网页中传输少量二进制数据。Base64是一种任意二进制到文本字符串的编码方法,常用于在URL、Cookie、网页中传输少量二进制数据。
    3.struct模块,Python提供了一个struct模块来解决bytes和其他二进制数据类型的转换。
    4.Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。
    5.itertools模块提供的全部是处理迭代功能的函数,它们的返回值不是list,而是Iterator,只有用for循环迭代的时候才真正计算。
    6.操作XML有两种方法:DOM和SAX。DOM会把整个XML读入内存,解析为树,因此占用内存大,解析慢,优点是可以任意遍历树的节点。SAX是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自己处理事件,正常情况下,优先考虑SAX,因为DOM实在太占内存。
    7.Python提供了HTMLParser来非常方便地解析HTML
    8.urllib提供了一系列用于操作URL的功能。

  14. 常用第三方模块
    1.PIL:Python Imaging Library,已经是Python平台事实上的图像处理标准库了,由于PIL仅支持到Python 2.7,加上年久失修,于是一群志愿者在PIL的基础上创建了兼容的版本,名字叫Pillow,支持最新Python 3.x,又加入了许多新特性,因此,我们可以直接安装使用Pillow。

  15. virtualenv
    virtualenv可以用来为一个应用创建一套“隔离”的Python运行环境。

  16. 图形界面
    Python自带的库是支持Tk的Tkinter,使用Tkinter,无需安装任何包,就可以直接进行GUI编程。

  17. 网络编程

  18. 电子邮件
    1.一封电子邮件的旅程就是:
    发件人 -> MUA -> MTA -> MTA -> 若干个MTA -> MDA <- MUA <- 收件人
    2.发邮件时,MUA和MTA使用的协议就是SMTP:Simple Mail Transfer Protocol,后面的MTA到另一个MTA也是用SMTP协议
    3.收邮件时,MUA和MDA使用的协议有两种:POP:Post Office Protocol,目前版本是3,俗称POP3;IMAP:Internet Message Access Protocol,目前版本是4,优点是不但能取邮件,还可以直接操作MDA上存储的邮件,比如从收件箱移到垃圾箱,等等。

  19. Web开发
    1.WSGI(Web Server Gateway Interface)接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求。
    2.WSGI提供的接口虽然比HTTP接口高级了不少,但和Web App的处理逻辑比,还是比较低级,我们需要在WSGI接口之上能进一步抽象,让我们专注于用一个函数处理一个URL,至于URL到函数的映射,就交给Web框架来做。
    3.使用web框架—Flask
    Flask通过Python的装饰器在内部自动地把URL和函数给关联起来。
    4.使用模版
    (1)使用模板,我们需要预先准备一个HTML文档,这个HTML文档不是普通的HTML,而是嵌入了一些变量和指令,然后,根据我们传入的数据,替换后,得到最终的HTML,发送给用户,这就是传说中的MVC:Model-View-Controller,中文名“模型-视图-控制器”。
    (2)Python处理URL的函数就是C:Controller,Controller负责业务逻辑,比如检查用户名是否存在,取出用户信息等等;包含变量{{ name }}的模板就是V:View,View负责显示逻辑,通过简单地替换一些变量,View最终输出的就是用户看到的HTML。Model是用来传给View的,这样View在替换变量的时候,就可以从Model中取出相应的数据。
    (3)Flask默认支持的模板是jinja2

  20. 异步IO
    如读写文件、发送网络数据时,就需要等待IO操作完成,才能继续进行下一步操作。这种情况称为同步IO。
    在IO操作的过程中,当前线程被挂起,而其他需要CPU执行的代码就无法被当前线程执行了。
    因为一个IO操作就阻塞了当前线程,导致其他代码无法执行,所以我们必须使用多线程或者多进程来并发执行代码,为多个用户服务。每个用户都会分配一个线程,如果遇到IO导致线程被挂起,其他用户的线程不受影响。
    多线程和多进程的模型虽然解决了并发问题,但是系统不能无上限地增加线程。由于系统切换线程的开销也很大,所以,一旦线程数量过多,CPU的时间就花在线程切换上了,真正运行代码的时间就少了,结果导致性能严重下降。
    同步IO模型下,主线程只能挂起,但异步IO模型下,主线程并没有休息,而是在消息循环中继续处理其他消息。这样,在异步IO模型下,一个线程就可以同时处理多个IO请求,并且没有切换线程的操作。对于大多数IO密集型的应用程序,使用异步IO将大大提升系统的多任务处理能力。
    1.协程,又称微线程,纤程。英文名Coroutine。
    2.asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。

3.参考

1.廖雪峰的Python3.X教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值