你所需要的,不仅仅是一个好用的代理。
# 计算平均成绩绩点
>>> gpa = ((4*96+3*85+5*98+2*70)*4) / ((4+3+5+2)*100)
>>> gpa
3.625714285714286 # 终于知道自己的绩点是咋算的了
eval(expression[, globals[, locals]])将字符串 str 当成有效的表达式来求值并返回计算结果,globas为字典形式,locals为任何映射对象,它们分别表示全局和局部命名空间,两者都省略表达式将在调用的环境中执行,为什么需要警惕eval()呢:
# 合理正确地使用
>>> eval("1+1==2")
True
>>> eval('"a"+"b"')
'ab'
# 坏心眼的geek
>>> eval('__import__("os").system("dir")')
Desktop Documents Downloads examples.desktop Music Pictures Public __pycache__ Templates Videos
0
>>> eval('__import__("os").system("del * /Q")') # 嘿嘿嘿
如果确实需要使用eval,建议使用安全性更好的ast.literal_eval。
>>> li = ['a', 'b', 'c', 'd', 'e']
>>> for i, e in enumerate(li):
... print('index: ', i, 'element: ', e)
...
index: 0 element: a
index: 1 element: b
index: 2 element: c
index: 3 element: d
index: 4 element: e
# enumerate(squence, start=0) 内部实现
def enumerate(squence, start=0):
n = start
for elem in sequence:
yield n, elem # 666
n += 1
# 明白了原理我们自己也来实现一个反序的
def reversed_enumerate(squence):
n = -1
for elem in reversed(sequence):
yield len(sequence) + n, elem
n -= 1
操作符意义isobject identity==equal
is的作用是用来检查对象的标示符是否一致,也就是比较两个对象在内存中是否拥有同一块内存空间,相当于id(x) == id(y),它并不适用于判断两个字符串是否相等。==才是用来判断两个对象的值是否相等,实际是调用了内部的__eq__,所以a==b相当于a.__eq__(b),也就是说==是可以被重载的,而is不能被重载。
>>> s1 = 'hello world'
>>> s2 = 'hello world'
>>> s1 == s2
True
>>> s1 is s2
False
>>> s1.__eq__(s2)
True
>>> a = 'Hi'
>>> b = 'Hi'
>>> a == b
True
>>> a is b
True
咦~怎么上例中的a, b又是“同一对象”了?这跟 Python 的 string interning 机制有关,为了提高系统性能,对于 较小的字符串 会保留其值的一个副本,当创建新的字符串时直接指向该副本,所以a和b的 id 值是一样的,同样对于小整数[-5, 257)也是如此:
>>> id(a)
140709793837832
>>> id(b)
140709793837832
>>> x = -5
>>> y = -5
>>> x is y
True
>>> id(x) == id(y)
True
我之前也总结过编码的问题。由于最早的编码是 ASCII 码,只能表示 128 个字符,显然这对其它语言编码并不适用,Unicode就是为了不同的文字分配一套统一的编码。
本质上每一个 Python 文件都是一个模块,使用模块可以增强代码的可维护性和可重用性,在较大的项目中,我们需要合理地组织项目层次来管理模块,这就是包(Package)的作用。
一句话说包:一个包含__init__.py 文件的目录。包中的模块可以通过.进行访问,即包名.模块名。那么这个__init__.py文件有什么用呢?最明显的作用就是它区分了包和普通目录,在该文件中申明模块级别的 import 语句从而变成了包级别可见,另外在该文件中定义__all__变量,可以控制需要导入的子包或模块。
这里给出一个较为合理的包组织方式,是 FlaskWeb 开发:基于Python的Web应用开发实战一书中推荐而来的:
|-flasky
|-app/ # Flask 程序
|-templates/ # 存放模板
|-static/ # 静态文件资源
|-main/
|-__init__.py
|-errors.py # 蓝本中的错误处理程序
|-forms.py # 表单对象
|-views.py # 蓝本中定义的程序路由
|-__init__.py
|-email.py # 电子邮件支持
|-models.py # 数据库模型
|-migrations/ # 数据库迁移脚本
|-tests/ # 单元测试
|-__init__.py
|-test*.py
|-venv/ # 虚拟环境
|-requirements/
|-dev.txt # 开发过程中的依赖包
|-prod.txt # 生产过程中的依赖包
|-config.py # 储存程序配置
|-manage.py # 启动程序以及其他的程序任务
Python 提供三种方式来引入外部模块:import语句、from...import语句以及__import__函数,其中__import__函数显式地将模块的名称作为字符串传递并赋值给命名空间的变量。
使用import需要注意以下几点:
优先使用import a的形式
有节制地使用from a import A
尽量避免使用from a import *
为什么呢?我们来看看 Python 的 import 机制,Python 在初始化运行环境的时候会预先加载一批内建模块到内存中,同时将相关信息存放在sys.modules中,我们可以通过sys.modules.items()查看预加载的模块信息,当加载一个模块时,解释器实际上完成了如下动作:
在sys.modules中搜索该模块是否存在,如果存在就导入到当前局部命名空间,如果不存在就为其创建一个字典对象,插入到sys.modules中
加载前确认是否需要对模块对应的文件进行编译,如果需要则先进行编译
执行动态加载,在当前命名空间中执行编译后的字节码,并将其中所有的对象放入模块对应的字典中
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']
>>> import test
testing module import
>>> dir()
['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'test']
>>> import sys
>>> 'test' in sys.modules.keys()
True
>>> id(test)
140367239464744
>>> id(sys.modules['test'])
140367239464744
>>> dir(test)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'a', 'b']
>>> sys.modules['test'].__dict__.keys()
dict_keys(['__file__', '__builtins__', '__doc__', '__loader__', '__package__', '__spec__', '__name__', 'b', 'a', '__cached__'])
从上可以看出,对于用户自定义的模块,import 机制会创建一个新的 module 将其加入当前的局部命名空间中,同时在 sys.modules 也加入该模块的信息,但本质上是在引用同一个对象,通过test.py所在的目录会多一个字节码文件。
首先++i或--i在 Python 语法上是合法,但并不是我们通常理解的自增或自减操作:
>>> ++1 # +(+1)
1
>>> --1 # -(-1)
1
>>> +++2
2
>>> ---2
-2
原来+或-只表示正负数符号。
对于打开的资源我们记得关闭它,如文件、数据库连接等,Python 提供了一种简单优雅的解决方案:with。
先来看with实现的原理吧。
with的实现得益于一个称为上下文管理器(context manager)的东西,它定义程序运行时需要建立的上下文,处理程序的进入和退出,实现了上下文管理协议,即对象中定义了__enter__()和__exit__(),任何实现了上下文协议的对象都可以称为一个上下文管理器:
__enter__():返回运行时上下文相关的对象
__exit__(exception_type, exception_value, traceback):退出运行时的上下文,处理异常、清理现场等
包含with语句的代码块执行过程如下:
with 表达式 [as 目标]:
代码块
# 例
>>> with open('test.txt', 'w') as f:
... f.write('test')
...
4
>>> f.__enter__
<built-in method __enter__ of _io.TextIOWrapper object at 0x7f1b967aaa68>
>>> f.__exit__
<built-in method __exit__ of _io.TextIOWrapper object at 0x7f1b967aaa68>
计算表达式的值,返回一个上下文管理器对象
加载上下文管理器对象的__exit__()以备后用
调用上下文管理器对象的__enter__()
将__enter__()的返回值赋给目标对象
执行代码块,正常结束调用__exit__(),其返回值直接忽略,如果发生异常,会调用__exit__()并将异常类型、值及 traceback 作为参数传递给__exit__(),__exit__()返回值为 false 异常将会重新抛出,返回值为 true 异常将被挂起,程序继续执行
于此,我们可以自定义一个上下文管理器:
>>> class MyContextManager(object):
... def __enter__(self):
... print('entering...')
... def __exit__(self, exception_type, exception_value, traceback):
... print('leaving...')
... if exception_type is None:
... print('no exceptions!')
... return False
... elif exception_type is ValueError:
... print('value error!')
... return True
... else:
... print('other error')
... return True
...
>>> with MyContextManager():
... print('Testing...')
...
entering...
Testing...
leaving...
no exceptions!
>>> with MyContextManager():
... print('Testing...')
... raise(ValueError)
...
entering...
Testing...
leaving...
value error!
Python 还提供contextlib模块,通过 Generator 实现,其中的 contextmanager 作为装饰器来提供一种针对函数级别上的上下文管理器,可以直接作用于函数/对象而不必关心__enter__()和__exit__()的实现。
Python 的 else 子句提供了隐含的对循环是否由 break 语句引发循环结束的判断,有点绕哈,来看例子:
>>> def print_prime(n):
... for i in range(2, n):
... for j in range(2, i):
... if i % j == 0:
... break
... else:
... print('{} is a prime number'.format(i))
...
>>> print_prime(7)
2 is a prime number
3 is a prime number
5 is a prime number
可以看出,else 子句在循环正常结束和循环条件不成立时被执行,由 break 语句中断时不执行,同样,我们可以利用这颗语法糖作用在 while 和 try...except 中。