Python菜鸟之路:Python基础(二)

时间:2023-03-08 17:51:25
Python菜鸟之路:Python基础(二)

一、温故而知新

1. 变量命名方式

旧的方式:

 username = 'xxxx'
password = 'oooo'

新的方式:

 username, password = 'xxxx', 'oooo'

2. Python中如何定义常量

  常量:指一旦初始化之后就无法修改的固定值。

  Python中实际是没有这样的名称去定义一个常量的。但是通常变量名是全部大写的话,表示一个常量。比如:MYSQL_CONNECTION。

  同时,《Python Cookbook》一书中提供了定义常量模块const,此类是定义了一个方法__setattr__()和一个异常类型ConstError,主要是判断定义的常量是否在字典中,在则抛出异常,否则,给新创建的常量赋值。代码如下:

 class _const:
class ConstError(TypeError):pass
def __setattr__(self,name,value):
if self.__dict__.has_key(name):
raise self.ConstError,"Can't rebind const (%s)"% name
self.__dict__[name]=value import sys
sys.modules[__name__]=_const()

  经测试python2中可以运行,且报出异常const.ConstError: can't rebind const(magic)

3. pyc文件和__pycache__是怎么回事?And pyo ?

3.1 pyc 文件

  pyc 是由py文件经过编译后二进制文件(也叫字节码文件),py文件变成pyc文件后,加载的速度有所提高,而且pyc是一种跨平台的字节码,是由python 的虚拟机来执行的。pyc的内容,是跟python的版本相关的,不同版本编译后的pyc文件是不同的。

  官方还有这样一段解释如下:

  A program doesn't run any faster when it is read from a ‘.pyc’ or ‘.pyo’ file than when it is read from a ‘.py’ file; the only thing that's faster about ‘.pyc’ or ‘.pyo’files is the speed with which they are loaded.
  When a script is run by giving its name on the command line, the bytecode for the script is never written to a ‘.pyc’ or ‘.pyo’ file. Thus, the startup time of a script may be reduced by moving most of its code to a module and having a small bootstrap script that imports that module. It is also possible to name a ‘.pyc’ or ‘.pyo’file directly on the command line.

