webbrowser – Convenient Web-browser controller

webbrowser 可以在命令行使用

python -m webbrowser -t/-n URL
  • -t: 在浏览器的新页面(tab)上打开 URL
  • -n: 在浏览器的新的窗口打开 URL(if possible)。

例子:在浏览器打开 http://alizs.cc,在命令行输入:

python -m webbrowser -t 'http://alizs.cc'
  • webbrowser.open(url, new=0, autoraise=True)
    用系统默认的浏览器打开 url

  • webbrowser.get(using=None)
    通过 using 的值,返回浏览器控制器对象。默认返回系统默认浏览器控制器对象。比如,系统默认的浏览器是 Chrome,现在想要用系统上安装的 FIrefox 浏览器打开 http://alizs.cc

    firefox = webbrowser.get('firefox')
    firefox.open('http://alizs.cc')
    

    已经预定义的浏览器类型,可以通过 get() 方法来获取。如果系统存在该类型浏览器,则会返回相应的浏览器控制器对象。

    Type Name Class Name
    ‘mozilla’ Mozilla(‘mozilla’)
    ‘firefox’ Mozilla(‘mozilla’)
    ‘netscape’ Mozilla(‘netscape’)
    ‘galeon’ galeon(‘galeon’)
    ‘epiphany’ Galeon(‘epiphany’)
    ‘skipstone’ BackgroundBrowser(‘skipstone’)
    ‘kfmclient’ Konqueror()
    ‘konqueror’ Konqueror()
    ‘kfm’ Konqueror()
    ‘mosaic’ BackgroundBrowser(‘mosaic’)
    ‘opera’ Opera()
    ‘grail’ Grail()
    ‘links’ GenericBrowser(‘links’)
    ‘elinks’ Elinks(‘elinks’)
    ‘lynx’ GenericBrowser(‘lynx’)
    ‘w3m’ GenericBrowser(‘w3m’)
    ‘windows-default’ WindowsDefault
    ‘macosx’ MacOSX(‘default’)
    ‘safari’ MacOSX(‘safari’)
    ‘google-chrome’ Chrome(‘google-chrome’)
    ‘chrome’ Chrome(‘chrome’)
    ‘chromium’ Chromium(‘chromium’)
    ‘chromium-browser’ Chromium(‘chromium-browser’)
  • webbrowser.register(name, constructor, instance=None)
    注册一个名为 name 的浏览器类型。注册成功之后,可以通过类型名 nameget() 该浏览器控制器对象。

    • name: 浏览器类型名称。
    • constructor: 可调用的对象名称,用来构建浏览器对象 instance。当 instance 不为 None 时,才有效。
    • instance: 浏览器对象。

    例一,用 constructor 来注册浏览器类型:

    def custom_browser():
        browser_path = '/usr/bin/firefox'
            return webbrowser.BackgroundBrowser(browser_path)
    
    webbrowser.register('custom_browser', custom_browser)
    controller = webbrowser.get('custom_browser')
    controller.open('http://alizs.cc')
    

    例二,用 instance 来注册浏览器类型:

    browser_path = '/usr/bin/firefox'
    custom_browser = webbrowser.BackgroundBrowser(browser_path)
    webbrowser.register('custom_browser', None, custom_browser)
    controller = webbrowser.get('custom_browser')
    controller.open('http://alizs.cc')
    

CentOS6.6 系统自带的 Python 版本是 Python2.6,但项目需要 Python2.7。

升级 Python2.6 到 Python2.7

  • 下载 Python源码包
    curl https://www.python.org/ftp/python/2.7.13/Python-2.7.13.tgz > Python-2.7.13.tgz
    tar -zxvf Python-2.7.13.tgz -C /opt/
    
  • 安装 Python
    cd /opt/Python-2.7.13
    ./configure
    make &&  make install
    

    默认安装在 /usr/loca/python2.7 目录下,也可以通过参数配置来指定安装路径 ./configure --prefix=/path/to/install/python
    安装完之后,系统默认的 Python 版本还是 Python2.6 的,需要修改:

    rm -f /usr/bin/python
    ln -s /usr/local/bin/python /usr/bin/python
    

    修改完之后,发现 yum 工具用不了了,因为 yum 工具是基于 Python2.6 的。将 /usr/bin/yum 的头部 #!/usr/bin/python 改为 #!/usr/bin/python2.6

安装 pip

cd /opt/
curl https://bootstrap.pypa.io/get-pip.py > get-pip.py
python get-pip.py
  • 如果出现错误:

    zipimport.ZipImportError: can’t decompress data; zlib not available

    是因为系统缺少了 zlibzlib-devel 库。

    yum install -y zlib zlib-devel
    

    安装成功之后,需要重新编译 Python:

    cd /opt/Python-2.7.13/
    make clean && make && make install
    # 重新编译完成之后再试一次安装 pip
    python get-pip.py
    
  • 如果接着出现错误:

    Could not fetch URL https://pypi.python.org/simple/pip/: There was a problem confirming the ssl certificate: Can’t connect to HTTPS URL because the SSL module is not available. – skipping

    是因为系统缺少 openssl-devel

    yum install -y openssl-devel
    

    安装成功之后,需要重新编译 Python:

    cd /opt/Python-2.7.13/
    make clean && make && make install
    # 重新编译完成之后再试一次安装 pip
    python get-pip.py
    

    到这里,我就成功安装了 pip。


总结 update.sh

#!/bin/sh

set -e
# 先安装需要的库:
yum install -y gcc zlib zlib-devel openssl-devel
# 下载 Python2.7 的源包
curl https://www.python.org/ftp/python/2.7.13/Python-2.7.13.tgz > Python-2.7.13.tgz
tar -zxvf Python-2.7.13.tgz -C /opt/
# 安装 Python
cd /opt/Python-2.7.13
./configure
make &&  make install
# 修改系统默认的 Python 版本
rm -f /usr/bin/python
ln -s /usr/local/bin/python /usr/bin/python
# 将 `/usr/bin/yum` 的头部 `#!/usr/bin/python` 改为 `#!/usr/bin/python2.6`
sed -i '1c #!/usr/bin/python2.6' /usr/bin/yum
# 接着安装 pip
cd /opt/
curl https://bootstrap.pypa.io/get-pip.py > get-pip.py
python get-pip.py

