

|
|
在下列情况下,我们可以获得一个login shell:
配置文件的加载:shell首先加载/etc/profile
,然后再尝试依次去加载下列三个配置文件之一,一旦找到其中一个便不再接着寻找:
最后一种模式为非交互非登陆的shell,创建这种shell典型有两种方式:
BASH_ENV
,将变量的值作为文件名进行查找,如果找到便加载它。至此,四种模式下配置文件如何加载已经讲完,因为涉及的配置文件有些多,我们再以两个图来更为直观的进行描述:
第一张图来自这篇文章,bash的每种模式会读取其所在列的内容,首先执行A,然后是B,C。而B1,B2和B3表示只会执行第一个存在的文件:
+----------------+--------+-----------+---------------+
| | login |interactive|non-interactive|
| | |non-login |non-login |
+----------------+--------+-----------+---------------+
|/etc/profile | A | | |
+----------------+--------+-----------+---------------+
|/etc/bash.bashrc| | A | |
+----------------+--------+-----------+---------------+
|~/.bashrc | | B | |
+----------------+--------+-----------+---------------+
|~/.bash_profile | B1 | | |
+----------------+--------+-----------+---------------+
|~/.bash_login | B2 | | |
+----------------+--------+-----------+---------------+
|~/.profile | B3 | | |
+----------------+--------+-----------+---------------+
|BASH_ENV | | | A |
+----------------+--------+-----------+---------------+
模块让你能够有逻辑地组织你的Python代码段。
把相关的代码分配到一个 模块里能让你的代码更好用,更易懂。
模块也是Python对象,具有随机的名字属性用来绑定或引用。
简单地说,模块就是一个保存了Python代码的文件。模块能定义函数,类和变量。模块里也能包含可执行的代码。
Sam学习Python的过程,主要是跟着《Learn PYTHON the Hard WAY》,其中习题40中,明确指出,
A: 模块是包含函数和编来那个的Python文件。
B: 其它程序可以导入这个文件。
C: 然后可以使用 . 操作符访问模块中的函数和变量。
例1:
supports.py:
def apple():
print "I am an Apple!"
tangerine = "Living reflection of a dream"
接下来就可以import这个模块,并用 .操作符调用函数。
import supports
supports.apple()
print supports.tangerine
1. 模块的导入:
模块的导入方式有以下几种:
A: import
B: from .... import
C: from .... import *
导入模式的异同:
A:import:
import supports
supports.apple()
print supports.tangerine
在调用函数,变量和类时,需要使用模块名+.操作符调用。
B:from ModuleName import name
from语句让你从模块中导入一个指定的部分到当前命名空间中.
from supports import apple
这个声明不会把整个supports模块导入到当前的命名空间中,它只会将supports里的apple单个引入到执行这个声明的模块的全局符号表。
C: from ModuleName import *
把一个模块的所有内容全都导入到当前的命名空间也是可行的
B和C连个方式,在使用函数,变量和类时,不需要使用模块名+.操作符调用。 而是直接调用。
例如:
from supports import *
apple()
print tangerine
2. 模块定位:
当使用import ,from... import...导入模块时, Python解析器对模块定位的搜索顺序为:
1. 当前目录。 (即input script所在目录)
2. shell 变量 PYTHONPATH下的每个目录。
3. 默认目录。Python安装目录。 如: /usr/local/lib/python
截至到现在,Python module还是很清晰的。Python由 modulename.py构成。内容放置在modulename.py中。modulename就是文件名。
文件名就是模块名加上后缀.py
导入方式有三种。看来没啥问题。
3. 模块导入的具体行为:
一个模块被导入,那些内容被执行,哪些不被执行呢?这就是模块导入的具体行为定义的:
每个module都包含对象定义和一些语句(statements),这些语句应该是意图要来初始化这个module的,这些语句会在这个module第一次被import的时候执行(多次import只会执行一次,不管是以上两种import的语句中那一种),当这个module被作为一个script来运行的时候也会被执行。
每个module都有自己的private symbol table,当使用第一种import语句import一个module的时候,引入者的local symbol table就加入了这个module,其名字如果没有使用as的话就是被引入的模块名本身。使用第二种import语句这会在引入者的local symbol table中加入具体引用的item,其名称若没使用as则就为item的名称。
这就是为何单纯import时,需要用modulename.item. 而是用from...import时, 直接调用item本身。
例:
fibo.py如下:
1 print ("__name__ :", __name__) 2 def fib(n): 3 a, b = 0, 1 4 result = [] 5 print ("in fib():", __name__) 6 while (b<<span style="font-family: 'Courier New' !important;">n): 7 result.append(b) 8 a, b = b, a+b 9 print(result)
这个fibo.py就是一个module,它有一个函数定义fib(),和一个语句(statement),第一行的print语句,我们在当前文件目录运行Python Interpreter就可以去引入这个模块,并执行模块中定义的fib()函数。
>>> import fibo ('__name__ :', 'fibo') #print语句执行 >>> fibo.fib(10) ('in fib() :', 'fibo') #fib()函数执行 [1, 1, 2, 3, 5, 8]
可以看到,在import的时候,这个module的语句(statements)执行了,所定义的函数并未执行,在通过module名引用module中的函数定义时,函数才被执行。
同样可以在一个script file中引入module,我们在fibo.py所在的目录创建另一个文件calculat.py
1 from fibo import fib 2 for n in range(10, 50, 5): 3 fib(n)
然后用Python解释器运行calcute.py得到结果。
4. Python标准库:
Python有一个标准库,其中定义了一系列的module,这些module中的一部分是直接集成在Interpreter中的,这些built-in module主要提供了很重要的但是Python语言又没有提供的功能,比如跟system call有关的sys module就集成在所有平台的Python Interpreter中,在Interpreter中集成哪些module是可以配置的,并且随平台不同而有差别。
遇到问题:
Sam在看一些例子代码时,首先遇到了:
import serial
import socket
等语句。
那按照以上认识,就应该有serial.py, socket.py等module存在。但Sam在当前目录,PYTHONPATH,/usr/local/lib/python等目录下均未能发现。这就有了疑问。
在疑问研究中,看到如下用法:
#pry
>>>import serial
>>>print serial.__file__
/usr/lib/python2.7/dist-packages/serial/__init__.pyc
>>>import socket
>>>print socket.__file__
/usr/lib/python2.7/socket.pyc
(__file__指向该模块的导入文件名)
Sam由此想到,是否除了 *.py, 还有类似 *.pyc的模块名呢?但__init__.py又是什么鬼?这就牵涉出Python中另一个概念---Pakcage。
5. python中的Package:
Package是一个分层次的文件目录结构,它定义了一个由模块及子包,和子包下的子包等组成的Python的应用环境。
package是一个directory,它包含sub-package或者是module,而module是.py文件,要让Python Interpreter把一个目录作为package,则该目录下必须有__init__.py文件,__init__.py可以为空,当然也可以有对象定义和语句,用来做初始化工作,__init__.py还有个作用就是设置__all__变量。
package本身就可以来作为一个module使用,只是它所包含的sub-module或module可以通过package name用package.module的名称形式去引用,这更有利于组织一系列相关的module,避免module间定义的名称的混乱。
package在实际工程中非常常用,__init__.py也常常不会为空,而会有对象定义和初始化代码来让这个包,也就是这个module,包含其该有的item定义。以后我们会对package做更多了解。
考虑一个在Phone目录下的pots.py文件。这个文件有如下源代码:
#!/usr/bin/python # -*- coding: UTF-8 -*- def Pots(): print "I'm Pots Phone"
同样地,我们有另外两个保存了不同函数的文件:
现在,在Phone目录下创建file __init__.py:
当你导入Phone时,为了能够使用所有函数,你需要在__init__.py里使用显式的导入语句,如下:
from Pots import Pots from Isdn import Isdn from G3 import G3
当你把这些代码添加到__init__.py之后,导入Phone包的时候这些类就全都是可用的了。
#!/usr/bin/python # -*- coding: UTF-8 -*- # 导入 Phone 包 import Phone Phone.Pots() Phone.Isdn() Phone.G3()
以上实例输出结果:
I'm Pots Phone I'm 3G Phone I'm ISDN Phone
如上,为了举例,我们只在每个文件里放置了一个函数,但其实你可以放置许多函数。你也可以在这些文件里定义Python的类,然后为这些类建一个包。
通过学习Pakcage,就可以完全解释:/usr/lib/python2.7/dist-packages/serial/__init__.pyc
即serial是一个pakcage.
具体举例分析:
port_publisher.py:
import os
import select
import socket
import sys
import time
import traceback
import serial
import serial.rfc2217
import slerialtools.list_ports
import dbus
其中,serial 就是一个Package. 在serial目录内,包含有__init__.py.
/
# Define the goal uint32 dishwasher_id # Specify which dishwasher we want to use --- # Define the result uint32 total_dishes_cleaned --- # Define a feedback message float32 percent_complete
#goal definition
int32 order
---
#result definition
int32[] sequence
---
#feedback definition
int32[] sequence
actionlib actionlib_msgs
roscpp
rospy
message_generation
用途 :长度为0的数组的主要用途是为了满足需要变长度 的结构体。
用法 :在一个结构体的最后 ,申明一个长度为0的数组,就可以使得这个结构体是可变长的。对于 编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代 表了一个不可修改的地址常量 (注意:数组名永远都不会是指针! ),但对于这个数组的大小,我们可以进行动态分配。例如:
typedef
struct{
int len;
char data[0];
}test_t;
int my_length = 10;
test_t *p_test =
(test_t *)malloc(sizeof(test_t) + my_length);
p_test->len = my_length;
......
free(p_test);
之后对于结构体中的数组可以像一般的数组一样进行访问。
1. 前导
前导是一个8比特的交替序列。他不是01010101就是10101010,取决于接入地址的第一个比特。
接收机可以根据前导的无线信号强度来配置自动增益控制。
2 接入地址
接入地址有两种类型:广播接入地址和数据接入地址。
对于数据信道,数据接入地址是一个随机值,但需要满足下面几点要求:
1) 数据接入地址不能超过6个连续的“0”或“1”。
2) 数据接入地址的值不能与广播接入地址相同。
3) 数据接入地址的4个字节的值必须互补相同。
4) 数据接入地址不能有超24次的比特翻转(比特0到1或1到0,称为1次比特翻转)。
5) 数据接入地址的最后6个比特需要至少两次的比特翻转。
6) 符合上面条件的有效随机数据接入地址大概有231个。
3. PDU--协议数据单元:
这部分才是BLE 的关键:
广播报文的报头包含4bit广播报文类型、2bit保留位、1bit发送地址类型和1bit接收地址类型。
广播报文类型:
在Linux BlueZ中,它就是:
typedef struct {
uint8_t evt_type;
uint8_t bdaddr_type;
bdaddr_t bdaddr;
uint8_t length;
uint8_t data[0];
} __attribute__ ((packed)) le_advertising_info;
对应解析代码:
static const char *evttype2str(uint8_t type)
{
switch (type) {
case 0x00:
return "ADV_IND - Connectable undirected advertising";
case 0x01:
return "ADV_DIRECT_IND - Connectable directed advertising";
case 0x02:
return "ADV_SCAN_IND - Scannable undirected advertising";
case 0x03:
return "ADV_NONCONN_IND - Non connectable undirected advertising";
case 0x04:
return "SCAN_RSP - Scan Response";
default:
return "Reserved";
}
}
发送地址类型和接收地址类型指示了设备使用公共地址(Public Address)还是随机地址(Random Address)。公共地址和随机地址的长度一样,都包含6个字节共48位。BLE设备至少要拥有这两种地址类型中的一种,当然也可以同时拥有这两种地址类型。
它在BlueZ中:
typedef struct {
uint8_t evt_type;
uint8_t bdaddr_type;
bdaddr_t bdaddr;
uint8_t length;
uint8_t data[0];
} __attribute__ ((packed)) le_advertising_info;
static const char *bdaddrtype2str(uint8_t type)
{
switch (type) {
case 0x00:
return "Public";
case 0x01:
return "Random";
default:
return "Reserved";
}
}
长度
广播报文和和数据报文的长度域有所不同,主要原因是:广播报文除了最多31个字节的数据之外,还必须要包含6个字节的广播设备地址。6+31=37,所以需要6比特的长度域。
再次强调:广播时必须要包含6个字节的广播设备地址。
typedef struct {
uint8_t evt_type;
uint8_t bdaddr_type;
bdaddr_t bdaddr;
uint8_t length;
uint8_t data[0];
} __attribute__ ((packed)) le_advertising_info;
图8:广播和扫描响应的数据格式
1) 有效数据部分:包含N个AD Structure,每个AD Structure由Length,AD Type和AD Data组成。其中:
1 #define BLE_GAP_AD_TYPE_FLAGS 0x01 2 #define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE 0x02 3 #define BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE 0x03 4 #define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE 0x04 5 #define BLE_GAP_AD_TYPE_32BIT_SERVICE_UUID_COMPLETE 0x05 6 #define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE 0x06 7 #define BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE 0x07 8 #define BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME 0x08 9 #define BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME 0x09 10 #define BLE_GAP_AD_TYPE_TX_POWER_LEVEL 0x0A 11 #define BLE_GAP_AD_TYPE_CLASS_OF_DEVICE 0x0D 12 #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C 0x0E 13 #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R 0x0F 14 #define BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE 0x10 15 #define BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS 0x11 16 #define BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE 0x12 17 #define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT 0x14 18 #define BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT 0x15 19 #define BLE_GAP_AD_TYPE_SERVICE_DATA 0x16 20 #define BLE_GAP_AD_TYPE_PUBLIC_TARGET_ADDRESS 0x17 21 #define BLE_GAP_AD_TYPE_RANDOM_TARGET_ADDRESS 0x18 22 #define BLE_GAP_AD_TYPE_APPEARANCE 0x19 23 #define BLE_GAP_AD_TYPE_ADVERTISING_INTERVAL 0x1A 24 #define BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS 0x1B 25 #define BLE_GAP_AD_TYPE_LE_ROLE 0x1C 26 #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_HASH_C256 0x1D 27 #define BLE_GAP_AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256 0x1E 28 #define BLE_GAP_AD_TYPE_SERVICE_DATA_32BIT_UUID 0x20 29 #define BLE_GAP_AD_TYPE_SERVICE_DATA_128BIT_UUID 0x21 30 #define BLE_GAP_AD_TYPE_3D_INFORMATION_DATA 0x3D 31 #define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF
原码:
知道了什么是原码,那反码就更是张飞吃豆芽——小菜一碟了。知道了原码,那么你只需要具备区分0跟1的能力就可以轻松求出反码,为什么呢?因为反码就是在原码的基础上,符号位不变其他位按位取反(就是0变1,1变0)就可以了。
例如:X=-101011 ,
[X]原= 10101011 ,[X]反=11010100
补码:
补码也非常的简单就是在反码的基础上按照正常的加法运算加1。
例如:X=-101011 ,
[X]原= 10101011 ,[X]反=11010100,[X]补=11010101
PS:0的补码是唯一的,如果机器字长为8那么[0]补=00000000。
移码:
移码最简单了,不管正负数,只要将其补码的符号位取反即可。
例如:X=-101011 , [X]原= 10101011 ,[X]反=11010100,[X]补=11010101,[X]移=01010101