如何手动生成:

  python2.7版本中,通过如下方式可以生成:(Python3.5测试失败)

 Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:40:30) [MSC v.1500 64 bit (
AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
2 >>> import py_compile
3 >>> py_compile.compile("b.py")
4 >>> exit()

  另外一种方式则是在其他python文件中import 该文件,无论2.7还是3.5都是可以生成的。

3.2 __pycache__

  为了提高模块加载的速度,每个模块都会在__pycache__文件夹中放置该模块的预编译模块,命名为module.version.pyc,version是模块的预编译版本编码,一般都包含Python的版本号。例如在CPython 发行版3.5中,shopping.py文件的预编译文件就是:__pycache__/shopping.cpython-35.pyc。这种命名规则可以保证不同版本的模块和不同版本的python编译器的预编译模块可以共存。运行的当前脚本(__main__)不会生成pycache,被import的那些modules才会.

  脚本在运行之前会首先检查python文件的最后编辑日期和预编译模块的编译时间,从而决定是否需要重新编译。预编译模块也是跨平台的,所以不同的模块是可以在不同的系统和不同的架构之间共享的。Python在两种情况下不检查缓存。第一种,从命令行中直接加载的模块总是会重新编译并且结果不保存。第二种,如果没有源模块,则不会检查缓存。为了支持无源代码的部署方式,应该将预编译模块放在源代码文件夹中而不是__pycache__中,并且不要包含源代码模块

3.3 pyo ??? 

  pyo文件,是python编译优化后的字节码文件。pyo文件在大小上,一般小于等于pyc文件。如果想得到某个py文件的pyo文件,可以这样:
  python -O -m py_compile xxxx.py。

  参数说明:使用-O和-OO参数来降低预编译模块的大小。-O开关会去除assert语句,-OO开关会去除assert语句和__doc__字符串。因为有些模块要依赖这些语句,因此只有当你确认模块的内容时才去使用这些开关。优化模块的后缀名是.pyo。

  .pyo和.pyc文件的执行速度不会比.py文件快,快的地方在于模块加载的速度。

  compileall模块可以用来把某个文件夹的中的所有文件都编译成为.pyc或者.pyo文件。

官方的一段解释:

  When the Python interpreter is invoked with the -O flag, optimized code is generated and stored in .pyo files. The optimizer currently doesn’t help much; it only removes assert statements. When -O is used, all bytecode is optimized; .pyc files are ignored and .py files are compiled to optimized bytecode.
  A program doesn’t run any faster when it is read from a .pyc or .pyo file than when it is read from a .py file; the only thing that’s faster about .pyc or .pyo files is the speed with which they are loaded.

贴一个其他网站的对比图:

Python菜鸟之路:Python基础(二)  

4. Python3 与Python2的另外一点区别

  详情看下边的输出:

Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:54:25) [MSC v.1900 64 bit (AM
D64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a=12837912739817983719379179321
>>> type(a)
<class 'int'>
>>> exit() Python 2.7.11 (v2.7.11:6d1b6a68f775, Dec 5 2015, 20:40:30) [MSC v.1500 64 bit (
AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a=12837912739817983719379179321
>>> type(a)
<type 'long'>

  从上边可以看出,python3中,int和long统一整合为“int”型。

5. is和 == 的区别

  is检查两个对象是否是同一个对象(同一性),类似C语言中的指针。判断同一性,可以用id来查看下在内存的地址空间。。(obj1 is obj2) 等价于 (id(obj1) == id(obj2))

  ==检查他们是否相等(等值性)。

异常现象:

python2中如果比较float型数字, 比如a,b = 2.5,2.5 那么id(a) != id(b)

python3中如果比较float型数字, 比如a,b = 2.5,2.5 那么id(a) == id(b) 

  上述的变化,或许是python3的一些优化,具体原因我还不知道,后续如果有学习到,会进行更新。

6. 字符串拼接符 “+” 、join 和 "%s"占位符的区别#这里的说法不一定正确,等待以后能力达到了, 自己去研究底层实现的区别

  “+”是copy内存复制,所以每次“+”都需要进行内存拷贝,而join是一次性拷贝。

  “%s”也是在定义变量的时候,提前划分一块内存空间出来。

  当然了,不妨试试str.format()

二、新知识整理

1. 列表

  python3中,新增copy和clear方法,代码如下

     def clear(self): # real signature unknown; restored from __doc__
""" L.clear() -> None -- remove all items from L """
pass def copy(self): # real signature unknown; restored from __doc__
""" L.copy() -> list -- a shallow copy of L """
return []

2.7与3.5的另一个差异:
  2.7中,可以直接对列表进行排序,list.sort() ,列表中可以存在数字和字符串。
  3.0中,会提示错误: TypeError: unorderable types: str() < int()。详情看下面代码:

 >>> a=['b',]
>>> a.sort()
Traceback (most recent call last):
File "/work/shopping.py", line , in <module>
a.sort()
TypeError: unorderable types: int() < str()

2. 字典

python3 中去除了Python2 dict的has_key 、iteritems 、 itervalues 、 iterkeys、viewvalues 等方法。具体原因不知道...但是感觉少了迭代器,麻烦了很多。有迭代器,各种遍历不得不说会效率高很多……If you want to return an iterator in Python3.x, use iter(dictview) :

 >>> d = {'one':'', 'two':''}
>>> type(d.items())
<class 'dict_items'>
>>>
>>> type(d.keys())
<class 'dict_keys'>
>>>
>>>
>>> ii = iter(d.items())
>>> type(ii)
<class 'dict_itemiterator'>
>>>
>>> ik = iter(d.keys())
>>> type(ik)
<class 'dict_keyiterator'>

另外,随机的一些方法尽量少用:例如   dict.iterms() dict.values() dict.fromkeys() dict.popiterms()

3. 元组

  tuple在python2/3中,无明显差异,具体不再说明。

4. 字符串

  对于字符串,我一般是按照字符串=list的方式来记忆以及使用的。虽然不具备list的诸多方法,但是还是有很多共通处的。下面介绍string的几个非常好用的方法。

4.1 string.format(*args, **kwargs)

  .format方法用来格式化输出字符串。与%s占位符是一样的。

>>> name='My name is {name} ,age is {age}'
>>> name.format(name='Bob',age=33)

>>> name='My name is {0} ,age is {1}'
>>> name.format(name='Bob',age=33) 输出:
>>> My name is Bob ,age is 33

4.2 string.center(width, fillchar=None)

  .center方法返回指定长度的字符串,不足用fillchar来进行两侧填充。

 >>> name = 'Home Work Is Hard'
>>> print(name.center(40,'#'))
输出:
###########Home Work Is Hard############

5. 补充collections模块

  Python的collections模块在这些内置数据类型的基础上,提供了几个额外的数据类型:namedtuple, defaultdict, deque, Counter, OrderedDict等,其中namedtuple和OrderDic是两个很实用的扩展类型。(写博客我认为最忌讳的就是洋洋洒洒一大堆,自己记忆麻烦,别人看着累赘,没有突出点)

5.1 namedtuple命名元组

namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素。

eg : 如果要用坐标和半径表示一个圆,可以用namedtuple定义:

 from collections import *
Yuan = namedtuple('circle',['x','y','z'])
#或者Yuan = nametuple('circle','x y z')
yuan = Yuan(1,2,3)
print(yuan.x)
print(yuan.y)
print(yuan.z)
输出:
1
2
3

  再来一个更加贴近实际的例子

from collections import namedtuple

# 变量名和namedtuple中的第一个参数一般保持一致,但也可以不一样
Student = namedtuple('Student', 'id name score')
# 或者 Student = namedtuple('Student', ['id', 'name', 'score']) students = [(1, 'Wu', 90), (2, 'Xing', 89), (3, 'Yuan', 98), (4, 'Wang', 95)] for s in students:
stu = Student._make(s)
print stu #def _make(cls, iterable, new=tuple.__new__, len=len):
# 'Make a new named tuple object from a sequence or #iterable.'
# return new(cls, iterable) # Output:
# Student(id=1, name='Wu', score=90)
# Student(id=2, name='Xing', score=89)
# Student(id=3, name='Yuan', score=98)
# Student(id=4, name='Wang', score=95)

5.2 OrderDic有序字典

  使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序。如果要保持Key的顺序,可以用OrderedDict

 >>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是无序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])

注意,OrderedDict的Key会按照插入的顺序排列,不是Key本身排序:

 >>> od = OrderedDict()
>>> od['z'] = 1
>>> od['y'] = 2
>>> od['x'] = 3
>>> list(od.keys()) # 按照插入的Key的顺序返回
['z', 'y', 'x']

5.3 deque双向队列

  本质上就是一个列表……只是增加了一些双向操作的方法。这里不再多描述。

今天的整理总结就到这儿,希望看完之后大家能有不同的收获。