当前位置: 首页 > 编程日记 > 正文

深入探讨Python的import机制:实现远程导入模块 | CSDN博文精选

640?wx_fmt=png


来源 | Python编程时光(ID:Python-Time)

所谓的模块导入,是指在一个模块中使用另一个模块的代码的操作,它有利于代码的复用。
也许你看到这个标题,会说我怎么会发这么基础的文章?
与此相反。恰恰我觉得这篇文章的内容可以算是 Python 的进阶技能,会深入地探讨并以真实案例讲解 Python import Hook 的知识点。
当然为了使文章更系统、全面,前面会有小篇幅讲解基础知识点,但请你有耐心的往后读下去,因为后面才是本篇文章的精华所在,希望你不要错过。
640?wx_fmt=png
1. 导入系统的基础
1.1 导入单元构成
导入单元有多种,可以是模块、包及变量等。
对于这些基础的概念,对于新手还是有必要介绍一下它们的区别。
模块:类似 *.py,*.pyc, *.pyd ,*.so,*.dll 这样的文件,是 Python 代码载体的最小单元。
 还可以细分为两种:
  • Regular packages:是一个带有 __init__.py  文件的文件夹,此文件夹下可包含其他子包,或者模块
  • Namespace packages
关于 Namespace packages,有的人会比较陌生,我这里摘抄官方文档的一段说明来解释一下。
Namespace packages 是由多个 部分 构成的,每个部分为父包增加一个子包。各个部分可能处于文件系统的不同位置。部分也可能处于 zip 文件中、网络上,或者 Python 在导入期间可以搜索的其他地方。命名空间包并不一定会直接对应到文件系统中的对象;它们有可能是无实体表示的虚拟模块。
命名空间包的 __path__属性不使用普通的列表。而是使用定制的可迭代类型,如果其父包的路径 (或者最高层级包的 sys.path) 发生改变,这种对象会在该包内的下一次导入尝试时自动执行新的对包部分的搜索。
命名空间包没有 parent/__init__.py文件。实际上,在导入搜索期间可能找到多个 parent 目录,每个都由不同的部分所提供。因此 parent/one 的物理位置不一定与 parent/two 相邻。在这种情况下,Python 将为顶级的 parent 包创建一个命名空间包,无论是它本身还是它的某个子包被导入。

1.2 相对/绝对对导入

当我们 import 导入模块或包时,Python 提供两种导入方式:
  • 相对导入(relative import ):import foo.bar 或者 form foo import bar
  • 绝对导入(absolute import):from . import B 或 from ..A import B,其中.表示当前模块,..表示上层模块
你可以根据实际需要进行选择,但有必要说明的是,在早期的版本( Python2.6 之前),Python 默认使用的相对导入。而后来的版本中( Python2.6 之后),都以绝对导入为默认使用的导入方式。
使用绝对路径和相对路径各有利弊:
  • 当你在开发维护自己的项目时,应当使用相对路径导入,这样可以避免硬编码带来的麻烦。
  • 而使用绝对路径,会让你模块导入结构更加清晰,而且也避免了重名的包冲突而导入错误。

1.3 导入的标准写法

在 PEP8 中有一条,对模块的导入顺序提出了要求,不同来源模块导入,应该有清晰的界限,使用一空行来分开。
  • import 语句应当分行书写
# bad
import os,sys

# good
import os
import sys
  • import语句应当使用absolute import
# bad
from ..bar import  Bar

# good
from foo.bar import test
  • import语句应当放在文件头部,置于模块说明及docstring之后,全局变量之前
  • import语句应该按照顺序排列,每组之间用一个空格分隔,按照内置模块,第三方模块,自己所写的模块调用顺序,同时每组内部按照字母表顺序排列
# 内置模块
import os
import sys

# 第三方模块
import flask

# 本地模块
from foo import bar


2. __import__ 的妙用

在 Python 中使用 import 关键字来实现模块/包的导入,可以说是基础中的基础。
但这不是唯一的方法,还有 importlib.import_module()和 __import__()等。
对于 __import__,普通的开发者,可能就会比较陌生。
和 import 不同的是,__import__是一个函数,也正是因为这个原因,使得 __import__的使用会更加灵活,常常用于框架中,对于插件的动态加载。
实际上,当我们调用 import 导入模块时,其内部也是调用了 __import__,请看如下两种导入方法,他们是等价的。
# 使用 import
import os

