python编译参数
1. python “编译的” Python 文件的理解是什么
为了加快加载模块的速度,Python 会在 __pycache__ 目录下以 mole.version.pyc 名字缓存每个模块编译后的版本,这里的版本编制了编译后文件的格式。它通常会包含 Python 的版本号。例如,在 CPython 3.3 版中,spam.py 编译后的版本将缓存为 __pycache__/spam.cpython-33.pyc。这种命名约定允许有不同发布和不同版本的 Python 编译的模块同时存在。
Python 会检查源文件与编译版的修改日期以确定它是否过期并需要重新编译。这是完全自动化的过程。同时,编译后的模块是跨平台的,所以同一个库可以在不同架构的系统之间共享。
Python 不检查在两个不同环境中的缓存。首先,它会永远重新编译而且不会存储直接从命令行加载的模块。其次,如果没有源模块它不会检查缓存。若要支持没有源文件(只有编译版)的发布,编译后的模块必须在源目录下,并且必须没有源文件的模块。
部分高级技巧:
为了减少一个编译模块的大小,你可以在 Python 命令行中使用 -O 或者 -OO。-O 参数删除了断言语句,-OO 参数删除了断言语句和 __doc__ 字符串。
因为某些程序依赖于这些变量的可用性,你应该只在确定无误的场合使用这一选项。“优化的” 模块有一个 .pyo 后缀而不是 .pyc 后缀。未来的版本可能会改变优化的效果。
来自 .pyc 文件或 .pyo 文件中的程序不会比来自 .py 文件的运行更快;.pyc 或 .pyo 文件只是在它们加载的时候更快一些。
compileall 模块可以为指定目录中的所有模块创建 .pyc 文件(或者使用 -O 参数创建 .pyo 文件)。
在 PEP 3147 中有很多关这一部分内容的细节,并且包含了一个决策流程。
2. python 中os.system()的用法
os模块中的system()函数可以方便地运行其他程序或者脚本。
语法如下:os.system(command)
其参数含义如下所示:
command 要执行的命令,相当于在Windows的cmd窗口中输入的命令。如果要向程序或者脚本传递参数,可以使用空格分隔程序及多个参数。
(2)python编译参数扩展阅读
Python在执行时,首先会将.py文件中的源代码编译成Python的byte code(字节码),然后再由Python Virtual Machine(Python虚拟机)来执行这些编译好的byte code。这种机制的基本思想跟Java,.NET是一致的。然而,Python Virtual Machine与Java或.NET的Virtual Machine不同的是,Python的Virtual Machine是一种更高级的Virtual Machine。
这里的高级并不是通常意义上的高级,不是说Python的Virtual Machine比Java或.NET的功能更强大,而是说和Java 或.NET相比,Python的Virtual Machine距离真实机器的距离更远。或者可以这么说,Python的Virtual Machine是一种抽象层次更高的Virtual Machine。
基于C的Python编译出的字节码文件,通常是.pyc格式。
除此之外,Python还可以以交互模式运行,比如主流操作系统Unix/Linux、Mac、Windows都可以直接在命令模式下直接运行Python交互环境。直接下达操作指令即可实现交互操作。
3. LINUX下要在C中嵌入Python,编译的时候怎样解决库的连接问题
gcc编译时,当使用动态库编译可以按照几种写法1.gcctest.c./libSDL2-2.so2.gcctest.c-lSDL2-23.gcctest.c-L/home/test-lSDL2-2一般的编译参数都是按照2或3去写2写法的含义是从/lib或者/usr/lib目录下寻找名称为SDL2-2的库,即寻找/lib/libSDL2-2.so或者/usr/lib/libSDL2-2.so文件进行链接,当然如果没有动态库就会去找静态库,再没有应该就会在编译时报错3写法的含义是从-L参数首先从指定的目录中寻找需要链接的库文件,随后再去寻找系统文件夹中是否存在需要的库1写法的含义是将当前目录下的./libSDL2-2.so.0文件链接进最终文件,因此执行readelf-aa.out后在动态库部分所看到的路径就是./libSDL2-2.so.0,进而在执行文件时仅会从当前目录下寻找libSDL2-2.so.0文件,当执行文件时所在的目录下没有该文件时就会出现找不到库文件的操作你第二次操作时,因为function.so库文件与a.out文件在同一个目录,同时也是在该目录下执行的ldd操作及运行a.out,a.out在加载动态库时从当前目录下找到了所需要的库文件,此时能够执行成功(ldd命令实质是一个脚本,通过设置环境变量运行动态库链接器来输出所有待链接的动态库)。你可以试试将a.out拷贝至其他目录再次运行,将出现和第一次操作时一样的现象,找不到function.so文件。具体的解决方法就是修改编译参数,将./libSDL2-2.so.0修改为-lSDL2-2并将libSDL2-2.so.0文件拷贝至/usr/lib目录下,并且可能因为没有修改链接器的缓存文件(将可能找不到带版本号后缀的动态库),需要在/usr/lib目录下建立一个文件连接(ln-slibSDL2-2.so.0libSDL2-2.so)或者直接修改名称为libSDL2-2.so
4. Python中定义函数默认参数值的使用注意事项
4.7.1. 默认参数值
最常用的一种形式是为一个或多个参数指定默认值。这会创建一个可以使用比定义是允许的参数更少的参数调用的函数,例如:
def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
while True:
ok = input(prompt)
if ok in ('y', 'ye', 'yes'):
return True
if ok in ('n', 'no', 'nop', 'nope'):
return False
retries = retries - 1
if retries < 0:
raise OSError('uncooperative user')
print(complaint)
这个函数可以通过几种不同的方式调用:
只给出必要的参数:
ask_ok('Do you really want to quit?')
给出一个可选的参数:
ask_ok('OK to overwrite the file?', 2)
或者给出所有的参数:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
这个例子还介绍了 in 关键字。它测定序列中是否包含某个确定的值。
默认值在函数 定义 作用域被解析,如下所示:
i = 5
def f(arg=i):
print(arg)
i = 6
f()
将会输出 5。
重要警告: 默认值只被赋值一次。这使得当默认值是可变对象时会有所不同,比如列表、字典或者大多数类的实例。例如,下面的函数在后续调用过程中会累积(前面)传给它的参数:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
这将输出:
[1]
[1, 2]
[1, 2, 3]
如果你不想让默认值在后续调用中累积,你可以像下面一样定义函数:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
5. Python程序如何使用参数
用sys模块,使用sys.argv接收参数,sys.argv是一个列表,第2个元素开始是传递进来的值,传递的时候用空格割开就好
import sys
for x in sys.argv:
....print(x)
6. 请教Scons python 编译问题
一、概述
scons是一个Python写的自动化构建工具,和GNU make相比优点明显:
1、移植性:python能运行的地方,就能运行scons
2、扩展性:理论上scons只是提供了python的类,scons使用者可以在这个类的基础上做所有python能做的事情。比如想把一个已经使用了Makefile大型工程切换到scons,就可以保留原来的Makefile,并用python解析Makefile中的编译选项、源/目标文件等,作为参数传递给scons,完成编译。
3、智能:Scons继承了autoconf/automake的功能,自动解析系统的include路径、typedef等;“以全局的观点来看所有的依赖关系”
二、scons文件
scons中可能出现的文件:
SConstruct,Sconstruct,sconstruct,SConscript
scons将在当前目录以下次序 SConstruct,Sconstruct,sconstruct 来搜索配置文件,从读取的第一个文件中读取相关配置。
在配置文件SConstruct中可以使用函数SConscript()函数来定附属的配置文件。按惯例,这些附属配置文件被命名为”SConscript”,当然也可以使用任意其它名字。
三、scons的命令行参数
scons: 执行SConstruct中脚本
scons -c clean
scons -Q 只显示编译信息,去除多余的打印信息
scons -Q --implicit-cache hello 保存依赖关系
--implicit-deps-changed 强制更新依赖关系
--implicit-deps-unchanged 强制使用原先的依赖关系,即使已经改变
四、SConstruct提供的方法
1、Program:生成可执行文件
Program('hello.c') 编译hello.c可执行文件,根据系统自动生成(hello.exe on Windows; hello on POSIX)
Program('hello','hello.c') 指定Output文件名(hello.exe on Windows; hello on POSIX)
Program(['hello.c', 'file1.c', 'file2.c']) 编译多个文件,Output文件名以第一个文件命名
Program(source = "hello.c",target = "hello")
Program(target = "hello" , source = "hello.c")
Program('hello', Split('hello.c file1.c file2.c')) 编译多个文件
Program(Glob("*.c"))
src = ["hello.c","foo.c"];Program(src)
2、Object:生成目标文件
Object('hello.c') 编译hello.c目标文件,根据系统自动生成(hello.obj on Windows; hello.o on POSIX)
3、Library:生成静态/动态库文件
Library('foo', ['f1.c', 'f2.c', 'f3.c']) 编译library
SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c']) 编译 shared library
StaticLibrary('bar', ['f4.c', 'f5.c', 'f6.c']) 编译 static library
库的使用:
Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.') 连接库,不需加后缀或是前缀
4、SourceSignatures:判断源文件是否修改
SourceSignatures('MD5') 根据内容是否改变,默认方式
SourceSignatures('timestamp') 根据修改时间
5、TargetSignatures:判断目标文件是否改变
TargetSignatures('build') 根据编译结果
TargetSignatures('content') 根据文件内容,如果只是加了句注释,将不会被重新编译
6、Ignore:忽略依赖关系
Ignore(hello, 'hello.h') 忽略某个依赖关系
7、Depends:明确依赖关系
Depends(hello, 'other_file') 明确依赖关系
8、SConscript:scons的配置文件。
源文件的目录结构如下:
src:
| SConstruct
|test.cpp
| mA(目录):
| SConscript
| func.cpp
其中test.cpp为主文件,中调用func.cpp中定义的函数
SConstruct内容如下:
[cpp]view plain
subobj=SConscript(['mA/SConscript'])
obj=subobj+Object(Glob("*.cpp"))
Program("test",list(obj))
- SConscript内容 :
obj=Object(Glob("*.cpp"))
Return("obj")
- 上例中,在主目录中执行 scons就可以编译整个"工程"。SConstruct编译主目录中的test.cpp,并通过SConscript编译mA目录下的源文件,并最终生成可执行文件;SConscript用于编译mA中的func.cpp并把生成的func.o传递给主目录的SConstruct。
env=Environment()
dict=env.Dictionary()
keys=dict.keys()
keys.sort()
forkeyinkeys:
print"constructionvariable='%s',value='%s'"%(key,dict[key])
- 环境变量的使用:
- env = Environment() #创建默认的环境变量,默认scons会按编译器的默认选项来进行编译
- import os
- env = Environment(CC = 'gcc',CCFLAGS = '-O2') #创建并设置环境 变量
- env.Program('foo.c')
env=Environment()
flags=env.ParseFlags(['-pthread-I/usr/include/stlport','-L.'])
env.MergeFlags(class_flags)
subobj=SConscript(['mA/SConscript'])
obj=subobj+env.Object(Glob("*.cpp"))
env.Program("test",list(obj),LIBS=['libstlport.a'])
obj=Object(Glob("*.cpp"))
Return("obj")
env=Environment()
flags=env.ParseFlags(['-pthread-I/usr/include/stlport','-L.'])
env.MergeFlags(class_flags)
Export('env')
subobj=SConscript(['mA/SConscript'],exports='env')
obj=subobj+env.Object(Glob("*.cpp"))
env.Program("test",list(obj),LIBS=['libstlport.a'])
- mA/SConscript:
[cpp]view plain
10.env:环境变量
环境变量用于设置在编译过程中的各种参数,可以用下面的SConstruct打印环境变量的所有信息(实际上env就是一个python字典)
可以使用如下的SConstruct查看环境变量的内容:
[cpp]view plain
环境变量的复制:
env = Environment(CC = 'gcc')
opt = env.Clone(CCFLAGS = '-O2')
dbg = env.Clone(CCFLAGS = '-g')
环境变量的替换:
env = Environment(CCFLAGS = '-DDEFINE1')
env.Replace(CCFLAGS = '-DDEFINE2')
env.Program('foo.c')
环境变量的输入输出:用于统一多目录源文件的编译选项,如:
src:
| SConstruct
| libstlport.a
| test.cpp
| include(目录):
| foo.h
| mA(目录):
| SConscript
|func.cpp
test.cpp和mA/func.cpp都引用了include/foo.h,test.cpp调用了mA/func.cpp的功能函数,其中include/foo.h中定义了一个包含string类型的类。
SConstruct如下:
[cpp]view plain
mA/SConscrip如下:
[cpp]view plain
不出意外的话上边的工程编译可以通过,但是运行的时候会Aborted。因为test.cpp,mA/func.cpp都使用了包含string类型的那个类,但是由于编译环境的不同,test.cpp认为string变量的大小是24字节, mA/func.cpp认为string变量的大小是4个字节(libstlport.a捣的鬼)。
解决问题的办法就是环境变量输出,修改SConstruct和mA/SConscript如下:
SConstruct:
[cpp]view plain
7. 编译python的enable-shared是什么意思
这是 configure 常用的一个参数,表示启用动态库版本。 如果你要编译一个库的源代码,可以把它编译成静态库,也可以把它编译成动态库。如果你想编译成静态库,就用 --enable-shared参数;如果你想编译成静态库,就用--enable-static参数。
8. python 函数参数的类型
1. 不同类型的参数简述
#这里先说明python函数调用得语法为:
复制代码
代码如下:
func(positional_args,
keyword_args,
*tuple_grp_nonkw_args,
**dict_grp_kw_args)
#为了方便说明,之后用以下函数进行举例
def test(a,b,c,d,e):
print a,b,c,d,e
举个例子来说明这4种调用方式得区别:
复制代码
代码如下:
#
#positional_args方式
>>>
test(1,2,3,4,5)
1 2 3 4 5
#这种调用方式的函数处理等价于
a,b,c,d,e = 1,2,3,4,5
print a,b,c,d,e
#
#keyword_args方式
>>>
test(a=1,b=3,c=4,d=2,e=1)
1 3 4 2 1
#这种处理方式得函数处理等价于
a=1
b=3
c=4
d=2
e=1
print a,b,c,d,e
#
#*tuple_grp_nonkw_args方式
>>>
x = 1,2,3,4,5
>>> test(*x)
1 2 3 4
5
#这种方式函数处理等价于
复制代码
代码如下:
a,b,c,d,e = x
print
a,b,c,d,e
#特别说明:x也可以为dict类型,x为dick类型时将键传递给函数
>>> y
{'a': 1,
'c': 6, 'b': 2, 'e': 1, 'd': 1}
>>> test(*y)
a c b e d
#
#**dict_grp_kw_args方式
>>>
y
{'a': 1, 'c': 6, 'b': 2, 'e': 1, 'd': 1}
>>> test(**y)
1 2 6
1 1
#这种函数处理方式等价于
a = y['a']
b = y['b']
... #c,d,e不再赘述
print
a,b,c,d,e
2.
不同类型参数混用需要注意的一些细节
接下来说明不同参数类型混用的情况,要理解不同参数混用得语法需要理解以下几方面内容.
首先要明白,函数调用使用参数类型必须严格按照顺序,不能随意调换顺序,否则会报错. 如 (a=1,2,3,4,5)会引发错误,;
(*x,2,3)也会被当成非法.
其次,函数对不同方式处理的顺序也是按照上述的类型顺序.因为#keyword_args方式和**dict_grp_kw_args方式对参数一一指定,所以无所谓顺序.所以只需要考虑顺序赋值(positional_args)和列表赋值(*tuple_grp_nonkw_args)的顺序.因此,可以简单理解为只有#positional_args方式,#*tuple_grp_nonkw_args方式有逻辑先后顺序的.
最后,参数是不允许多次赋值的.
举个例子说明,顺序赋值(positional_args)和列表赋值(*tuple_grp_nonkw_args)的逻辑先后关系:
复制代码
代码如下:
#只有在顺序赋值,列表赋值在结果上存在罗辑先后关系
#正确的例子1
>>> x =
{3,4,5}
>>> test(1,2,*x)
1 2 3 4 5
#正确的例子2
>>>
test(1,e=2,*x)
1 3 4 5 2
#错误的例子
>>> test(1,b=2,*x)
Traceback (most recent call
last):
File "<stdin>", line 1, in <mole>
TypeError: test()
got multiple values for keyword argument 'b'
#正确的例子1,处理等价于
a,b = 1,2 #顺序参数
c,d,e = x #列表参数
print a,b,c,d,e
#正确的例子2,处理等价于
a = 1 #顺序参数
e = 2 #关键字参数
b,c,d = x #列表参数
#错误的例子,处理等价于
a = 1 #顺序参数
b = 2 #关键字参数
b,c,d = x
#列表参数
#这里由于b多次赋值导致异常,可见只有顺序参数和列表参数存在罗辑先后关系
函数声明区别
理解了函数调用中不同类型参数得区别之后,再来理解函数声明中不同参数得区别就简单很多了.
1. 函数声明中的参数类型说明
函数声明只有3种类型, arg, *arg , **arg 他们得作用和函数调用刚好相反.
调用时*tuple_grp_nonkw_args将列表转换为顺序参数,而声明中的*arg的作用是将顺序赋值(positional_args)转换为列表.
调用时**dict_grp_kw_args将字典转换为关键字参数,而声明中**arg则反过来将关键字参数(keyword_args)转换为字典.
特别提醒:*arg
和 **arg可以为空值.
以下举例说明上述规则:
复制代码
代码如下:
#arg, *arg和**arg作用举例
def
test2(a,*b,**c):
print a,b,c
#
#*arg 和
**arg可以不传递参数
>>> test2(1)
1 () {}
#arg必须传递参数
>>>
test2()
Traceback (most recent call last):
File "<stdin>", line 1,
in <mole>
TypeError: test2() takes at least 1 argument (0 given)
#
#*arg将顺positional_args转换为列表
>>>
test2(1,2,[1,2],{'a':1,'b':2})
1 (2, [1, 2], {'a': 1, 'b': 2})
{}
#该处理等价于
a = 1 #arg参数处理
b = 2,[1,2],{'a':1,'b':2} #*arg参数处理
c =
dict() #**arg参数处理
print a,b,c
#
#**arg将keyword_args转换为字典
>>>
test2(1,2,3,d={1:2,3:4}, c=12, b=1)
1 (2, 3) {'c': 12, 'b': 1, 'd': {1: 2, 3:
4}}
#该处理等价于
a = 1 #arg参数处理
b= 2,3 #*arg参数处理
#**arg参数处理
c =
dict()
c['d'] = {1:2, 3:4}
c['c'] = 12
c['b'] = 1
print
a,b,c
2. 处理顺序问题
函数总是先处理arg类型参数,再处理*arg和**arg类型的参数.
因为*arg和**arg针对的调用参数类型不同,所以不需要考虑他们得顺序.
复制代码
代码如下:
def test2(a,*b,**c):
print
a,b,c
>>> test2(1, b=[1,2,3], c={1:2, 3:4},a=1)
Traceback (most
recent call last):
File "<stdin>", line 1, in
<mole>
TypeError: test2() got multiple values for keyword argument
'a'
#这里会报错得原因是,总是先处理arg类型得参数
#该函数调用等价于
#处理arg类型参数:
a = 1
a = 1
#多次赋值,导致异常
#处理其他类型参数
...
print a,b,c
>>> def foo(x,y):
... def bar():
... print
x,y
... return bar
...
#查看func_closure的引用信息
>>> a =
[1,2]
>>> b = foo(a,0)
>>>
b.func_closure[0].cell_contents
[1, 2]
>>>
b.func_closure[1].cell_contents
0
>>> b()
[1, 2] 0
#可变对象仍然能被修改
>>> a.append(3)
>>>
b.func_closure[0].cell_contents
[1, 2, 3]
>>> b()
[1, 2, 3] 0
9. python如何通过命令行输入参数
形式一:直接在命令行输入参数
第一个红色框为命令行参数
第二个框为控制台模式(Terminal)
形式二:在编译工具中配置参数
点击运行:点击红色框 编辑配置
如下图:红色框即为设置的命令行参数