Reference: Virtualenv

安装

pip install virtualenv

创建虚拟环境

virtualenv ENV

ENV: 需要创建的虚拟环境的路径。ENV 可以是全局路径,也可以是相对路径。

以上命令创建的 Python 虚拟环境是没有从系统的 Python 中继承任何 Python 库的,是一个新的 Python 环境。其它选项:

  • -p PYTHON_EXE, --python=PYTHON_EXE
    默认创建的虚拟环境的 Python 版本是系统默认的 Python,但是可以通过添加该选项来指定虚拟环境的 Python 版本(前提是系统已有的 Python 版本)。

    virtualenv -p python3.5 ENV
    # or
    virtualenv --python=python3.5 ENV
    
  • --system-site-packages
    默认创建的虚拟环境是没有继承任何 Python 库的,如果需要继承系统默认 Python 的库,可以添加该选项:

    virtualenv --system-site-packages ENV
    
  • --always-copy
    默认情况下,创建虚拟环境需要的文件很多都是从系统软连接过来使用的。如果想要直接复制那些文件到虚拟环境而不是使用软连接,可以添加该选项:

    virutalenv --always-copy ENV
    

    更多参数选项可以参考 virtualenv,或 virtualenv --help

激活虚拟环境

激活虚拟环境,只需要 source 虚拟环境 ENV/bin/activate。如,虚拟环境目录为 /var/virtualenvs/scanner/,当前路径为 /home/lizs/

cd /var/virtualenvs/scanner/
source bin/activate

source /var/virtualenvs/scanner/bin/activate

成功激活之后,当前命令窗口的 python 就处于一个独立的虚拟环境的。pip freeze 可以看到当前的虚拟环境是没有安装任何 Python 的库的。

注意:在虚拟环境下,如果安装时候需要sudo权限 (如,sudo pip install Django),virtualenv 是获取不到sudo权限的。即,用sudo提权时,执行的命令不再在当前虚拟环境。那么,当在 virtualenv 虚拟环境下需要sudo权限安装的时候要怎么做呢?可以这样做:

sudo $(which pip) install Django

执行 which pip 的时候还是在当前虚拟环境下,sudo加命令的绝对路径安装就会自动安装到当前虚拟环境下了。

退出激活状态

如果想要退出激活状态的虚拟环境,可以执行:

deactivate

在非激活状态使用虚拟环境

  • 使用虚拟环境的 python 和相应的库
    如果,想要在非激活状态使用用虚拟环境的 Python 执行 Python 文件,可以指定 Python 解析器的路径为 /path/to/ENV/bin/python

  • 使用全局环境的 python,并且添加虚拟环境中的 python 库
    在 python 环境下,或执行文件中添加以下内容:

    activate_this = '/path/to/env/bin/activate_this.py'
    execfile(activate_this, dict(__file__=activate_this))
    

删除虚拟环境

删除虚拟环境,非激活状态下直接删除虚拟环境下的文件即可:

rm -r ENV

安装

前提,安装了 python 和 python-pip

  • windows

在 cmd 窗口中执行 pip install Sphinx

  • ubuntu

sudo pip install Sphinx

创建 Sphinx 项目

  • sphinx-quickstart

  • 设定文档的根目录:


Enter the root path for documentation. > Root path for the documentation [.]:

默认为 .,即当前目录,或者也可以新建目录 ./xxx

  • 是否分离 “_build” 文件夹

You have two options for placing the build directory for Sphinx output. Either, you use a directory "_build" within the root path, or you separate "source" and "build" directories within the root path. > Separate source and build directories (y/n) [n]: y
  • 设置 _templates_static 文件夹的前缀,默认为 _

Inside the root directory, two more directories will be created; "_templates" for custom HTML templates and "_static" for custom stylesheets and other static files. You can enter another prefix (such as ".") to replace the underscore. > Name prefix for templates and static dir [_]:
  • 设置项目的名称和作者

The project name will occur in several places in the built documentation. > Project name: wiki-zhongniu > Author name(s): lizs
  • 设置项目的版本号

Sphinx has the notion of a "version" and a "release" for the software. Each version can have multiple releases. For example, for Python the version is something like 2.5 or 3.0, while the release is something like 2.5.1 or 3.0a1. If you don't need this dual structure, just set both to the same value. > Project version: v1.0 > Project release [v1.0]: // 默认为上面输入的 veision
  • 设置项目的编写语言

If the documents are to be written in a language other than English, you can select a language here by its language code. Sphinx will then translate text that it generates into that language. For a list of supported codes, see http://sphinx-doc.org/config.html#confval-language. > Project language [en]: zh_CN
  • 设置源文件的后缀

The file name suffix for source files. Commonly, this is either ".txt" or ".rst". Only files with this suffix are considered documents. > Source file suffix [.rst]:
  • 设置文档首页的名称

One document is special in that it is considered the top node of the "contents tree", that is, it is the root of the hierarchical structure of the documents. Normally, this is "index", but if your "index" document is a custom template, you can also set this to another filename. > Name of your master document (without suffix) [index]:
  • 设置是否 epub 输出,默认即可

Sphinx can also add configuration for epub output: > Do you want to use the epub builder (y/n) [n]:
  • 设置是否使用 Sphinx 扩展功能:

Please indicate if you want to use one of the following Sphinx extensions: > autodoc: automatically insert docstrings from modules (y/n) [n]: y

然后,选择需要的 extension。

  • 创建 Makefile 和 Windows command file