# 使用 __import__
os = __import__('os')
通过举一反三,下面两种方法同样也是等价的。
# 使用 import .. as ..
import pandas as pd

# 使用 __import__
pd = __import__('pandas')
上面我说 __import__常常用于插件的动态,事实上也只有它能做到(相对于 import 来说)。
插件通常会位于某一特定的文件夹下,在使用过程中,可能你并不会用到全部的插件,也可能你会新增插件。
如果使用 import 关键字这种硬编码的方式,显然太不优雅了,当你要新增/修改插件的时候,都需要你修改代码。更合适的做法是,将这些插件以配置的方式,写在配置文件中,然后由代码去读取你的配置,动态导入你要使用的插件,即灵活又方便,也不容易出错。
假如我的一个项目中,有 plugin01plugin02plugin03plugin04四个插件,这些插件下都会实现一个核心方法 run()。但有时候我不想使用全部的插件,只想使用 plugin02plugin04,那我就在配置文件中写我要使用的两个插件。
# my.conf
custom_plugins=['plugin02', 'plugin04']
那我如何使用动态加载,并运行他们呢?
# main.py

for plugin in conf.custom_plugins:
    __import__(plugin)
    sys.modules[plugin].run()


3. 理解模块的缓存

在一个模块内部重复引用另一个相同模块,实际并不会导入两次,原因是在使用关键字 import导入模块时,它会先检索 sys.modules里是否已经载入这个模块了,如果已经载入,则不会再次导入,如果不存在,才会去检索导入这个模块。
来实验一下,在 my_mod02这个模块里,我 import 两次 my_mod01这个模块,按逻辑每一次 import 会一次 my_mod01里的代码(即打印 in mod01),但是验证结果是,只打印了一次。
$ cat my_mod01.py                 
print('in mod01')                    

$ cat my_mod02.py                 
import my_mod01                                        
import my_mod01     

$ python my_mod02.py              
in mod01                          
该现象的解释是:因为有 sys.modules的存在。
sys.modules是一个字典(key:模块名,value:模块对象),它存放着在当前 namespace 所有已经导入的模块对象。
# test_module.py

import sys
print(sys.modules.get('json', 'NotFound'))

import json
print(sys.modules.get('json', 'NotFound'))
运行结果如下,可见在 导入后 json 模块后,sys.modules才有了 json 模块的对象。
$ python test_module.py
NotFound
<module 'json' from 'C:\Python27\lib\json\__init__.pyc'>
由于有缓存的存在,使得我们无法重新载入一个模块。
但若你想反其道行之,可以借助 importlib 这个神奇的库来实现。事实也确实有此场景,比如在代码调试中,在发现代码有异常并修改后,我们通常要重启服务再次载入程序。这时候,若有了模块重载,就无比方便了,修改完代码后也无需服务的重启,就能继续调试。
还是以上面的例子来理解,my_mod02.py改写成如下
# my_mod02.py

import importlib
import my_mod01
importlib.reload(my_mod01)
使用 python3 来执行这个模块,与上面不同的是,这边执行了两次 my_mod01.py
$ python3 my_mod02.py
in mod01
in mod01

4. 查找器与加载器

如果指定名称的模块在 sys.modules找不到,则将发起调用 Python 的导入协议以查找和加载该模块。
此协议由两个概念性模块构成,即 查找器和 加载器
一个 Python 的模块的导入,其实可以再细分为两个过程:
  • 由查找器实现的模块查找
  • 由加载器实现的模块加载

4.1 查找器是什么?

