Python基础教程

本章将介绍python的最基本语法,以及一些和深度学习还有计算机视觉最相关的基本使用。
python简介 python是一门解释型的高级编程语言,特点是简单明确。python作者是荷兰人guido van rossum,1982年他获得数学和计算机硕士学位后,在荷兰数学与计算科学研究所(centrum wiskunde & informatica, cwi)谋了份差事。在cwi期间,guido参与到了一门叫做abc的语言开发工作中。abc是一门教学语言,所以拥有简单,可读性好,语法更接近自然语言等特点。在那个c语言一统天下的年代,abc就是一股简单的清流,毕竟是门教学语言,最后没有流行起来,不过这段经历影响了guido。1989年的圣诞假期,闲得蛋疼的guido决定设计一门简单易用的新语言,要介于c和shell之间,同时吸取abc语法中的优点。guido用自己喜欢的一部喜剧电视剧来命名这门语言:《monty python‘s flying circus》。
1991年,第一版基于c实现的python编译器诞生,因为简单,拓展性好,python很快就在guido的同事中大受欢迎,不久python的核心开发人员就从guido一人变成了一个小团队。后来随着互联网时代的到来,开源及社区合作的方式蓬勃发展,python也借此上了发展的快车道。因为python非常容易拓展,在不同领域的开发者贡献下,许多受欢迎的功能和特征被开发出来,渐渐形成了各种各样的库,其中一部分被加入到python的标准库中,这让本来就不需要过多思考底层细节的python变得更加强大好用。在不过多考虑执行效率的前提下,使用python进行开发的周期相比传统的c/c++甚至java等语言都大大缩短,代码量也大幅降低,所以出bug的可能性也小了很多。因此有了语言专家bruce eckel的那句名言:life is short, you need python. 后来这句话的中文版“人生苦短,我用python”被guido印在了t恤上。发展至今,python渐渐成了最流行的语言之一,在编程语言排行榜tobie中常年占据前5的位置。另外随着python的用户群越来越壮大,慢慢在本身特点上发展出了自己的哲学,叫做python的禅(the zen of python)。遵循python哲学的做法叫做很python(pythonic),具体参见:
pep 20 — the zen of python
>> import this
python拥有很好的扩充性,可以非常轻松地用其他语言编写模块供调用,用python编写的模块也可以通过各种方式轻松被其他语言调用。所以一种常见的python使用方式是,底层复杂且对效率要求高的模块用c/c++等语言实现,顶层调用的api用python封装,这样可以通过简单的语法实现顶层逻辑,故而python又被称为“胶水语言”。这种特性的好处是,无需花费很多时间在编程实现上,更多的时间可以专注于思考问题的逻辑。尤其是对做算法和深度学习的从业人员,这种方式是非常理想的,所以如今的深度学习框架中,除了matlab,或是deeplearning4j这种摆明了给java用的,其他框架基本上要么官方接口就是python,要么支持python接口。
安装和使用python python有两个大版本,考虑到用户群数量和库的各种框架的兼容性,本文以python2(2.7)为准,语法尽量考虑和python3的兼容。
unix/linux下的python基本都是系统自带的,一般默认为python2,使用时在终端直接键入python就能进入python解释器界面:
在解释器下就已经可以进行最基本的编程了,比如:
写程序的话还是需要保存成文件再执行,比如我们写下面语句,并且保存为helloworld.py:
print(“hello world!”)
然后在终端里执行:
安装更多的python库一般有两种方法,第一是用系统的软件包管理,以ubuntu 16.04 lts为例,比如想要安装numpy库(后面会介绍这个库),软件包的名字就是python-numpy,所以在终端中输入:
>> sudo apt install python-numpy
python自己也带了包管理器,叫做pip,使用如下:
>> pip install numpy
安装和深度学习相关的框架时,一般来说推荐使用系统自带的包管理,出现版本错误的可能性低一些。另外也可以使用一些提前配置好很多第三方库的python包,这些包通常已经包含了深度学习框架中绝大多数的依赖库,比如最常用的是anaconda:
download anaconda now!
windows下的python安装简单一些,从官方网站下载相应的安装程序就可以了,当然也有更方便的已经包含了很全的第三方库的选择,winpython:
winpython
并且是绿色的,直接执行就可以用了。
python基本语法 there should be one– and preferably only one –obvious way to do it.
对于一个特定的问题,应该只用最好的一种方法来解决。
— tim peters
基本数据类型和运算 基本数据类型
python中最基本的数据类型包括整型,浮点数,布尔值和字符串。类型是不需要声明的,比如:
a = 1 # 整数
b = 1.2 # 浮点数
c = true # 布尔类型
d = false # 字符串
e = none # nonetype
其中#是行内注释的意思。最后一个none是nonetype,注意不是0,在python中利用type函数可以查看一个变量的类型:
type(a) #
type(b) #
type(c) #
type(d) #
type(e) #
注释中是执行type()函数后的输出结果,可以看到none是单独的一种类型nonetype。在很多api中,如果执行失败就会返回none。
变量和引用
python中基本变量的赋值一般建立的是个引用,比如下面的语句:
a = 1
b = a
c = 1
a赋值为1后,b=a执行时并不会将a的值复制一遍,然后赋给b,而是简单地为a所指的值,也就是1建立了一个引用,相当于a和b都是指向包含1这个值的这块内存的指针。所以c=1执行的也是个引用建立,这三个变量其实是三个引用,指向同一个值。这个逻辑虽然简单,不过也还是常常容易弄混,这没关系,python内置了id函数,可以返回一个对象的地址,用id函数可以让我们知道每个变量指向的是不是同一个值:
id(a) # 35556792l
id(b) # 35556792l
id(c) # 35556792l
注释中表示的仍是执行后的结果。如果这时候我们接下面两个语句:
b = 2 # b的引用到新的一个变量上
id(b) # 35556768l
可以看到b引用到了另一个变量上。
运算符
python中的数值的基本运算和c差不多,字符串的运算更方便,下面是常见的例子:
a = 2
b = 2.3
c = 3
a + b # 2 + 2.3 = 4.3
c – a # 3 - 2 = 1
a / b # 整数除以浮点数,运算以浮点数为准,2 / 2.3 = 0.8695652173913044
a / c # python2中,整数除法,向下取整 2 / 3 = 0
a ** c # a的c次方,结果为8
a += 1 # python中没有i++的用法,自增用+=
c -= 3 # c变成0了
d = 'hello'
d + ' world!' # 相当于字符串拼接,结果为'hello world!'
d += ' world!'# 相当于把字符串接在当前字符串尾,d变为'hello world!'
e = r'\n\t\\'
print(e) # '\\n\\t\\\\'
需要提一下的几点:1)字符串用双引号和单引号都可以,区别主要是单引号字符串中如果出现单引号字符则需要用转义符,双引号也是一样,所以在单引号字符串中使用双引号,或者双引号字符串中使用单引号就会比较方便。另外三个双引号或者三个单引号围起来的也是字符串,因为换行方便,更多用于文档。2)python2中两个数值相除会根据数值类型判断是否整数除法,python3种则都按照浮点数。想要在python2种也执行python3中的除法只要执行下面语句:
from __future__ import division # 使用python3中的除法
1 / 2
3)字符串前加r表示字符串内容严格按照输入的样子,好处是不用转义符了,非常方便。
python中的布尔值和逻辑的运算非常直接,下面是例子:
a = true
b = false
a and b # false
a or b # true
not a # false
基本上就是英语,操作符优先级之类的和其他语言类似。python中也有位操作:
~8 # 按位翻转,1000 --> -(1000+1)
8 >> 3 # 右移3位,1000 --> 0001
1 年龄的字典,并执行一些常见操作:
a = {'tom': 8, 'jerry': 7}
print(a['tom']) # 8
b = dict(tom=8, jerry=7) # 一种字符串作为键更方便的初始化方式
print(b['tom']) # 8
if 'jerry' in a: # 判断'jerry'是否在keys里面
print(a['jerry']) # 7
print(a.get('spike')) # none,通过get获得值,即使键不存在也不会报异常
a['spike'] = 10
a['tyke'] = 3
a.update({'tuffy': 2, 'mammy two shoes': 42})
print(a.values()) # dict_values([8, 2, 3, 7, 10, 42])
print(a.pop('mammy two shoes')) # 移除'mammy two shoes'的键值对,并返回42
print(a.keys()) # dict_keys(['tom', 'tuffy', 'tyke', 'jerry', 'spike'])
注意到初始化字典和集合很像,的确如此,集合就像是没有值只有键的字典。既然有了人名到年龄的映射,也许你立马想到是否可以给字典排序?在python3.6之前,这个问题是错误的,字典是一种映射关系,没有顺序。当然了,如果要把(键, 值)的这种对进行排序,是没有问题的,前提是先把字典转化成可排序的结构,items()或者iteritems()可以做到这件事,接上段代码继续:
b = a.items()
print(b) # [('tuffy', 2), ('spike', 10), ('tom', 8), ('tyke', 3), ('jerry', 7)]
from operator import itemgetter
c = sorted(a.items(), key=itemgetter(1))
print(c) # [('tuffy', 2), ('tyke', 3), ('jerry', 7), ('tom', 8), ('spike', 10)]
d = sorted(a.iteritems(), key=itemgetter(1))
print(d) # [('tuffy', 2), ('tyke', 3), ('jerry', 7), ('tom', 8), ('spike', 10)]
e = sorted(a)
print(e) # 只对键排序,['jerry', 'spike', 'tom', 'tuffy', 'tyke']
items()可以把字典中的键值对转化成一个列表,其中每个元素是一个tuple,tuple的第一个元素是键,第二个元素是值。变量c是按照值排序,所以需要一个操作符itemgetter,去位置为1的元素作为排序参考,如果直接对字典排序,则其实相当于只是对键排序。字典被当作一个普通的可遍历结构使用时,都相当于遍历字典的键。如果觉得字典没有顺序不方便,可以考虑使用ordereddict,使用方式如下:
from collections import ordereddict
a = {1: 2, 3: 4, 5: 6, 7: 8, 9: 10}
b = ordereddict({1: 2, 3: 4, 5: 6, 7: 8, 9: 10})
print(a) # {1: 2, 3: 4, 9: 10, 5: 6, 7: 8}
print(b) # ordereddict([(1, 2), (3, 4), (9, 10), (5, 6), (7, 8)])
这样初始化时的顺序就保留了,除了有序的特性以外,用法上和字典没有区别。2016年9月,guido宣布在python3.6中,字典将默认有序,这样就不用纠结了。另外需要注意的一点是字典是通过哈希表实现的,所以键必须是可哈希的, list不能被哈希,所以也不能作为字典的键,而tuple就可以。
因为上上段代码中用到了iteritems(),所以这里顺带提一下迭代器(iterator),迭代器相当于一个函数,每次调用都返回下一个元素,从遍历的角度来看就和列表没有区别了。iteritems()就是一个迭代器,所以效果一样,区别是迭代器占用更少内存,因为不需要一上来就生成整个列表。一般来说,如果只需要遍历一次,用迭代器是更好的选择,若是要多次频繁从一个可遍历结构中取值,且内存够,则直接生成整个列表会更好。当然,用迭代器生成一个完整列表并不麻烦,所以有个趋势是把迭代器作为默认的可遍历方式,比如前面我们使用过用来生成等差数列列表的range(),在python2中对应的迭代器形式是xrange()。在python3中,range()就不再产生一个列表了,而是作为迭代器,xrange()直接没了。
分支和循环
从这节开始,代码就未必适合在python终端中输入了,选个顺手的编辑器或者ide。作者良心推荐pycharm,虽然慢,但好用,社区版免费:
pycharm
for循环
上面提到的4种容器类型都是可遍历的,所以该讲讲用来遍历的for循环了。for循环的语法也是简单的英语:
a = ['this', 'is', 'a', 'list', '!']
b = ['this', 'is', 'a', 'tuple', '!']
c = {'this': 'is', 'an': 'unordered', 'dict': '!'}
# 依次输出:'this', 'is', 'a', 'list', '!'
for x in a:
print(x)
# 依次输出:'this', 'is', 'a', 'tuple', '!'
for x in b:
print(x)
# 键的遍历。不依次输出:'this', 'dict', 'an'
for key in c:
print(key)
# 依次输出0到9
for i in range(10):
print(i)
注意到每个for循环中,print都有缩进,这是python中一个让人爱恨交织的特点:强行缩进来表明成块的代码。这样做的好处是代码十分清晰工整,还有助于防止写出过长的函数或者过深的嵌套,坏处是有时候不知为什么tab和空格就一起出现了,又或是多重if-else不知怎得就没对齐,还是挺麻烦的。
回到for循环上,这种把每个元素拿出来的遍历方式叫做for_each风格,熟悉java的话就不会陌生,c++11中也开始支持这种for循环方式。不过如果还是需要下标呢?比如遍历一个list的时候,希望把对应下标也打印出来,这时可以用enumerate:
names = [rick, daryl, glenn]
# 依次输出下标和名字
for i, name in enumerate(names):
print(i, name)
需要注意的是,通过取下标遍历当然是可行的,比如用len()函数获得列表长度,然后用range()/xrange()函数获得下标,但是并不推荐这样做:
words = [this, is, not, recommended]
# not pythonic :(
for i in xrange(len(words)):
print(words[i])
在使用for循环时,有时会遇到这样一种场景:我们需要对遍历的每个元素进行某种判断,如果符合这种判断的情况没有发生,则执行一个操作。举个例子某神秘部门要审核一个字符串列表,如果没有发现不和谐的字眼,则将内容放心通过,一种解决办法是下面这样:
wusuowei = [i, don't, give, a, shit] # 无所谓
hexie = true # 默认和谐社会
for x in wusuowei:
if x == f**k:
print(what the f**k!) # 发现了不该出现的东西,wtf!
hexie = false # 不和谐了
break # 赶紧停下!不能再唱了
if hexie: # 未发现不和谐元素!
print(harmonious society!) # 和谐社会!
这样需要设置一个标记是否发现不和谐因素的状态变量hexie,循环结束后再根据这个变量判断内容是否可以放心通过。一种更简洁不过有些小众的做法是直接和else一起,如果for循环中的if块内的语句没有被触发,则通过else执行指定操作:
wusuowei = [i, don't, give, a, shit]
for x in wusuowei:
if x == f**k:
print(what the f**k!)
hexie = false
break
else: # for循环中if内语句未被触发
print(harmonious society!) # 和谐社会!
这样不需要一个标记是否和谐的状态变量,语句简洁了很多。
if和分支结构 上一个例子中已经出现if语句了,所以这部分讲讲if。python的条件控制主要是三个关键字:if-elif-else,其中elif就是else if的意思。还是看例子:
pets =['dog', 'cat', 'droid', 'fly']
for pet in pets:
if pet == 'dog': # 狗粮
food = 'steak' # 牛排
elif pet == 'cat': # 猫粮
food = 'milk' # 牛奶
elif pet == 'droid': # 机器人
food = 'oil' # 机油
elif pet == 'fly': # 苍蝇
food = 'sh*t' #
else:
pass
print(food)
需要提一下的是pass,这就是个空语句,什么也不做,占位用。python并没有switch-case的语法,等效的用法要么是像上面一样用if-elif-else的组合,要么可以考虑字典:
pets = ['dog', 'cat', 'droid', 'fly']
food_for_pet = {
'dog': 'steak',
'cat': 'milk',
'droid': 'oil',
'fly': 'sh*t'
}
for pet in pets:
food = food_for_pet[pet] if pet in food_for_pet else none
print(food)
这里还用到了一个if-else常见的行内应用,就是代替三元操作符,如果键在字典中,则food取字典的对应值,否则为none。
if表达式中的小技巧
通过链式比较让语句简洁:
if -1 < x -1 and x < 1:
print('the absolute value of x is 0
print('birds')
if '': # 判断是否空字符串,同上
print('nothing!')
if {}: # 判断是否空的容器(字典),相较于len({}) > 0
print('nothing!')
隐式表达式为false的是如下状况:
– none
– false
– 数值0
– 空的容器或序列(字符串也是一种序列)
– 用户自定义类中,如果定义了__len__()或者__nonzero__(),并且被调用后返回0或者false
while循环 while的就是循环和if的综合体,是一种单纯的基于条件的循环,本身没有遍历的意思,这是和for_each的本质差别,这种区别比起c/c++中要明确得多,用法如下:
i = 0
while i = 0:
yield x
x -= 1
for i in countdown(10):
print(i)
# 打印小于100的斐波那契数
def fibonacci(n):
a = 0
b = 1
while b < n:
yield b
a, b = b, a + b
for x in fibonacci(100):
print(x)
生成器和所有可迭代结构一样,可以通过next()函数返回下一个值,如果迭代结束了则抛出stopiteration异常:
a = fibonacci(3)
print(next(a)) # 1
print(next(a)) # 1
print(next(a)) # 2
print(next(a)) # 抛出stopiteration异常
python3.3以上可以允许yield和return同时使用,return的是异常的说明信息:
# python3.3以上可以return返回异常的说明
def another_fibonacci(n):
a = 0
b = 1
while b 代表右对齐,>前是要填充的字符,依次输出:
# 000001
# 000019
# 000256
for i in [1, 19, 256]:
print('the index is {:0>6d}'.format(i))
# <代表左对齐,依次输出:
# *---------
# ****------
# *******---
for x in ['*', '****', '*******']:
progress_bar = '{:-<10}'.format(x)
print(progress_bar)
for x in [0.0001, 1e17, 3e-18]:
print('{:.6f}'.format(x)) # 按照小数点后6位的浮点数格式
print('{:.1e}'.format(x)) # 按照小数点后1位的科学记数法格式
print ('{:g}'.format(x)) # 系统自动选择最合适的格式
template = '{name} is {age} years old.'
c = template.format(name='tom', age=8)) # tom is 8 years old.
d = template.format(age=7,)# jerry is 7 years old.
format在生成字符串和文档的时候非常有用,更多更详细的用法可以参考python官网:
7.1. string – common string operations – python 2.7.13 documentation
文件操作和pickle 在python中,推荐用上下文管理器(with-as)来打开文件,io资源的管理更加安全,而且不用老惦记着给文件执行close()函数。还是举例子来说明,考虑有个文件name_age.txt,里面存储着名字和年龄的关系,格式如下:
tom,8
jerry,7
tyke,3
...
读取文件内容并全部显示:
with open('name_age.txt', 'r') as f: # 打开文件,读取模式
lines = f.readlines() # 一次读取所有行
for line in lines: # 按行格式化并显示信息
name, age = line.rstrip().split(',')
print('{} is {} years old.'.format(name, age))
open()的第一个参数是文件名,第二个参数是模式。文件的模式一般有四种,读取(r),写入(w),追加(a)和读写(r+)。如果希望按照二进制数据读取,则将文件模式和b一起使用(wb, r+b…)。
再考虑一个场景,要读取文件内容,并把年龄和名字的顺序交换存成新文件age_name.txt,这时可以同时打开两个文件:
with open('name_age.txt', 'r') as fread, open('age_name.txt', 'w') as fwrite:
line = fread.readline()
while line:
name, age = line.rstrip().split(',')
fwrite.write('{},{}\n'.format(age, name))
line = fread.readline()
有的时候我们进行文件操作是希望把对象进行序列化,那么可以考虑用pickle模块:
import pickle
lines = [
i'm like a dog chasing cars.,
i wouldn't know what to do if i caught one...,
i'd just do things.
]
with open('lines.pkl', 'wb') as f: # 序列化并保存成文件
pickle.dump(lines, f)
with open('lines.pkl', 'rb') as f: # 从文件读取并反序列化
lines_back = pickle.load(f)
print(lines_back) # 和lines一样
注意到,序列化的时候就得使用b模式了。python2中有个效率更高的pickle叫cpickle,用法和pickle一样,在python3中就只有一个pickle。
异常 相比起其他一些语言,在python中我们可以更大胆地使用异常,因为异常在python中是非常常见的存在,比如下面这种简单的遍历:
a = ['why', 'so', 'serious', '?']
for x in a:
print(x)
当用for进行遍历时,会对要遍历的对象调用iter()。这需要给对象创建一个迭代器用来依次返回对象中的内容。为了能成功调用iter(),该对象要么得支持迭代协议(定义__iter__()),要么得支持序列协议(定义__getitem__())。当遍历结束时,__iter__()或者__getitem__()都需要抛出一个异常。__iter__()会抛出stopiteration,而__getitem__()会抛出indexerror,于是遍历就会停止。
在深度学习中,尤其是数据准备阶段,常常遇到io操作。这时候遇到异常的可能性很高,采用异常处理可以保证数据处理的过程不被中断,并对有异常的情况进行记录或其他动作:
for filepath in filelist: # filelist中是文件路径的列表
try:
with open(filepath, 'r') as f:
# 执行数据处理的相关工作
...
print('{} is processed!'.format(filepath))
except ioerror:
print('{} with ioerror!'.format(filepath))
# 异常的相应处理
...
多进程(multiprocessing) 深度学习中对数据高效处理常常会需要并行,这时多进程就派上了用场。考虑这样一个场景,在数据准备阶段,有很多文件需要运行一定的预处理,正好有台多核服务器,我们希望把这些文件分成32份,并行处理:
from multiprocessing import process#, freeze_support
def process_data(filelist):
for filepath in filelist:
print('processing {} ...'.format(filepath))
# 处理数据
...
if __name__ == '__main__':
# 如果是在windows下,还需要加上freeze_support()
#freeze_support()
# full_list包含了要处理的全部文件列表
...
n_total = len(full_list) # 一个远大于32的数
n_processes = 32
# 每段子列表的平均长度
length = float(n_total) / float(n_processes)
# 计算下标,尽可能均匀地划分输入文件列表
indices = [int(round(i*length)) for i in range(n_processes+1)]
# 生成每个进程要处理的子文件列表
sublists = [full_list[indices[i]:indices[i+1]] for i in range(n_processes)]
# 生成进程
processes = [process(target=process_data, args=(x,)) for x in sublists]
# 并行处理
for p in processes:
p.start()
for p in processes:
p.join()
其中if __name__ == ‘__main__’用来标明在import时不包含,但是作为文件执行时运行的语句块。为什么不用多线程呢?简单说就是python中线程的并发无法有效利用多核,如果有兴趣的读者可以从下面这个链接看起:
globalinterpreterlock – python wiki
os模块 深度学习中的数据多是文件,所以数据处理阶段和文件相关的操作就非常重要。除了文件io,python中一些操作系统的相关功能也能够非常方便地帮助数据处理。想象一下我们有一个文件夹叫做data,下边有3个子文件夹叫做cat,dog和bat,里面分别是猫,狗和蝙蝠的照片。为了训练一个三分类模型,我们先要生成一个文件,里面每一行是文件的路径和对应的标签。定义cat是0,dog是1,bat是2,则可以通过如下脚本:
import os
# 定义文件夹名称和标签的对应关系
label_map = {
'cat': 0,
'dog': 1,
'bat': 2
}
with open('data.txt', 'w') as f:
# 遍历所有文件,root为当前文件夹,dirs是所有子文件夹名,files是所有文件名
for root, dirs, files in os.walk('data'):
for filename in files:
filepath = os.sep.join([root, filename]) # 获得文件完整路径
dirname = root.split(os.sep)[-1] # 获取当前文件夹名称
label = label_map[dirname] # 得到标签
line = '{},{}\n'.format(filepath, label)
f.write(line)
其中,os.sep是当前操作系统的路径分隔符,在unix/linux中是’/’,windows中是’\\’。有的时候我们已经有了所有的文件在一个文件夹data下,希望获取所有文件的名称,则可以用os.listdir():
filenames = os.listdir('data')
os也提供了诸如拷贝,移动和修改文件名等操作。同时因为大部分深度学习框架最常见的都是在unix/linux下使用,并且unix/linux的shell已经非常强大(比windows好用太多),所以只需要用字符串格式化等方式生成shell命令的字符串,然后通过os.system()就能方便实现很多功能,有时比os,还有python中另一个操作系统相关模块shutil还要方便:
import os, shutil
filepath0 = 'data/bat/img_000001.jpg'
filepath1 = 'data/bat/img_000000.jpg'
# 修改文件名
os.system('mv {} {}'.format(filepath0, filepath1))
#os.rename(filepath0, filepath1)
# 创建文件夹
dirname = 'data_samples'
os.system('mkdir -p {}'.format(dirname))
#if not os.path.exists(dirname):
# os.mkdir(dirname)
# 拷贝文件
os.system('cp {} {}'.format(filepath1, dirname))
#shutil.copy(filepath1, dirname)

一文解析电路反馈框图
北航在纳米柔性器件先进制造方面取得重大进展
ST展示安全微控制器和射频存储器解决方案
台积电做出涨价决定的原因分析
长安欧尚X7 Geeker版:搭载车内外双摄人脸智控系统
Python基础教程
瑞萨科技北京后道工序厂完成扩建
微型机器人可以给我们带来什么好处
电磁操动安排的断路器操控回路
SiTime提供最小的MEMS振荡器,与Telit同掀超小型GPS接收器及导航革命
大唐电信拟筹资25亿元收购联芯科技等三公司
马云:企业家要有敬畏之心,AI区块链—你想要的,时代都会给你
亚马逊宣布再雇用10万名员工 并计划优先运送医疗用品和家庭必需品
动态内存分配优化了Blackfin处理器软件的集成
IC企业的成长基础是技术、是研发、是人才
详解proxy-stub结构的设计模式
科大讯飞正式推出新一代智能办公本X2
dfrobotMicro USB数据线简介
华为新的泄漏揭示了即将推出的智能手表的细节
GNSS模块供应商有哪些?