Python 学习要点分享

发布时间:2020-08-15编辑:脚本学堂
本文分享下,python编程中的一些学习要点,有兴趣研究python的朋友可以参考学习下,希望对你有所帮助。

本节内容:
python要点

import一个模块的开销是很大的, 但多次import一个模块只算一次, 要重载模块需要使用imp.reload方法.

一个以.py为后缀的python源码文件(包括.pyc和.pyo)都是一个python模块(module),module是python程序框架的核心基础概念.

module是变量名的封装, 也是一个独立的命名空间, 还是一个对象.

经常调用dir方法help方法等方法, 结合Pydoc, 这是学习python的好方法

from m import x 形式的导入尽量少用, 使用时需要多加小心, 它会带来诸多潜在bug. 如和本地变量名的相互覆盖,模块重载更新的不完全性等.

exec(open(script.py).read())这种用法存在两个显著的隐患, 一是变量覆盖的问题, 如同from import,另一个是可能存在安全漏洞, 如让用户执行任何危险代码. 尽量不用.

随机挑选一个元素:
 

复制代码 代码示例:
import random
random.choice([1,2,3,4])

python3.x后列表,集合,字典都可以用解析直接创建, 元组不能直接在括号中用解析创建, 需要加上tuple.

任何时候优先使用解析而非循环.虽然map等内置函数有时比解析还快,但是是不稳定的.

注意列表分片中负数的使用技巧,很多时候既高效又简短.

reload(A)仅仅重载A, 如在A中导入了B, 则B并不会随之重载.

目录环境变量在sys.path中,而这个变量是可以随意修改的,方便的同时可能也带来潜在的问题.

可以使用import __future__模块导入未来版本支持的特性.

python的逻辑操作更加抽象, 可以连续比较如 a < b < c; d == e > d等.

and和or等操作符也不会返回True或False,更不是1或0,而是为真或者为假的对象的变量.

afile = open(r'C:/new/t.txt')而不是open("c:newt.txt")

三引号字符串可以用做多行注释,也是注解的重要手段.

bytearray并不是真正的字符串, 而是一个整型序列, 以实现所谓"可修改的字符串".

编译字节码方法(具体参考help):
 

复制代码 代码示例:
import py_compile
py_compile.compile(filename, outputpath, cfilename, dfilename, doraise=True, optimize=2)

注意解释器和交互环境默认生成字节码的优化等级是2(最高).

尽量使用_pickle而不是pickle模块,更加不要使用eval方法.并非因为效率问题.

深层的,完备的全面拷贝,必须用copy模块的deepcopy方法而非copy方法或其他数据结构自己的copy方法.

用None而非数值0来初始化各种数据结构元素的初值.
None不是0,也不是C语言中的NULL, 更不是void*和void.

注意:
拷贝是深拷贝还是浅拷贝。
不要生成循环对象,虽然它很有趣。

文件名和变量名有一样的命名要求,因为他们可能作为模块名导入。
像and.py,123.py和my-code.py都是不可以的,因为他们都是非法变量名。

虽然print内部也是调用sys.stdout.write方法,但是在需要重定向时,不要使用sys.stdout=open(...
而是使用print(strinfo, file=filename)。

注意and和or的特殊用法以及相关陷阱。

多用解析,少用循环,循环多用for和迭代器,少用while。

map等方法调用自定义函数时,可能比循环还要慢,map等方法快或慢的决定因素是参数是否是内置方法。

注意下面的bug:
L = [1, 2, 3]
L = L.append(4)

def是"可执行的"。而非一个提示作用的关键字。它产生一个经过编译为字节码的函数对象。
方法(函数)在python中也是对象,而非单传的函数。

嵌套作用域之间的变量的相互关系和命名往往打来难缠的bug。很多时候需要一些check辅助工具。
下面的代码的bug:
 

复制代码 代码示例:
def fun():
    a = []
    for i in range(5):
        a.append(lambda x : x ** i)
    return a
 

a[0](2)到a[4](2)都返回16, 而并非期待的0,2,4,8,16需要改为:
a.append(lambda x, a=i : a ** x) 注意lambda表达式中是自己独立的作用域,上面a.append(lambda x : i ** x)中的i在循环结束时(i为4),才会真正把lambda对象返回,这导致五个对象都是返回定义为x ** 4的函数,所以都是16了.

L = [1, 2, 3] 注意 L * 4 , [L * 4], [L] * 4之间的区别。

format格式化方法和%格式化符未来谁会废弃现在未知,所以两种都需要掌握,但是尽量在代码中保持一样的风格,除非确定有必要两种混用。

生成器函数返回的不是一个函数对象,而是生成器对象, 该对象是支持迭代协议的迭代器对象.
next方法本质也是调用迭代器对象的__next__()方法。

a = yield x这种形式中,yield返回给a的是None,a等待接收的不是x,而是send方法的参数,x是用以返回给next方法的调用者的。

在生成器上多调用iter方法取得返回值本质都是一个值,他们并非"新"的迭代器。

对内置类型如列表调用iter方法,每次都返回"新"的迭代器。

注意打包和解包操作符(*和**)在方法调用和方法定义时的区别以及他们与Keyword-one参数的关系。
对于字典的打包和解包,**是对应键值对,而*是对应仅键。

元组解析必须在括号外带上tuple,如tuple(x  for x in range(11)),如果没有,返回的是生成器。

包名与模块名尽量与python内置的包,标准库等组件的名称不同,相同的话可能出现一些覆盖和冲突。
相对路径导入,并不能解决这类问题,尽量少用。

包与模块也是对象, 虽然包看起来像目录, 但它不是, __init__.py的存在提供了理由.

单下划线的(如_abc)所谓模块私有变量, 并非真正意义的"私有",它仅能阻止使用from import语法导入该变量. 而一般的import语句依然可以使用mod._abc访问这些变量.

python中封装的概念更像是把数据整合打包或者说给他一个命名空间, 而非其他语言那样产生严格的约束和私有.

千万不要递归import两个模块.

在.pth文件中添加额外的环境目录是个好的办法, 虽然是硬编码.

mod = "string"; import mod 无法执行,可是有时候需要动态导入模块,正确的方式并非exec("import " + mod),而是__import__(mod),不过__import__方法会隐式调用reload.

from import导入的变量名并非是"指针"或者某种"连接", 而仅仅是个变量名.
本地的修改对其影响视具体情况而定.
对于类而言在概念上self更像c++的this指针,但是实际上不全是.函数定义时,参数中可以写self,但是如果未来不作为类或对象的额外属性,那么它就仅仅是个参数名.
 

复制代码 代码示例:
class My: pass
def fun(self):
 return self.name.upper()
m = My()
My.method = fun
m.name = "what"
m.method() #"WHAT"
 

python中的很多OOP特性和语法可能和C++或java中的类似,但是不要认为是一样的语法概念,python中的定义更加灵活多变。