查找器(finder),简单点说,查找器定义了一个模块查找机制,让程序知道该如何找到对应的模块。
其实 Python 内置了多个默认查找器,其存在于 sys.meta_path 中。
但这些查找器对应使用者来说,并不是那么重要,因此在 Python 3.3 之前, Python 解释将其隐藏了,我们称之为隐式查找器。
# Python 2.7
>>> import sys
>>> sys.meta_path
[]
>>> 
由于这点不利于开发者深入理解 import 机制,在 Python 3.3 后,所有的模块导入机制都会通过 sys.meta_path 暴露,不会在有任何隐式导入机制。
# Python 3.7
>>> import sys
>>> sys.meta_path
[<class '_frozen_importlib.BuiltinImporter'>, 
 <class '_frozen_importlib.FrozenImporter'>, 
 <class '_frozen_importlib_external.PathFinder'>, 
 <class '_frozen_importlib_external.PathFinder'>]
>>>
观察一下 Python 默认的这几种查找器 (finder),可以分为三种:
  • 一种知道如何导入内置模块
  • 一种知道如何导入冻结模块
  • 一种知道如何导入来自 import path 的模块 (即 path based finder)。
那我们能不能自已定义一个查找器呢?当然可以,你只要:
  1. 定义一个实现了 find_module 方法的类(py2和py3均可),或者实现 find_loader 类方法(仅 py3 有效),如果找到模块需要返回一个 loader 对象或者 ModuleSpec 对象(后面会讲),没找到需要返回 None
  2. 定义完后,要使用这个查找器,必须注册它,将其插入在 sys.meta_path 的首位,这样就能优先使用。
import sys

class MyFinder(object):
    @classmethod
    def find_module(cls, name, path, target=None):
        print("Importing", name, path, target)
        # 将在后面定义
        return MyLoader()

# 由于 finder 是按顺序读取的,所以必须插入在首位
sys.meta_path.insert(0, MyFinder)
查找器可以分为两种:
object
 +-- Finder (deprecated)
      +-- MetaPathFinder
      +-- PathEntryFinder
这里需要注意的是,在 3.4 版前,查找器会直接返回 加载器(Loader)对象,而在 3.4 版后,查找器则会返回模块规格说明(ModuleSpec),其中 包含加载器。
而关于什么是 加载器 和 模块规格说明, 请继续往后看。

4.2 加载器是什么?

查找器只负责查找定位找模,而真正负责加载模块的,是加载器(loader)。
一般的 loader 必须定义名为 load_module()的方法。
为什么这里说一般,因为 loader 还分多种:
object
 +-- Finder (deprecated)
 |    +-- MetaPathFinder
 |    +-- PathEntryFinder
 +-- Loader
      +-- ResourceLoader --------+
      +-- InspectLoader          |
           +-- ExecutionLoader --+
                                 +-- FileLoader
                                 +-- SourceLoader
通过查看源码可知,不同的加载器的抽象方法各有不同。
加载器通常由一个 查找器 返回。详情参见 PEP 302。
那如何自定义我们自己的加载器呢?
你只要:
  1. 定义一个实现了 load_module 方法的类
  2. 对与导入有关的属性(点击查看详情)进行校验
  3. 创建模块对象并绑定所有与导入相关的属性变量到该模块上
  4. 将此模块保存到 sys.modules 中(顺序很重要,避免递归导入)
  5. 然后加载模块(这是核心)
  6. 若加载出错,需要能够处理抛出异常( ImportError),若加载成功,则返回 module 对象
若你想看具体的例子,可以接着往后看。

4.3 模块的规格说明

导入机制在导入期间会使用有关每个模块的多种信息,特别是加载之前。大多数信息都是所有模块通用的。模块规格说明的目的是基于每个模块来封装这些导入相关信息。
模块的规格说明会作为模块对象的 __spec__属性对外公开。有关模块规格的详细内容请参阅 ModuleSpec
在 Python 3.4 后,查找器不再返回加载器,而是返回 ModuleSpec 对象,它储存着更多的信息
  • 模块名
  • 加载器
  • 模块绝对路径
那如何查看一个模块的 ModuleSpec ?
这边举个例子
$ cat my_mod02.py
import my_mod01
print(my_mod01.__spec__)

$ python3 my_mod02.py
in mod01
ModuleSpec(name='my_mod01', loader=<_frozen_importlib_external.SourceFileLoader object at 0x000000000392DBE0>, origin='/home/MING/my_mod01.py')
从 ModuleSpec 中可以看到,加载器是包含在内的,那我们如果要重新加载一个模块,是不是又有了另一种思路了?
来一起验证一下。
现在有两个文件:
一个是 my_info.py
# my_info.py
name='python'
另一个是:main.py
# main.py
import my_info