A Makefile and a Windows command file can be generated for you so that you only have to run e.g. `make html' instead of invoking sphinx-build directly. > Create Makefile? (y/n) [y]: y > Create Windows command file? (y/n) [y]: y
  • 生成 HTML 文件

执行完以上步骤之后,就会在当前文件夹下生成一个目录为 xxx 的项目文件。进入文件夹里面,可以看到生成了 Makefile 文件。这时候,就可以用 make 命令来生成 html 文件了


make html

执行完 make html 会在 _build 文件夹里面的 html 文件夹里可以看到生成的 html 文件。如果分离了 _build,html 文件会在 buildhtml 文件夹里面。

List Slice: list[start:end:step]

  • start,切片的开始位置,包括 start,注意列表是从索引 0 开始的。

  • end,切片的结束位置,不包括 end

  • step,切片的步长。默认为 1。



>>> li = [0, 1, 2, 3, 4, 5]
  • start 为空,则默认为 0;end 为空,则默认切片到列表的最后,即 len(li) + 1

>>> li[:] [0, 1, 2, 3, 4, 5] >>> li[:3] [0, 1, 2] >>> li[3:] [3, 4, 5]
  • step 不能够为 0.

>>> li[::0] Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: slice step cannot be zero
  • step > 0 时,切片是从从左到右进行的。所以,在没有超出边界时,start 要在 end 的左边,否则返回值为空

>>> li[4:0] [] >>> li[0:-1] [0, 1, 2, 3, 4] >>> li[:-5] [0] >>> li[-6:1] [0] >>> li[-6:5:2] [0, 2, 4]
  • step < 0 时,切片是从右到左进行的。所以,在没有超出边界时,start 要在 end 的右边,否则返值为空。

>>> li[0:4:-1] [] >>> li[5:0:-1] # exclude end [5, 4, 3, 2, 1] >>> li[::-1] # 经典应用:反转字符串 [5, 4, 3, 2, 1, 0]

注意:无论 step > 0,还是 step < 0,切片都是包含 start,而不包含 end


边界问题:

  • start 超出左边界,则从索引 0 开始

>>> li[-7:] [0, 1, 2, 3, 4, 5]
  • end 超出右边界,则切片到最后结束,即len(li)

>>> li[:100] [0, 1, 2, 3, 4, 5]
  • startend,一个超出左边界一个超出右边界要看 step 的值正负来判断

>>> li[-10:10] [0, 1, 2, 3, 4, 5] >>> li[10:-10] [] >>> li[-10:10:-1] [] >>> li[10:-10:-1] [5, 4, 3, 2, 1, 0]
  • startend 都超出了左边界或者都超出了右边界,则为空

>>> li[-10:-20] [] >>> li[10:20] []

类定义

  • 类的定义就像函数的定义,要先执行才能生效。
  • 类定义之后,就会创建一个新的命名空间, 作为局部作用域。所有的赋值和函数名会成为命名空间的局部变量。
  • 类定义正常退出时,一个类对象就创建了。
  • Python 类中的方法的第一个参数通常是self,这是一个约定。如果不遵循这个约定,对其他 Python 程序员而言你的代码可读性就会变差,而且有些浏览器程序也可能遵循此约定编写的。
    self 是类方法的第一个参数,它就是类的实例对象自己,当调用方法时:
    A().func() 等同于 A().func(A)
    然后,类中的方法就可以通过 self 来调用该方法外面的方法或者变量了。这和 C++ 中隐式的 this 类似。

类对象

类对象支持两种操作: Attribute References and Instantiation (属性引用和实例化)
类的 Attribute References 使用 Python 中标准的属性引用语法:obj.name
类的 Instantiation 使用函数的符号。可以假设类对象是一个不带参数的函数,该函数返回这个类的一个新实例。x = A()

>>> class A :
        '''A simple example class'''
        a = 0
        def func(self) :
            b = self.a + 1
            print(b)

>>> A.a
0
>>> A().a
0
>>> A.func    # 直接引用类 A 中的函数 func,注意,如果类 A 不需要传参,这样就是实例化之后的引用了。
<function A.func at 0x000000D5EB96E8C8>
>>> A().func    # 实例化类 A 之后,引用函数 func
<bound method A.func of <__main__.A object at 0x000000D5EB9716D8>>
>>> A().func()    # 实例化类 A 之后,调用函数 func
1
>>> A.__doc__
'A simple example class'
>>> A().__doc__
'A simple example class'

实例化操作将创建一个空的对象。很多类希望创建的对象可以自定义一个初始状态,因此,可以在类中定义一个名为 __init__() 的特殊方法。类似其它语言的构造函数__construct()

>>> class B :
        a = 0
        def __init__(self, m) :
            self.a = m
        def func(self) :
            b = self.a
            print(b)

>>> B.a
0
>>> B().func()
TypeError: __init__() missing 1 required positional argument: 'm'
>>> B(1).func()
1


Class Variable and Instance Variable (类变量和实例变量)

Class Variable shared by all Instances, Instance Variable unique to each Instance.

>>> class A :
    a = [0]
    def __init__(self, m) :
        self.a.append(m)    # 'a' 为 Class Variable
    def func(self) :
        b = self.a    # 'a' 为 Class Variable
        print(b)

>>> B = A(1)
>>> B.func()
[0, 1]
>>> C = A(2)
>>> C.func()
[0, 1, 2]
>>> B.func()    
[0, 1, 2]

__init__()func() 里面的 a 都是引用了函数外面的 a,所以都是 Class Variable,对所有 Instance 都是共享的。


>>> class A :
        a = 0
        def __init__(self, m) :
            self.a = m    # 'a' 为 Instance Variable
        def func(self) :
            b = self.a
            print(b)

>>> B = A(1)
>>> B.func()
1
>>> C = A(2)
>>> C.func()
2
>>> B.func()
1
>>> A.a, B.a, C.a
(0, 1, 2)

__init__() 中对 a 进行赋值操作,就相当于创建了一个局部的 a (B.a、C.a)。所以,在__init__() 里面对 a 的操作是与外面 a 无关的。类中的 __init__() 函数用于创建实例化类的变量 a (B.a、C.a),因此,func() 函数中就会用实例化对象自己创建的 a。当实例化对象没有从新定义自己的 a 的时候,就会用继承的共享的 a
如果想要在初始化的时候改变 Class Variable a,可以这样:

>>> class A :
        a = 0
        def __init__(self, m) :
            A.a = m    # 直接指定 'a' 的类名
        def func(self) :
            b = self.a    # 因为实例化类中没有创建新的 'a',所以 'a' 是继承类 A 的 Class Variable
            print(b)

>>> B = A(1)
>>> B.func()
1
>>> A.a, B.a
(1, 1)

Namespace

A namespace ia a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries.
命名空间是从名称到对象的映射。当前,命名空间主要通过 Python 字典来实现。
Examples of namespaces are:
+ The set of built-in names (containing functions such as abs(), and built-in exception names)
内置名称集(包括内置函数,如 abs(),和内置异常的名称)
+ The global names in a module
模块中的全局名称
+ The local names in a function invocation
函数调用中的局部名称

and so on.

不同命名空间的名称没有任何关系。例如,两个不同模块都可以定义函数 func(),而不会产生混淆。只要在使用的时候加上模块名作为前缀引用它们就可以了。

module.funcmodule 是一个模块对象,func 是这个模块的一部分内容(function),我们称之为 属性。也就是说,funcmodule 的一个属性。

各个命名空间创建的时间是不一样的,而且有着不同的生命周期:
+ 内置名称的命名空间在 Python 解析器启动时创建,永远不会被删除
+ 模块的全局命名空间在读入模块定义时创建。通常情况下,模块命名空间也会一直保存到解析器退出。
+ 函数的局部命名空间在函数调用时创建,在函数返回或者引发了一个函数内部没有处理的异常时删除。


Scope

作用域 是 Python 程序中可以直接访问命名空间的代码区域。
直接访问,是指用没有前缀的引用在命名空间中找到相应的名称。如,abs(-1)abs属于直接访问。
属性访问,是指需要用点分.模式来指定属性的访问。如,module.func()

在 Python 程序运行中,至少有 4 个 scopes 是存在的。
+ Local(innermost),包含局部变量。如,function 内部的变量。
+ Enclosing,包含了非局部(non-local)也非全局(non-global)的变量。例如,两个嵌套函数,内层函数可能搜索外层函数的 namespace,但该 namespace 对内层函数而言既非局部也非全局。
+ Global(next-to-last),当前脚本的最外层。如,当前模块的全局变量。
+ Built-in(outtermost),Python builtin module。Containing bulit-in functions / built-in values / keywords and so on.

著名的 ‘LEGB-rule’,即 scope 的搜索顺序:
** Local -> Enclosing -> Global -> Built-in **

  • 首先,搜索最里面包含局部命名的作用域
  • 其次,从里向外搜索所有父函数的作用域,其中的命名既非局部也非全局。(该域不一定存在)
  • 接着,再往上搜索的作用域是当前模块全局命名的作用域,即函数定义所在的模块的命名空间
  • 最后,搜索的是包含内置命名的命名空间作用域

对于最终都没有搜索到的命名,Python 会抛出一个 NameError 异常。


Example1:

>>> def outer() :
        a = 0
        b = 1
        def inner() :
            print(a)
            print(b)
        inner()

>>> outer()
0
1

当执行 inner() 的时候,发现 Local 作用域里面没有 ab,就会往上层搜索


Example2:

>>> def outer() :
        a = 0
        b = 1
        def inner() :
                print(a)    # non-local namespace 'a'
                b = 2
                print(b)    # Locale namespace 'b'
        inner()

>>> outer()
0
2

Example3:

>>> def outer() :
        a = 0
        b = 1
        def inner() :
                print(a)    # Local namespace 'a'
                print(b)    # Local namespace 'b'
                b = 2
        inner()

>>> outer()
0
UnboundLocalError: local variable 'b' referenced before assignment

Python 局部变量不能够在定义之前引用


总结:
+ 局部赋值语句通常会隐式地创建一个局部变量,即便该变量名已存在于赋值语句发生的上一层作用域中。
+ 如果没有 global 关键字声明变量,对一个变量的赋值总是认为该变量存在于最内层(innermost)的作用域中


local non-local global

local:一般在没有说明的情况下赋值都默认为 local 的。
nonlocal:默认情况下变量的作用范围是local的,nonlocal 能够将变量绑定为localglobal(excluding)之间作用域。i.e.,如果你说明了一个 nonlocal 变量,这个命名的作用域就是从本地到整个模块之间(excluding global)。比如,函数外有一个变量 a,函数内说明一个 nonlocal a 变量,则函数里面的这个 a 其实就是函数外面的 a 的值。如果,对函数里面的 a 赋值,则调用这个函数之后,函数外面的 a 的值就已经改变了。
global:说明全局变量,这个变量的作用域是整个模块。

>>> def scope_test() :
        def do_local() :
            spam = 'local spam'
        def do_nonlocal() :
            nonlocal spam
            spam = 'nonlocal spam'
        def do_global() :
            global spam
            spam = 'global spam'
        spam = 'test spam'
        do_local()
        print('After local assignment: ', spam)    # print nonlocal 'spam'
        do_nonlocal()
        print('After nonlocal assignment: ', spam)    # print nonlocal 'spam', but it has been change
        do_global()
        print('After global assignment: ', spam)    # print nonlocal 'spam', the function just change the global 'spam'

>>> scope_test()
After local assignment:  test spam
After nonlocal assignment:  nonlocal spam
After global assignment:  nonlocal spam
>>> print('In global scope: ', spam)
In global scope:  global spam

The Scope and Namespace of Class

>>> class A :
        a = 0
        def func(self) :    
            b = a + 1
            print(b)

>>> A.func    # 查看类中 func 函数的属性
<function A.func at 0x00000038A3AF4488>
>>> A().func
<bound method A.func of <__main__.A object at 0x000000D5EB971400>>
>>> A.func()
TypeError: func() missing 1 required positional argument: 'self'
>>> A().func()    # 执行类中 func 函数
NameError: name 'a' is not defined
  • Python 类中的方法的第一个参数通常是self,这是一个约定。如果不遵循这个约定,对其他 Python 程序员而言你的代码可读性就会变差,而且有些浏览器程序也可能遵循此约定编写的。
    self 是类方法的第一个参数,它就是类的实例对象自己,当调用方法时:
    A().func() 等同于 A().func(A)
    然后,类中的方法就可以通过 self 来调用该方法外面的方法或者变量了。这和 C++ 中隐式的 this 类似。

  • 类的定义就像函数定义,要先执行才能生效。所以,定义了一个类无论有没有错误(不包括定义类时出现语法错误),都不会报错。因此,查看类的 attribute 时(如,A.func A().func),无论这个类有没有错误,都不会报错。但是当执行这个类的时候(如,A().func()),如果错误就会报错。
    同时,因为类中的方法有参数 self,所以,在实例化类的时候要加括号A()self 表示传进去的时类本身,所以可以不用填,但括号一定要。
    如果,定义的类中不用传参,实例化类的时候是可以不用括号的。

>>> class B :
        a = 0
        def func() :
            b = 'hello'
            print(b)

>>> B.a
0
>>> B.func()
hello
  • 类定义时,会创建一个新的命名空间,作为局部作用域。因此,在类中定义的变量(第一层)和函数名会成为这个新命名空间的局部变量。
    定义一个函数也会创建一个命名空间,因此,在类中定义一个函数时,这个函数里面的变量是属于这个函数命名空间的。类的命名空间的变量不能够直接调用函数内的变量,函数内也不能过直接调用类命名空间的变量。如果想要调用该方法外面的变量或者方法,可以通过 self 来实现
>>> class A :
        a = 0
        def func(self) :
            b = self.a + 1
            print(b)

>>> A().func()
1

List Comprehension (列表推导式/列表解析)
[expression for varible in iterable] or list(expression for varible in iterable)
Generator Expression (生成器表达式)
(expression for varible in iterable)
List Comprehension 和 Generator Expression 都会创建一个新的 namespace,里面的 varible 的作用域只是在这个命名空间。所以,当执行完一个 List Comprehension 或 Generator Expression 的时候,里面的 varible 都不会存留下来。

>>> [i for i in range(0, 10, 2)]
[0, 2, 4, 6, 8]
>>> print(i)
NameError: name 'i' is not defined
>>> list(i for i in range(0, 10, 2))
[0, 2, 4, 6, 8]
>>> print(i)
NameError: name 'i' is not defined
>>> (i for i in range(0, 10, 2))
<generator object <genexpr> at 0x000000734276DDB0>
>>> i
NameError: name 'i' is not defined

因此,在 List Comprehension 或者 Generator Expression 调用外部的变量也会出错。

>>> class A :
        a = 3
        b = list(a + i for i in range(10))    # 'i' 输入 range(10),'a' 没有定义

NameError: name 'a' is not defined

Import Module

  • 主程序和模块程序在同一目录下:
    — folder:
    —- test.py
    —- module.py

test.py

def func1() :
    print('Hello World!')

def func2() :
    print('Python3')

module.py

def func1() :
    print('Python3')

def func2() :
    print('Hello World!')

test.py import module.py
在 test.py 文件中或者运行 test.py 时加入 import module,则 test.py import 了整个 module.py。

============ RESTART: C:\Users\lizs\Desktop\Python3_test\test.py ============
>>> import module    # import 整个模块
>>> module.func2()    # 调用模块下的内容的时候要在前面加模块名和点分连接(module.func2())
Hello World!

也可以 import 模块中的个别内容,如:

>>> from module import func1    # import module 模块中的 func1
>>> func1()    # 调用的时候就不用加模块名称了(module.func1())
Python3

也可以 from module import *,但是这种方式不会导入下划线_开头的名称。一般情况下不赞成使用这种方法。
注意,出于性能考虑,每个模块在每个解析器会话中只导入一次。因此,如果你修改了已经导入的模块,你必须重启解析器。或者,如果你就是想交互式的测试一下更改的模块,可以使用 importlib.reload(module)module.reload() has been deprecated since version 3.4.

# module.py 添加了 func3()
>>> module.func3()    # 更新之后直接调用
AttributeError: module 'module' has no attribute 'func3'
>>> import module    # 再次 import,无效
>>> module.func3()
AttributeError: module 'module' has no attribute 'func3'
>>> from module import func3    # 无效
ImportError: cannot import name 'func3'
# 使用 importlib.reload(module) 重新导入
>>> improt importlib
>>> importlib.reload(module)
>>> module.func3()
module

  • 主程序在模块所在目录的父(或祖辈)目录。
    folder:
    — test.py
    — package:
    —- module.py

test.py

def func1() :
    print('Hello World!')

def func2() :
    print('Python3')

module.py

def func1() :
    print('Python3')

def func2() :
    print('Hello World!')

首先,要模块所在的目录(Package,包)创建一个 init.py 文件。然后再 import:

>>> import package.module    # Import 整个 module.py,要用点分连接 Package 和 Module
>>> package.module.func1()    # 调用是要完整的 package.module.func() 模式
Python3
>>> from package.module import func1()    # 这种方式 import 只需要 module.py 文件下的func
>>> func2()
Hello World!    # 调用也是只需要 func 名称

sys.path是python的搜索模块的路径集,是一个list。可以在python 环境下使用sys.path.append(path)添加相关的路径,但在退出python环境后自己添加的路径就会自动消失了!

使用下面方法将路径永久添加到sys.path:

方法一:使用pth文件,在 /Lib/site-packages文件中创建.pth文件,将模块的路径写进去,一行一个路径,

方法二:使用PYTHONPATH环境变量,在这个环境变量中输入相关的路径,不同的路径之间用逗号(英文的)分开,如果PYTHONPATH 变量还不存在,可以创建它!

远程目录通过分布式文件系统挂载后,找出路径用上述方法即可。

需要解决一个问题,避免由于之前存在一个同名模块导致加载失败

import sys; 
if not "/home/a/" in sys.path:
    sys.path.append("/home/a/") 
if not 'b' in sys.modules:
    b = __import__('b')
else:
    eval('import b')
    b = eval('reload(b)')

字典是映射类型(Mapping Type)。

  • 创建字典可以用 braces({}):{k: v, ...},也可以用 dict()。创建一个空字典用 {}dict()

  • 与序列(Sequence)不同,序列用数字作为索引,字典用 keys 作为索引,keys 可以是任何不可变类型。因此,字符串和数组永远可以用来做 keys。

  • 在同一字典内,keys 必须是唯一的。

  • 要检查某个 key 是否在 dictionary 中,可以使用 innot in

  • 也可以通过 del 语句来删除 key: valuedel dic[key],或者删除整个字典 del dic

  • 清空字典不能够用 del dic[ : ],因为,字典是不能够切片的TypeError: unhashable type: 'slice'

>>> dic = {}
>>> type(dic)
<class 'dict'>
>>> dic = {0: 'a', 'b': 1}
>>> dic
{0: 'a', 'b': 1}
>>> b['a']    # 字符串 keyword 不要忘了引号
0
>>> a[0]
'a'
>>> a['b']
1
>>> 0 in dic
True
>>> 'b' in dic
True
>>> 'a' in dic
False
>>> 0 not in a
False
>>> 'a' not in a
True
>>> del a[0]
>>> a
{'b': 1}

dict()

>>> a = {0: 'a', 'b': 1}
>>> b = dict(0 = 'a', 1 = 'b')
SyntaxError: keyword can't be an expression
>>> c= dict({0: 'a', 'b': 1})
>>> d= dict([(0, 'a'), ('b', 1)])
>>> e= dict(zip([0, 'b'], ['a', 1]))
>>> a == c == d == e
True

使用 dict(key = value, ..) 方法是 dict() 中创建字典最简单的方法。但是,用这种方法的 key 只能够是 Python 有效的标识符。i.e. 数字是无效的,而且 identifier 是没有引号的,生成字典会自动添加引号作为字符串 keywords。

>>> b = dict(a = 1, b = 2, abc = 3)    # keys 只能够是 identifiers,而且 identifiers 是没有引号的。
>>> b
{'abc': 3, 'b': 2, 'a': 1}   # 会自动生成字符串 keywords

In addition, dict comprehensions can be used to create dictionaries from arbitrary key and value expressions
此外,字典解析可以用于从任意键和值表达式创建字典。

>>> {x: y for x, y in zip((0, 1, 2), ('a', 'b', 'c'))}
{0: 'a', 1: 'b', 2: 'c'}
>>> {x: y for x, y in zip((0, 1, 2), ('a', 'b', 'c'))}
{'c': 2, 'b': 1, 'a': 0}


>>> dir({})
['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

dic.copy()
Return a shallow copy of the dictionary.

>>> dic = {0: 'a', 1: 'b', 2: 'c', 'a': 0, 'b': 1, 'c': 2}
>>> c = dic.copy()
>>> c
{0: 'a', 1: 'b', 2: 'c', 'a': 0, 'b': 1, 'c': 2}

dic.clear()
Remove all items from the dictionary.

>>> dic = {0: 'a', 'a': 0}
>>> dic.clear()
>>> dic
{}

dic.get(key[, default])
Return the value for key if the key is in the dictionary, else return default. If default is not given, it defaults to None. So that this method never raises a KeyError.

>>> b = dict(a = 0, b = 1, c = 2)
>>> b
{'c': 2, 'b': 1, 'a': 0}
>>> b.get('a')
0
>>> b.get('abc', 123)
123
>>> b.get('abc')
>>> 

dic.items()
Return a new view of the dictionary’s items ((key, value) pairs).

>>> b
{'c': 2, 'b': 1, 'a': 0}
>>> b.items()
dict_items([('c', 2), ('b', 1), ('a', 0)])
>>> for x in a.items() :    # 当将 dic.items() 的值赋给一个参数时,是 (key, value) pair
        print(x)

('a', 0)
('c', 2)
('b', 1)
>>> for x, y in b.items() :    # 当将 dic.items() 的值赋给两参数时,分别将 key 和 value 传给参数
            print(x, ':', y)

a : 0
c : 2
b : 1

for 语句调用 items() 的值:
for x in dic.items()(key, value) 对赋给变量 x
for x, y in dic.items() 会自动将 keyvalue 分别赋给 xy 变量。


dic.keys()
Return a new view of the dictionary’s keys.

>>> b
{'c': 2, 'b': 1, 'a': 0}
>>> b.keys()
dict_keys(['c', 'b', 'a'])
>>> for x in a.keys() :
        print(x)

a
c
b

dic.values()
Return a new view of the dictionary’s values.

>>> b
{'c': 2, 'b': 1, 'a': 0}
>>> b.values()
dict_values([2, 1, 0])
>>> for x in a.values() :
        print(x)

0
2
1

Dictionary view objects:
The objects returned by dic.items(), dic.keys(), dic.values() are view objects. They provide a dynamic view on the dictionary’s entries, which means that when the dictionary changes, the view reflects these changes.


dic.fromkeys(iterable[, value])
Create a new dictionary with keys from iterable and values set to value. value defaults to None.
fromkeys() is a class method that returns a new dictionary.

>>> dic = dict(a = 0, b = 1, c = 2, d = 3)
>>> dict.fromkeys('a', 0)
{'a': 0}
>>> dict.fromkeys(0)
TypeError: 'int' object is not iterable
>>> dict.fromkeys([0])
{0: None}
>>> dict.fromkeys('a')
{'a': None}
>>> dict.fromkeys(dic.keys(), 0)
{'c': 0, 'd': 0, 'a': 0, 'b': 0}
>>> dict.fromkeys(dic.keys(), 'abc')    # "value" is not iterable, all keys use the same 'value'
{'c': 'abc', 'd': 'abc', 'a': 'abc', 'b': 'abc'}
>>> dict.fromkeys(dic.keys(), [0, 1, 2, 3])
{'c': [0, 1, 2, 3], 'd': [0, 1, 2, 3], 'a': [0, 1, 2, 3], 'b': [0, 1, 2, 3]}
>>> dict.fromkeys([0, 1, 2, 3])
{0: None, 1: None, 2: None, 3: None}
>>> dict.fromkeys('abcd')
{'c': None, 'd': None, 'b': None, 'a': None}
>>> dict.fromkeys('abcd', dic.keys())
{'c': dict_keys(['c', 'd', 'b', 'a']), 'd': dict_keys(['c', 'd', 'b', 'a']), 'b': dict_keys(['c', 'd', 'b', 'a']), 'a': dict_keys(['c', 'd', 'b', 'a'])}

通过fromkeys(iterable[, value]) 创建的字典的 keys 由迭代器 iterable 产生,对应的值统一为 value。如果没有设置 value,则统一为 None


dic.pop(key[, default])
If key is in the dictionary, remove it and return its value, else return default. If default is not given and key is not in the dictionary, a KeyError is raised.

>>> b
{'c': 2, 'b': 1, 'a': 0}
>>> b.pop('a')
0
>>> b
{'c': 2, 'b': 1}
>>> b.pop('b', 'The dictionary don\'t have key "b"')
1
>>> b
{'c': 2}
>>> b.pop('abc', 'The dictionary don\'t have key "abc"')
'The dictionary don\'t have key "abc"'
>>> b.pop('abc')
KeyError: 'abc'

dic.popitem()
Remove and return an arbitray (key, value) pair from the dictionary.
popitem() is useful to destructively iterate over a dictionary, as often used in set algorithms. If the dictionary is empty, calling popitem() raises a KeyError.

>>> b = dict(a = 0, b = 1, c = 2)
>>> b
{'c': 2, 'b': 1, 'a': 0}
>>> b.popitem()
('c', 2)
>>> b
{'b': 1, 'a': 0}
>>> b.popitem()
('b', 1)
>>> b.popitem()
('a', 0)
>>> b
{}
>>> b.popitem()
KeyError: 'popitem(): dictionary is empty'

dic.setdefault(key[, default])
If key is in the dictionary, return its value. If not, insert key with a value of default and return default. default defaults to None.

>>> dic = dict(a = 0, b = 1, c = 2)
>>> dic
{'c': 2, 'b': 1, 'a': 0}
>>> dic.setdefault('a')
0
>>> dic.setdefault('abc', 123)
123
>>> dic
{'c': 2, 'b': 1, 'abc': 123, 'a': 0}
>>> dic.setdefault(0)    # insert key 0, and value default None
>>> dic
{0: None, 'c': 2, 'b': 1, 'abc': 123, 'a': 0}

dic.update([other])
Update the dictionary with the key/value pairs from other, overwriting existing keys. Return None.
update() accepts either another dictionary object or an iterable of key/value pairs (as tuples or iterables of length two). If keyword arguments are specified, the dictionary is then updated with those key/value pairs: dic.update(a = 0, b = 1).

>>> a = dict(a = 0, b = 1)
>>> a
{'b': 1, 'a': 0}
>>> a.update('c': 3)
SyntaxError: invalid syntax
>>> a.update('c'= 3)
SyntaxError: keyword can't be an expression
>>> a.update(c = 2)    # If keyword arguments are specified, 键名只能够是 identifier。
>>> a
{'c': 2, 'b': 1, 'a': 0}
>>> a.update(d = 3, e = 4)
>>> a
{'e': 4, 'c': 2, 'd': 3, 'b': 1, 'a': 0}
>>> a.update(a = -1)
>>> a
{'e': 4, 'c': 2, 'd': 3, 'b': 1, 'a': -1}
>>> a.update(0 = 'a')
SyntaxError: keyword can't be an expression
>>> b = {0: 'a', 1: 'b'}
>>> a.update(b)
>>> a
{'e': 4, 'c': 2, 'd': 3, 1: 'b', 0: 'a', 'b': 1, 'a': -1}
>>> a.update([('m', 0), (1, 'b')])
>>> a
{'e': 4, 'c': 2, 'd': 3, 1: 'b', 'm': 0, 0: 'a', 'b': 1, 'a': -1}

set 是一个无序不重复元素集。集合的基本用途有成员测试和消除重复的条目。集合对象还支持 union(并集)、intersection(交集)、different(差集)、sysmmetric difference(对称差集)。
集合可以用 {} 或者 set() 函数创建。注意:若要创建一个空集,必须使用 set(),而不能用 {}{} 用于创建一个空的字典。

>>> a = {0, 1, 2, 3}
>>> a
{0, 1, 2, 3}
>>> a = {0, 0, 1, 2, 3}    # set 消除重复
>>> a
{0, 1, 2, 3}
>>> a = set([0, 0, 1, 2, 3])
>>> a
{0, 1, 2, 3}
>>> a = set()    # 创建一个空集
>>> a
set()
>>> type(a)
<class 'set'>
>>> b = {}    # 创建一个空字典
>>> b
{}
>>> type(b)
<class 'dict'>

set([iterable])
Return a new set or frozenset object whose elements are taken from iterable. The elements of a set must be hashable . To represent sets of sets, the inner sets must be frozenset objects. if iterable is not specified, a new empty set is returned.

>>> a = set((0, 1, 2, 3))    # iterable is tuple
>>> a
{0, 1, 2, 3}
>>> set([0, 1, 2, 3])    # iterable is list
{0, 1, 2, 3}
>>> a = set([0, 1, 2, 3])
>>> a
{0, 1, 2, 3}
>>> b = set(['a', 'b', 'c', 'd'])
>>> b
{'b', 'c', 'a', 'd'}
>>> c = set('0123')    # iterable is string
>>> c
{'1', '2', '3', '0'}
>>> d = set('abcd')    # 创建一个唯一字符的集合
>>> d
{'b', 'c', 'a', 'd'}
>>> a & c
set()
>>> b & d
{'b', 'c', 'a', 'd'}

>>> dir(set())
['__and__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__iand__', '__init__', '__ior__', '__isub__', '__iter__', '__ixor__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__', 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard', 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset', 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update', 'union', 'update']

len(s)

>>> s = set([0, 1, 2, 3])
>>> len(s)
4

x in s x not in s

注意,x 是字符串时,要引号。否则,系统会认为 x 是其他已经定义的类型(如变量)


>>> s = {0, 1, 'a', 'b'} >>> 0 in s True >>> 0 not in s False >>> a in s NameError: name 'a' is not defined >>> 'a' in s True

s.issubset(t)
Test whether every element in set s is in set t. Return True when s <= t.

>>> s = set([0, 1, 2, 3])
>>> t = {0, 1, 2, 3, 4, 5}
>>> s.issubset(t)
True
>>> t = {0, 1, 2, 3}
>>> s.issubset(t)
True
>>> s <= t
True

s.issuperset(t)
Test whether every element in set t is in set s. Return True when s >= t.

>>> s = {0, 1, 2, 3, 4, 5}
>>> t = {0, 1, 2}
>>> s.issuperset(t)
True
>>> s >= t
True

s.isdisjoint(t)
Return True if the s has no elements in common with t.

>>> s = {0, 1, 2, 3}
>>> t = {4, 5, 6}
>>> t2 = {0, 'a', 'b'}
>>> s.isdisjoint(t)
True
>>> s.isdisjoint(t2)
False

s.union(t, ...)
Return a new set with elements from the s and all t. The same as s | t | ....
返回一个并集。

>>> s = {0, 1, 2}
>>> t = {0, 1, 2}
>>> t2 = {2, 3, 4}
>>> t3 = {5, 6, 7}
>>> a = s.union(t, t2, t3)
>>> a
{0, 1, 2, 3, 4, 5, 6, 7}
>>> b = s | t | t2 | t3
>>> b
{0, 1, 2, 3, 4, 5, 6, 7}

s.intersection(t, ...)
Return a new set with elements common to the sand all t. The same as s & t & ....
返回一个交集。

>>> s = {0, 1, 2, 3, 4}
>>> t = {0, 1}
>>> t2 = {1, 2, 3}
>>> a = s.intersection(t)
>>> a
{0, 1}
>>> b = s.intersection(t, t2)
>>> b
{1}

s.difference(t, ...)
Return a new set with elements in set s that are not in the t. The same as s - t - ....
返回一个差集,即返回s中有,t 中没有的集合。

>>> s = {0, 1, 2, 3, 4, 5, 'a', 'b', 'c'}
>>> t = {0, 1, 2}
>>> t = {'a', 'abc'}
>>> t = {0, 1, 2, 6, 7}
>>> t2 = {'a', 'abc'}
>>> s.difference(t)
{3, 4, 5, 'b', 'c', 'a'}
>>> s.difference(t, t2)
{3, 4, 5, 'b', 'c'}
>>> s - t
{3, 4, 5, 'b', 'c', 'a'}
>>> s - t - t2
{'b', 3, 4, 5, 'c'}

s.symmetric_difference(t)
Return a new set with elements in either s or t but not both.
返回一个对称差集,即包含集合 st 中不重复的元素。

>>> s = {0, 1, 2, 3, 4}
>>> t = {0, 1, 'a', 'b'}
>>> s.symmetric_difference(t)
{2, 3, 4, 'b', 'a'}
>>> s ^ t
{2, 3, 4, 'b', 'a'}

s.copy()
Return a new set with a shallow copy of s.
返回集合s的一个浅复制。

>>> s = {0, 1, 2, 3, 4}
>>> t = s.copy()
>>> t
{0, 1, 2, 3, 4}

s.update(t, ...)
Update the s, adding elements from all t. The same as s |= t | ....
更新集合 s,增加集合 t 中的元素。

>>> s = {0, 1, 2, 3}
>>> t = {0, 'a', 'b', 'c'}
>>> s.update(t)    # update 之后不产生新的集合,只是 update 了原来的集合
>>> s
{0, 1, 2, 3, 'b', 'c', 'a'}

s.intersection_update(t, ...)
Update the s, keeping only elements found in it and all t. The same as s &= t & ....
更新集合 s,更新后 s 中的元素只能是原 st 中共有的元素。

>>> s = {0, 1, 2, 3, 4}
>>> t = {0, 1, 2, 'a', 'b'}
>>> s.intersection_update(t)
>>> s
{0, 1, 2}

s.difference_update(t, ...)
Update the s, removing elements found in ‘t’. The same as s -= t.
更新集合s,删除在集合t中出现的元素。

>>> s = {0, 1, 2, 3, 4, 5}
>>> t = {0, 1, 2, 'a', 'b'}
>>> s.difference_update(t)
>>> s
{3, 4, 5}

s.add(t)
Add element t to the s.
**
add() takes exactly one argument, and only hashable type.
add() 只能够添加一个元素,而且是 hashable 类型的。
**

>>> s = {0, 1, 2}
>>> s.add(0)
>>> s
{0, 1, 2}
>>> s.add(3)
>>> s
{0, 1, 2, 3}
>>> s.add('a')
>>> s
{0, 1, 2, 3, 'a'}
>>> s.add(4, 5)
TypeError: add() takes exactly one argument (2 given)
>>> s.add([0])
TypeError: unhashable type: 'list'

s.remove(t)
Remove element t from the s. Raises KeyError if the set is empty.
remove() takes exactly one argument.

>>> s = {0, 1, 2, 3}
>>> s.remove(0)
>>> s
{1, 2, 3}
>>> s.remove('1')
KeyError: '1'
>>> s.remove({1, 2})
KeyError: {1, 2}

s.discard(t)
Remove element t from the s if it is present.
如果在集合s中存在t,则删除。

>>> s = {0, 1, 2, 3}
>>> s.discard(0)
>>> s
{1, 2, 3}
>>> s.discard(4)
>>> s
{1, 2, 3}
>>> s.discard({1, 2})
>>> s
{1, 2, 3}

s.pop()
Remove and return an arbitrary element from the s. Raises KeyError if the set is empty.
删除并返回集合s中一个任意的元素。如果集合为空则引发 KeyError。
注意,pop() 中不能够有参数。

>>> s = {0, 1, 2, 3, 4}
>>> s.pop(0)
Traceback (most recent call last):
  File "<pyshell#210>", line 1, in <module>
    s.pop(0)
TypeError: pop() takes no arguments (1 given)
>>> s.pop()
0
>>> s.pop()
1
>>> s.pop()
2
>>> s.pop()
3
>>> s.pop()
4
>>> s.pop()
KeyError: 'pop from an empty set'

s.clear()
Remove all elements from the s. The set s still exist, but it is a empty set.

>>> s = {0, 1, 2, 3}
>>> s.clear()
>>> s
set()

和列表解析类似,Python 也支持集合解析:

>>> s = {x for x in 'abcdefg' if x not in 'abcd'}
>>> s
{'g', 'e', 'f'}