Mac系统Eclipse无法导入Python第三方模块的解决办法

使用pip安装了python的第三方库,但eclipse中导入不成功,import xxx时提示“no module named xxx”

版本

  • eclipse 4.5.0
  • python 2.7.11
  • pip 8.1.1

为什么呢

先来看一下Eclipse中的Python Interpreter。打开Eclipse-偏好设置-PyDev-Interpreters-Python Interpreter
Python Interpreter
可以看到System Libs中第三方包的目录是/Library/Python/2.7/site-packages
再看一下pip的安装目录,打开终端,输入pip –version
pip version
可以看到pip的site-package的安装目录是/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages
这样就找到原因了,是eclipse中的库路径与pip的下载路径不一致所造成的。我尝试修改了一下eclipse中的System Libs,点击New Folder去找pip的下载路径,然而根本找不到这个目录,而在Finder中是可以看到这个目录的(不知道为什么,是不是因为用户权限不同,可见性不一样?)

解决方法

在网上找了一圈,有人说可以把pip的site-package的安装目录下的所有文件拷贝到/Library/Python/2.7/site-packages下,然后写一个脚本,每次安装新的第三方库时都拷贝一次。然而宝宝比较懒,不想每次都执行脚本。
想了一下,这个方法可以用软链接来替代。软链接实际上是一段文字,里面包含着它所指向的文件的名字,系统看到软链接后自动跳到对应的文件位置处进行处理,就相当于Windows下的快捷方式。我们可以将/Library/Python/2.7/site-packages这个目录直接链接到第三方库的安装目录。

步骤

打开终端,进入目录/Library/Python/2.7/

1
cd /Library/Python/2.7/

先做好备份

1
sudo mv site-packages site-packages-backup

链接两个目录

1
sudo ln -s /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/ .

查看一下属性

1
2
localhost:2.7 yuuuu$ ls -l site-packages
lrwxr-xr-x 1 root wheel 78 4 12 10:26 site-packages -> /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/

成功链接了两个目录

好了,再重启一下Eclipse,import下的红线消失了,大功告成!

程序员笔试题集合

整理一下最近遇到的笔试题,希望能被offer砸死。

第一题 int **a[2][4]在32位的机器上占用多少内存?

这定义了一个2*4的指针数组,每个指针的大小是4字节,所以总共占用了 2*4*4=32字节。int* 是指向数组的指针,int**是指向指针的指针,所以都是4字节。

第二题 #ifdef #if defined #if的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define TEST1 1
#define TEST2 0
int main(){
int count=0;

#ifdef TEST2
count+=1;
#endif

#if defined TEST1
count+=2;
#endif

#if(TEST1)
count+=4;
#endif

#if(TEST2)
count+=8;
#endif

printf("count=%d\n",count);
return 0;
}

这段代码的输出是多少?

答案是count=7

  1. #ifdef和#if defined判断是否宏定义过,区别是#ifdef只能判断单个宏是否定义过,#if defined可以写一些复杂的语法,比如

    1
    #if defined (A) && defined (B)
  2. #if后面接表达式,表达式为真,编译器就会将后面的代码编译进去。

  3. 最后强调一点,这些宏定义都是决定代码是否会被编译,不是执行。

第三题 Union

1
2
3
4
5
6
7
8
9
10
11
12
int main(){
union{
int c;
struct{
int a;
int b;
}b;
int a;
}test;
test.b.a=1;
printf("%d %d %d\n",test.a,test.b.b,test.c);
}

运行后:test.a=1,test.b.b不确定,test.c=1;

Union的所有成员共用一个内存空间,内存空间以size最大的成员变量为准,所有成员从低地址开始对齐。一次只能访问一个成员变量,在对某个成员变量修改时也会改变其他成员变量的值,但当size不同时,只会覆盖相对应的内存部分。
在本题中,test.b.a的值修改后,test.a、test.c与其内存地址相同,也会被覆盖,test.b.b不会被修改,没有赋初值,所以是不确定。

大端模式和小端模式

  • 大端模式(Big endian):数据的高字节存储在低地址中。
  • 小端模式(Little endian):数据的低字节存储在低地址中。

union中的成员变量都是从低地址开始对齐的,所以,在不同的CPU下会有不同的结果,可以由union来判断CPU类型,看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main(){
union{
struct{
char a;
char b;
char c;
char d;
}s;
int x;
}test;
test.s.a=1;
test.s.b=2;
test.s.c=3;
test.s.d=4;
printf("0X%08x",test.x);
}