print(my_info.name)

# 加一个断点
import pdb;pdb.set_trace()

# 再加载一次
my_info.__spec__.loader.load_module()

print(my_info.name)
在 main.py处,我加了一个断点,目的是当运行到断点处时,我修改 my_info.py 里的 name 为 ming,以便验证重载是否有效?
$ python3 main.py
python
> /home/MING/main.py(9)<module>()
-> my_info.__spec__.loader.load_module()
(Pdb) c
ming
从结果来看,重载是有效的。

4.4 导入器是什么?

导入器(importer),也许你在其他文章里会见到它,但其实它并不是个新鲜的东西。
它只是同时实现了查找器和加载器两种接口的对象,所以你可以说导入器(importer)是查找器(finder),也可以说它是加载器(loader)。

5. 远程导入模块

由于 Python 默认的 查找器和加载器 仅支持本地的模块的导入,并不支持实现远程模块的导入。
为了让你更好的理解 Python Import Hook 机制,我下面会通过实例演示,如何自己实现远程导入模块的导入器。

5.1 动手实现导入器

当导入一个包的时候,Python 解释器首先会从 sys.meta_path 中拿到查找器列表。
默认顺序是:内建模块查找器 -> 冻结模块查找器 -> 第三方模块路径(本地的 sys.path)查找器
若经过这三个查找器,仍然无法查找到所需的模块,则会抛出ImportError异常。
因此要实现远程导入模块,有两种思路。
  • 一种是实现自己的元路径导入器;
  • 另一种是编写一个钩子,添加到sys.path_hooks里,识别特定的目录命名模式。
我这里选择第一种方法来做为示例。
实现导入器,我们需要分别查找器和加载器。
首先是查找器
由源码得知,路径查找器分为两种
  • MetaPathFinder
  • PathEntryFinder
这里使用 MetaPathFinder 来进行查找器的编写。
在 Python 3.4 版本之前,查找器必须实现 find_module()方法,而  Python 3.4+ 版,则推荐使用 find_spec()方法,但这并不意味着你不能使用 find_module(),但是在没有 find_spec()方法时,导入协议还是会尝试 find_module()方法。
我先举例下使用 find_module()该如何写。
from importlib import abc

class UrlMetaFinder(abc.MetaPathFinder):
    def __init__(self, baseurl):
        self._baseurl = baseurl

    def find_module(self, fullname, path=None):
        if path is None:
            baseurl = self._baseurl
        else:
            # 不是原定义的url就直接返回不存在
            if not path.startswith(self._baseurl):
                return None
            baseurl = path

        try:
            loader = UrlMetaLoader(baseurl)
            # loader.load_module(fullname)
        except Exception:
            return None
若使用 find_spec(),要注意此方法的调用需要带有两到三个参数。
第一个是被导入模块的完整限定名称,例如 foo.bar.baz。第二个参数是供模块搜索使用的路径条目。对于最高层级模块,第二个参数为 None,但对于子模块或子包,第二个参数为父包 __path__属性的值。如果相应的 __path__属性无法访问,将引发 ModuleNotFoundError。第三个参数是一个将被作为稍后加载目标的现有模块对象。导入系统仅会在重加载期间传入一个目标模块。
from importlib import abc
from importlib.machinery import ModuleSpec

class UrlMetaFinder(abc.MetaPathFinder):
    def __init__(self, baseurl):
        self._baseurl = baseurl
    def find_spec(self, fullname, path=None, target=None):
        if path is None:
            baseurl = self._baseurl
        else:
            # 不是原定义的url就直接返回不存在
            if not path.startswith(self._baseurl):
                return None
            baseurl = path

        try:
            loader = UrlMetaLoader(baseurl)
            return ModuleSpec(fullname, loader, is_package=loader.is_package(fullname))
        except Exception:
            return None
接下来是加载器
由源码得知,路径查找器分为两种
  • FileLoader
  • SourceLoader
按理说,两种加载器都可以实现我们想要的功能,我这里选用 SourceLoader 来示范。
在 SourceLoader 这个抽象类里,有几个很重要的方法,在你写实现加载器的时候需要注意
  • get_code:获取源代码,可以根据自己场景实现实现。
  • exec_module:执行源代码,并将变量赋值给 module.dict
  • get_data:抽象方法,必须实现,返回指定路径的字节码。
  • get_filename:抽象方法,必须实现,返回文件名
在一些老的博客文章中,你会经常看到 加载器 要实现 load_module(),而这个方法早已在 Python 3.4 的时候就被废弃了,当然为了兼容考虑,你若使用 load_module()也是可以的。
from importlib import abc

class UrlMetaLoader(abc.SourceLoader):
    def __init__(self, baseurl):
        self.baseurl = baseurl

    def get_code(self, fullname):
        f = urllib2.urlopen(self.get_filename(fullname))
        return f.read()

    def load_module(self, fullname):
        code = self.get_code(fullname)
        mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
        mod.__file__ = self.get_filename(fullname)
        mod.__loader__ = self
        mod.__package__ = fullname
        exec(code, mod.__dict__)
        return None

    def get_data(self):
        pass

    def execute_module(self, module):
        pass

    def get_filename(self, fullname):
        return self.baseurl + fullname + '.py'
当你使用这种旧模式实现自己的加载时,你需要注意两点,很重要:
  • execute_module 必须重载,而且不应该有任何逻辑,即使它并不是抽象方法。
  • load_module,需要你在查找器里手动执行,才能实现模块的加载。。
做为替换,你应该使用 execute_module()和 create_module()。由于基类里已经实现了 execute_module和 create_module(),并且满足我们的使用场景。我这边可以不用重复实现。和旧模式相比,这里也不需要在设查找器里手动执行 execute_module()
import urllib.request as urllib2

class UrlMetaLoader(importlib.abc.SourceLoader):
    def __init__(self, baseurl):
        self.baseurl = baseurl

    def get_code(self, fullname):
        f = urllib2.urlopen(self.get_filename(fullname))
        return f.read()

    def get_data(self):
        pass

    def get_filename(self, fullname):
        return self.baseurl + fullname + '.py'
查找器和加载器都有了,别忘了往sys.meta_path 注册我们自定义的查找器(UrlMetaFinder)。
def install_meta(address):
    finder = UrlMetaFinder(address)
    sys.meta_path.append(finder)
所有的代码都解析完毕后,我们将其整理在一个模块(my_importer.py)中
# my_importer.py
import sys
import importlib
import urllib.request as urllib2

class UrlMetaFinder(importlib.abc.MetaPathFinder):
    def __init__(self, baseurl):
        self._baseurl = baseurl


    def find_module(self, fullname, path=None):
        if path is None:
            baseurl = self._baseurl
        else:
            # 不是原定义的url就直接返回不存在
            if not path.startswith(self._baseurl):
                return None
            baseurl = path

        try:
            loader = UrlMetaLoader(baseurl)
        except Exception:
            return None

class UrlMetaLoader(importlib.abc.SourceLoader):
    def __init__(self, baseurl):
        self.baseurl = baseurl

    def get_code(self, fullname):
        f = urllib2.urlopen(self.get_filename(fullname))
        return f.read()

    def get_data(self):
        pass

    def get_filename(self, fullname):
        return self.baseurl + fullname + '.py'

def install_meta(address):
    finder = UrlMetaFinder(address)
    sys.meta_path.append(finder)


5.2 搭建远程服务端

最开始我说了,要实现一个远程导入模块的方法。
我还缺一个在远端的服务器,来存放我的模块,为了方便,我使用python自带的 http.server模块用一条命令即可实现。
$ mkdir httpserver && cd httpserver
$ cat>my_info.py<EOF
name='Python编程时光'
print('ok')
EOF

$ cat my_info.py
name='Python编程时光'
print('ok')