char占1字节,int占4字节,由低地址开始对齐,每个地址存放一个字节(8位),在一个字节中的数是固定的,比如地址0x00存放的是01而不是10,与大小端无关。而int型占了4字节,如果是在小端模式下,低位地址存的是数据低位,test.x数据从高位到低位为04030201;在大端模式下,低位地址存的是数据高位,test.x为01020304,注意这个数是十六进制的。根据这个值就可以判断CPU是什么模式的了。一般的x86架构都是小端模式。

地址 0x00 0x01 0x02 0x03
test.s 01 02 03 04

主机序和网络序

  • 主机序:不同的CPU有不同的字节序类型,即整数在内存中保存的顺序,一般有两种,就是之前说的大端模式与小端模式。
  • 网络序:TCP/IP中定义的数据表示格式,保证数据在不同CPU类型的主机之间传输时能被正确解释。网络字节序采用大端模式。在数据传输时会进行主机序与网络序之间的转换,保证数据的正确性。

第四题 JavaScript 变量作用域

1
2
3
4
5
6
7
var s = "global";
function f(){
console.log(s);
var s = "local";
console.log(s);
}
f();

运行结果为:

undefined  
local

Javascript中没有块级作用域,只有函数作用域,var声明的变量都是局部变量,变量在声明它的函数体内是有定义的。第一句的console.log(s)在s未声明就使用了,这时s是未定义的,外面定义的变量并不能作用到函数内部。

第五题 sizeof strlen

1
2
3
4
5
6
7
int main(){
char str[10]="Hel\0lo\0";
int len1 = strlen(str);
int len2 = sizeof(str);
printf("%d %d",len1,len2);

}

运行结果为:3 10

  • sizeof 是运算符,其值在编译时就计算好了,获得能容纳实现所建立的最大对象的字节大小。
  • strlen 是函数,是在运行时计算的,返回字符串的长度,从第一个地址开始遍历,直到遇到字符串的结束符’\0’。

给定一个字符串,找出字符串中包含{'a','b','c'}字符集的最短子串

给定字符串str,字符集{’a’,’b’,’c’},’a’,’b’,’c’的顺序可以改变,要找出包含字符集中所有字符的最短字串。

  • Record记录每个字符是否出现和最后出现的位置,minLength记录最短子串长度。
  • 设置front, rear指针。rear遍历str字符串,当遇到字符集中的字符时更新该字符的标记和位置。
  • 在front到rear区间,判断字符集中的字符是否都出现了,若是,从所有字符最后出现的位置中找出最小和最大的位置min、max,则区间内最短子串长度为max - min + 1。
  • front指针用于优化。当字符集中的字符都出现后,front指针置为min + 1, 并且清除min位置的字符状态。
  • 时间复杂度为O(n)。

参考了http://blog.csdn.net/expleeve/article/details/32715791 这个博客,但是他的front指针每次只移动1位,如果这一位本来就不包含在最短的子串里,那么没有什么实际意义,所以这里改进了一下,每次都移到min + 1的位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include<map>
#include<string>
using namespace std;

struct Record{
bool isAppear;
int lastPos;
};

map<char, Record> mp;
int front, rear;
int minLength;

string str = "ababaaassaxxxaaacccd";
char charset[3] = {'a', 'b', 'c'};

bool isValid(){
for(auto it = mp.begin();it != mp.end(); it++){
if(!it->second.isAppear){
return false;
}
}
return true;
}

void updateFront(int pos){
front = pos + 1;
mp[str[pos]].isAppear = false;
}

int countLength(){
int max = -1, min = INT_MAX;
for(auto it = mp.begin(); it != mp.end(); it++){
if(it->second.lastPos > max)
max = it->second.lastPos;
if(it->second.lastPos < min)
min = it->second.lastPos;
}
updateFront(min);
return max - min + 1;
}

int main(){

for(int i = 0; i < 3; i++){
Record r;
r.isAppear = false;
mp[charset[i]] = r;
}
front = 0, rear = 0;
minLength = INT_MAX;

for(; rear < str.length(); rear++){
if(mp.find(str[rear]) != mp.end()){
mp[str[rear]].isAppear = true;
mp[str[rear]].lastPos = rear;
if(isValid()){
int len = countLength();
minLength = len < minLength ? len : minLength;
}
}
}
printf("minLength = %d\n", minLength);
return 0;
}