$ python3 -m http.server 12800
Serving HTTP on 0.0.0.0 port 12800 (http://0.0.0.0:12800/) ...
...
一切准备好,我们就可以验证了。
>>> from my_importer import install_meta
>>> install_meta('http://localhost:12800/') # 往 sys.meta_path 注册 finder 
>>> import my_info  # 打印ok,说明导入成功
ok
>>> my_info.name  # 验证可以取得到变量
'Python编程时光'
至此,我实现了一个简易的可以导入远程服务器上的模块的导入器。

6. 参考文档

1.https://docs.python.org/zh-cn/3/reference/import.html
2.https://docs.python.org/zh-cn/3/library/importlib.html#module-importlib.abc
3.https://python3-cookbook.readthedocs.io/zh_CN/latest/c10/p11_load_modules_from_remote_machine_by_hooks.html


扫码查看作者更多文章
▼▼▼
640?wx_fmt=jpeg

(*本文为 AI科技大本营投稿文章,转载联系作者


精彩推荐



2019 中国大数据技术大会(BDTC)再度来袭!豪华主席阵容及百位技术专家齐聚,15 场精选专题技术和行业论坛,超强干货+技术剖析+行业实践立体解读,深入解析热门技术在行业中的实践落地。5 折票倒计时 4 天!

640?wx_fmt=png

推荐阅读

相关文章:

吴恩达老师深度学习视频课笔记:人脸识别

什么是人脸识别&#xff1a;人脸验证和人脸识别的区别&#xff0c;如下图&#xff1a;One-shot learning&#xff1a;人脸识别所面临的挑战就是需要解决一次学习(one-shot learning)问题。这意味着在绝大多数人脸识别应用中你需要通过单单一张图像或者单单一个人脸图像就能去识…

用小白鼠喝毒药

题设&#xff1a;有N瓶水&#xff0c;其中有一瓶水有剧毒&#xff0c;如果小白鼠喝了会在24小时的时候死亡。 问&#xff1a;用多少只小白鼠能够检测出哪瓶水有剧毒&#xff1f; 要求&#xff1a;用的小白鼠数量少并且用时要短&#xff0c;并给出合理的过程与结论。 我的解题思…

怎样在swift中创建CocoaPods

本文由yake_099&#xff08;博客&#xff09;翻译自raywenderlich&#xff0c;作者&#xff1a;Joshua Greene 原文&#xff1a;How to Create CocoaPods with Swift 你可能对一些比较著名的开源的CocoaPods框架比较熟悉&#xff0c;比如Alamofire、MBProgressHUD。但是有时你…

吴恩达老师深度学习视频课笔记:神经风格迁移(neural style transfer)

什么是神经风格迁移(neural style transfer)&#xff1a;如下图&#xff0c;Content为原始拍摄的图像&#xff0c;Style为一种风格图像。如果用Style来重新创造Content照片&#xff0c;神经风格迁移可以帮你生成Generated图像。深度卷积网络在学什么&#xff1a;如下图&#xf…

“Jupyter的杀手”:Netflix发布新开发工具Polynote

作者 | Michael Li 译者 | Rosie 编辑 | Jane 出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;【导读】10 月 29 日&#xff0c;Netflix 公开了他们内部开发的 Polynote。现如今&#xff0c;大型高科技公司公开其内部的工具或服务&#xff0c;然后受到业界…

System Center 2012 r2优点

System Center 2012System Center2012 是一个全面的管理平台&#xff0c;可帮助你轻松、高效地管理数据中心、客户端设备和混合云 IT 环境。为您提供了针对私有云、托管云和公有云基础结构和应用程序服务的通用管理工具集。可按照您的需求&#xff0c;为生产基础架构、可预期应…

Swift 闭包表达式

闭包是功能性自包含模块,可以在代码中被传递和使用。 Swift 中的闭包与 C 和 Objective-C 中的 blocks 以及其他一些编程语言中的 lambdas 比较相似。 闭包的形式主要有三种&#xff1a; 1. 全局函数是一个有名字但不会捕获任何值的闭包 2. 嵌套函数是一个有名字并可以捕获其封…

GNU AWK中BEGIN/END使用举例

以下是使用gnu awk将test.cpp文件拆分成两个文件a.cpp和b.cpp&#xff0c;其中b.cpp仅存放test.cpp中的数据&#xff0c;其它内容存放在a.cpp文件中。test.cpp内容如下&#xff1a; #include <stdio.h> #include <iostream> #include <string>int main() {//…

目标检测的渐进域自适应,优于最新SOTA方法

作者 | Han-Kai Hsu、Chun-Han Yao、Yi-Hsuan Tsai、Wei-Chih Hung、Hung-Yu Tseng、Maneesh Singh、Ming-Hsuan Yang译者 | 刘畅编辑 | Jane出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;【导读】目标检测的最新深度学习方法依赖于大量的边界框标注信息…

讨论下IDS的绕过

自从知道dedecms自带了80sec的内置Mysqlids后&#xff0c;一直以来也没有想到绕过的办法。或者是自己mysql的根底太差了吧。于是分析dedecms源码时&#xff0c;只找模板执行&#xff0c;本地包含&#xff0c;上传等&#xff0c;完全没有想到注入存在的可能性了。 可以看看某牛的…

GCC编译选项参数介绍

gcc和g分别是gnu的c和c编译器&#xff0c;下面是整理的常用编译选项参数&#xff1a; #(1). -x: 设定文件所使用的语言&#xff0c;使文件后缀名无效&#xff0c;如下&#xff0c;执行完后生成test.o gcc -c -x c test.jpg #(2). -c: 只编译生成目标文件即*.o,只编译不链接生成…

程序员自学到底有没有用?网友们吵翻了...

最近就有个程序员吐槽说&#xff0c;自己大学没怎么听老师讲课&#xff0c;老师讲的知识要么太旧&#xff0c;要么老师不会讲&#xff0c;自己大部分时间是在网上看视频学的。引发了以下激烈的讨论。很多网友觉得&#xff0c;学校老师的代码能力不行&#xff0c;现在技术更新又…

更新 FrameWork

这里把想要改变的东西封装到FrameWork以便实现热更新&#xff0c;提一下关于BundiD 一定要一致&#xff0c;在打包的时候一定在Edit scheme —— >Run 选择Release如图&#xff1a; 因为你要跑在真机上&#xff0c;所以这个要选择Release 另外将包含你想要放出的方法类添加…

把Illustrator矢量图转化为代码:Drawscript

2019独角兽企业重金招聘Python工程师标准>>> DrawScript是一款Illustrator插件&#xff0c;可以将Illustrator的矢量图片转换成代码&#xff0c;目前免费&#xff0c;支持转换的语言有 OBJ-CCJAVASCRIPTCREATEJS/EASELJSPROCESSINGACTIONSCRIPT 3JSONRAW BEZIER PO…

必读:ICLR 2020 的50篇推荐阅读论文

来源 | 香侬科技本文整理了ICLR2020的相关论文&#xff0c;此次分享的是从Openreview中选取的部分论文&#xff0c;共50篇&#xff0c;其中大部分为NLP相关。文中涉及的相关论文推荐指数与推荐理由仅为个人观点&#xff0c;利益无关&#xff0c;亦不代表香侬科技立场。希望大家…

14个Xcode中常用的快捷键操作

在Xcode 6中有许多快捷键的设定可以使得你的编程工作更为高效&#xff0c;对于在代码文件中快速导航、定位Bug以及新增应用特性都是极有效的。 当然&#xff0c;你戳进这篇文章的目的也在于想要快速的对代码文件进行操作&#xff0c;或者是让Xcode的各面板更为适应你小本子的屏…

C++中标准模板库std::pair的实现

以下用C实现了标准模板库中的std::pair实现&#xff0c;参考了 cplusplus 和 vs2013中的utility文件。关于std::pair的介绍和用法可以参考&#xff1a; https://blog.csdn.net/fengbingchun/article/details/52205149 实现代码pair.hpp如下&#xff1a; #ifndef FBC_STL_PAIR_H…

【人在职场】能力与价值

原创作品&#xff0c;允许转载&#xff0c;转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://yunli.blog.51cto.com/831344/1547051 最近给团队&#xff08;指#UC浏览器电脑版#开发团队&#xff09;分享了我的《基层技术管理原则》。…

Windows与Linux之间互传文件的方法

以下方法均是以Windows为操作机&#xff1a;1. 通过WinSCP:WinSCP是一款开源的SFTP客户端&#xff0c;运行于Windows系统下&#xff0c;遵照GPL发布。WinSCP除了SFTP&#xff0c;还支持SSH、SCP(SecureCopy Protocol)。WinSCP的开发始于2000年4月&#xff0c;由布拉格经济大学所…

一文读懂简化的图卷积网络GCN(SGC)| ICML 2019

作者 | yyl424525来源 | CSDN博客文章目录1 相关介绍1.1 Simple Graph Convolution (SGC)提出的背景1.2 SGC效果2 Simple Graph Convolution 简化的图卷积2.1 符号定义2.2 图卷积网络GCNGCN vs MLPFeature propagation 特征传播Feature transformation and nonlinear transitio…

iOS UITableViewCell重用问题

TableView的重用机制&#xff0c;为了做到显示和数据分离&#xff0c;iOS tableView的实现并且不是为每个数据项创建一个tableCell。而是只创建屏幕可显示最大个数的cell&#xff0c;然后重复使用这些cell&#xff0c;对cell做单独的显示配置&#xff0c;来达到既不影响显示效果…

NLP常用工具

为什么80%的码农都做不了架构师&#xff1f;>>> NLP常用工具 各种工具包的有效利用可以使研究者事半功倍。 以下是NLP版版友们提供整理的NLP研究工具包。 同时欢迎大家提供更多更好用的工具包&#xff0c;造福国内的NLP研究。 *NLP Toolbox CLT http://compl…

Swift快速入门之getter 和 setter

属性可以用getter和setter方法的形式提供。 <code class"hljs lasso has-numbering" style"display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: Source Code Pro, monospace;font-size:u…

Linux下getopt函数的使用

getopt为解析命令行参数函数&#xff0c;它是Linux C库函数。使用此函数需要包含系统头文件unistd.h。 getopt函数声明如下&#xff1a; int getopt(int argc, char * const argv[], const char * optstring); 其中函数的argc和argv参数通常直接从main的参数直接传递而来。o…

20行Python代码说清“量子霸权”

作者 | 马超 来源 | 程序人生&#xff08;ID:coder_life&#xff09;近日谷歌的有关量子霸权&#xff08;Quantum Supremacy&#xff09;的论文登上了Nature杂志150年刊的封面位置&#xff0c;而再次罢占各大媒体的头条位置&#xff0c;其实这篇文章之前曾经短暂上过NASA的网站…

Android组件系列----BroadcastReceiver广播接收器

​【声明】 欢迎转载&#xff0c;但请保留文章原始出处→_→ 生命壹号&#xff1a;http://www.cnblogs.com/smyhvae/ 文章来源&#xff1a;http://www.cnblogs.com/smyhvae/p/3960623.html 【正文】 一、广播的功能和特征 广播的生命周期很短&#xff0c;经过调用对象-->…

Swift 代码调试-善用XCode工具(UI调试,五种断点,预览UIImage...)

原创Blog&#xff0c;转载请注明出处 http://blog.csdn.net/hello_hwc?viewmodelist 我的stackoverflow 工欲善其事&#xff0c;必先利其器&#xff0c;强烈建议新手同学好好研究下XCode这个工具。比如Build Settings&#xff0c;Build Info Rules&#xff0c;Build Parse…

Linux下getopt_long函数的使用

getopt_long为解析命令行参数函数&#xff0c;它是Linux C库函数。使用此函数需要包含系统头文件getopt.h。 getopt_long函数声明如下&#xff1a; int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);…

Expect自动化控制简单介绍

telnet&#xff0c;ftp&#xff0c;Passwd&#xff0c;fsck&#xff0c;rlogin&#xff0c;tip&#xff0c;ssh等等。该工具利用Unix伪终端包装其子进程&#xff0c;允许任意程序通过终端接入进行自动化控制&#xff1b;也可利用Tk工具&#xff0c;将交互程序包装在X11的图形用…

C++中标准模板库std::vector的实现

以下实现了C标准模板库std::vector的部分实现&#xff0c;参考了 cplusplus. 关于C中标准模板库std::vector的介绍和用法可以参考 https://blog.csdn.net/fengbingchun/article/details/51510916 实现代码vector.hpp内容如下&#xff1a; #ifndef FBC_STL_VECTOR_HPP_ #defi…