Python 基础回顾(三)
来源:互联网 发布:基金仓位测算数据 编辑:程序博客网 时间:2024/05/29 04:01
求 1到 1000 的
1. 总和 sum([x for x in range(1,1001)])
2. 乘积 my_chengji([x for in range(1, 1001)])
list
str
len
文件IO
读写文件是最常见的IO操作。Python内置了读写文件的函数,用法和C是兼容的。
读写文件前,我们先必须了解一下,在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。
文件 IO
Python打开一个文件对象,使用open()函数,传入文件名和标示符:
f = open(‘./test.txt’, ‘r’)
标示符’r’表示读,这样,我们就成功地打开了一个文件。
如果文件不存在,open()函数就会抛出一个IOError的错误,并且给出错误码和详细的信息告诉你文件不存在:
f=open(‘./test.txt’, ‘r’)
Traceback (most recent call last):
File “”, line 1, in
IOError: [Errno 2] No such file or directory: ‘./test.txt’
如果文件打开成功,接下来,调用read()方法可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示:
f.read()
‘Hello, world!’
最后一步是调用close()方法关闭文件。文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的:
f.close()
lsof 这个命令要熟悉一下,利器
strace
由于文件读写时都有可能产生IOError,一旦出错,后面的f.close()就不会调用。所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用try … finally来实现:
try:
f = open(‘/path/to/file’, ‘r’)
print f.read()
finally:
if f:
f.close()
但是每次都这么写实在太繁琐,所以,Python引入了with语句来自动帮我们调用close()方法:
with open(‘/path/to/file’, ‘r’) as f:
print f.read()
这和前面的try … finally是一样的,但是代码更佳简洁,并且不必调用f.close()方法。
调用read()会一次性读取文件的全部内容,如果文件有10G,内存就爆了,所以,要保险起见,可以反复调用read(size)方法,每次最多读取size个字节的内容。另外,调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list。因此,要根据需要决定怎么调用。
如果文件很小,read()一次性读取最方便;如果不能确定文件大小,反复调用read(size)比较保险;如果是配置文件,调用readlines()最方便:
for line in f.readlines():
print(line.strip()) # 把末尾的’\n’删掉
file-like Object
像open()函数返回的这种有个read()方法的对象,在Python中统称为file-like Object。除了file外,还可以是内存的字节流,网络流,自定义流等等。file-like Object不要求从特定类继承,只要写个read()方法就行。
StringIO就是在内存中创建的file-like Object,常用作临时缓冲。
字符编码
要读取非ASCII编码的文本文件,就必须以二进制模式打开,再解码。比如gbk、utf8编码的文件:
f = open(‘/root/dir/gbk.txt’, ‘rb’)
u = f.read().decode(‘gbk’)
u
u’\u6d4b\u8bd5’
print u
测试
如果每次都这么手动转换编码嫌麻烦(写程序怕麻烦是好事,不怕麻烦就会写出又长又难懂又没法维护的代码),Python还提供了一个codecs模块帮我们在读文件时自动转换编码,直接读出unicode:
import codecs
with codecs.open(‘/root/dir/gbk.txt’, ‘r’, ‘gbk’) as f:
f.read() # u’\u6d4b\u8bd5’
写文件
写文件和读文件是一样的,唯一区别是调用open()函数时,传入标识符’w’或者’wb’表示写文本文件或写二进制文件:
f = open(‘/root/dir/test.txt’, ‘w’)
f.write(‘Hello, world!’)
f.close()
你可以反复调用write()来写入文件,但是务必要调用f.close()来关闭文件。当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。所以,还是用with语句来得保险:
with open(‘/root/dir/test.txt’, ‘w’) as f:
f.write(‘Hello, world!’)
要写入特定编码的文本文件,请效仿codecs的示例,写入unicode,由codecs自动转换成指定编码。
在Python中,文件读写是通过open()函数打开的文件对象完成的。
文件和目录
如果我们要操作文件、目录,可以在命令行下面输入操作系统提供的各种命令来完成。比如ls、cp等命令。
如果要在Python程序中执行这些目录和文件的操作怎么办?其实操作系统提供的命令只是简单地调用了操作系统提供的接口函数,Python内置的os模块也可以直接调用操作系统提供的接口函数。
打开Python交互式命令行,我们来看看如何使用os模块的基本功能:
import os
os.name # 操作系统名字
‘posix’
如果是posix,说明系统是Linux、Unix或Mac OS X,如果是nt,就是Windows系统。
要获取详细的系统信息,可以调用uname()函数:
os.uname()
(‘Linux’,
‘iZ253ir7gzgZ’,
‘3.13.0-32-generic’,
‘#57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014’,
‘x86_64’)
注意uname()函数在Windows上不提供,也就是说,os模块的某些函数是跟操作系统相关的。
环境变量
在操作系统中定义的环境变量,全部保存在os.environ这个dict中,可以直接查看:
os.environ
{‘LANG’: ‘en_US.UTF-8’, ‘TERM’: ‘xterm’, ‘SHELL’: ‘/bin/bash’, ‘LESSCLOSE’: ‘/usr/bin/lesspipe %s %s’, ‘XDG_RUNTIME_DIR’: ‘/run/user/0’, ‘LANGUAGE’: ‘en_US:’, ‘SHLVL’: ‘1’, ‘SSH_TTY’: ‘/dev/pts/1’, ‘HOME’: ‘/root’, ‘PWD’: ‘/root’, ‘LESSOPEN’: ‘| /usr/bin/lesspipe %s’, ‘SSH_CLIENT’: ‘111.199.189.226 23262 22’, ‘LOGNAME’: ‘root’, ‘USER’: ‘root’, ‘PATH’: ‘/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games’, …}
要获取某个环境变量的值,可以调用os.getenv()函数:
os.getenv(‘PATH’)
‘/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/mysql/bin’
操作文件和目录
操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中,这一点要注意一下。查看、创建和删除目录可以这么调用:
查看当前目录的绝对路径:
os.path.abspath(‘.’)
‘/root’
在某个目录下创建一个新目录,
首先把新目录的完整路径表示出来:
os.path.join(‘/root ‘, ‘testdir’)
‘/root/testdir’
然后创建一个目录:
os.mkdir(‘/root/testdir’)
删掉一个目录:
os.rmdir(‘/root/testdir’)
把两个路径合成一个时,不要直接拼字符串,而要通过os.path.join()函数,这样可以正确处理不同操作系统的路径分隔符。在Linux/Unix/Mac下,os.path.join()返回这样的字符串:
part-1/part-2
而Windows下会返回这样的字符串:
part-1\part-2
同样的道理,要拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数,这样可以把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名:
os.path.split(‘/root/testdir/file.txt’)
(‘/root/testdir’, ‘file.txt’)
os.path.splitext()可以直接让你得到文件扩展名,很多时候非常方便:
os.path.splitext(‘/path/to/file.txt’)
(‘/path/to/file’, ‘.txt’)
这些合并、拆分路径的函数并不要求目录和文件要真实存在,它们只对字符串进行操作。
文件操作使用下面的函数。假定当前目录下有一个test.txt文件:
对文件重命名:
os.rename(‘test.txt’, ‘test.py’)
删掉文件:
os.remove(‘test.py’)
但是复制文件的函数居然在os模块中不存在!原因是复制文件并非由操作系统提供的系统调用。幸运的是shutil模块提供了copyfile()的函数,你还可以在shutil模块中找到很多实用函数,它们可以看做是os模块的补充。
最后看看如何利用Python的特性来过滤文件。比如我们要列出当前目录下的所有目录,只需要一行代码:
[x for x in os.listdir(‘.’) if os.path.isdir(x)]
[‘.lein’, ‘.local’, ‘.m2’, ‘.npm’, ‘.ssh’, ‘.Trash’, ‘.vim’, ‘Adlm’, ‘Applications’, ‘Desktop’, …]
要列出所有的.py文件,也只需一行代码:
[x for x in os.listdir(‘.’) if os.path.isfile(x) and os.path.splitext(x)[1]==’.py’]
[‘apis.py’, ‘config.py’, ‘models.py’, ‘pymonitor.py’, ‘test_db.py’, ‘urls.py’, ‘wsgiapp.py’]
是不是非常简洁?
小结
Python的os模块封装了操作系统的目录和文件操作,要注意这些函数有的在os模块中,有的在os.path模块中。
练习2:编写一个search(s)的函数,能在当前目录以及当前目录的所有子目录下查找文件名包含指定字符串的文件,并打印出完整路径:
函数
Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
我们以自定义一个求绝对值的myabs函数为例:
def myabs(x,y,z):
if x >= 0: return xelse: return -x
aa = myabs(3)
myabs(-3)
调用myabs看看返回结果是否正确。
请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。
如果没有return语句,函数执行完毕后也会返回结果,只是结果为None。
return None可以简写为return。
空函数
如果想定义一个什么事也不做的空函数,可以用pass语句:
def nothing():
pass
pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
pass还可以用在其他语句里,比如:
if age >= 20:
pass
缺少了pass,代码运行就会有语法错误。
参数检查
调用函数时,如果参数个数不对,Python解释器会自动检查出来,并抛出TypeError:
myabs(1, 2)
Traceback (most recent call last):
File “”, line 1, in
TypeError: myabs() takes exactly 1 argument (2 given)
但是如果参数类型不对,Python解释器就无法帮我们检查。试试myabs和内置函数abs的差别:
myabs(‘a’)
‘a’
abs(‘a’)
Traceback (most recent call last):
File “”, line 1, in
TypeError: bad operand type for abs(): ‘str’
当传入了不恰当的参数时,内置函数abs会检查出参数错误,而我们定义的myabs没有参数检查,所以,这个函数定义不够完善。
让我们修改一下myabs的定义,对参数类型做检查,只允许整数和浮点数类型的参数。数据类型检查可以用内置函数isinstance实现:
def myabs(x):
if not isinstance(x, (int, float)):
raise TypeError(‘bad operand type’)
if x >= 0:
return x
else:
return -x
添加了参数检查后,如果传入错误的参数类型,函数就可以抛出一个错误:
myabs(‘A’)
Traceback (most recent call last // 最近的一次调用在最后):
File “”, line 1, in
File “”, line 3, in my_abs
TypeError: bad operand type
错误和异常处理将在后续讲到。
返回多个值
函数可以返回多个值吗?答案是肯定的。
def point(x, y):
nx = 10 * x
ny = 20 * y
return nx, ny return [nx,ny]
这样我们就可以同时获得返回值:
x, y = point(1, 1)
print x, y
10,20
但其实这只是一种假象,Python函数返回的仍然是单一值:
r = move(1, 1)
print r
(10,20)
原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同时接收一个tuple,按位置赋给对应的值,所以,Python的函数返回多值其实就是返回一个tuple,但写起来更方便。
小结
定义函数时,需要确定函数名和参数个数;先对参数的数据类型做检查;
函数体内部可以用return随时返回函数结果;没有return语句时,自动return None。
函数可以同时返回多个值,但其实就是一个tuple。
函数的参数
Python的函数除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。
默认参数
先写一个计算x2的函数:
def power(x):
return x * x
当我们调用power函数时,必须传入有且仅有的一个参数x:
power(5)
25
power(8)
64
现在,如果我们要计算x3怎么办?可以再定义一个power3函数,但是如果要计算x4、x5……怎么办?我们不可能定义无限多个函数。
你也许想到了,可以把power(x)修改为power(x, n),用来计算xn,说干就干:
def power(x, n):
return x ** n
s = 1
while n > 0:
n = n - 1
s = s * x
return s
对于这个修改后的power函数,可以计算任意n次方:
power(5, 2)
25
power(5, 3)
125
但是,旧的调用代码失败了,原因是我们增加了一个参数,导致旧的代码无法正常调用:
power(5)
Traceback (most recent call last):
File “”, line 1, in
TypeError: power() takes exactly 2 arguments (1 given)
这个时候,默认参数就排上用场了。由于我们经常计算x2,所以,完全可以把第二个参数n的默认值设定为2:
def power(x, n=2):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
这样,当我们调用power(5)时,相当于调用power(5, 2):
power(5)
25
power(5, 2)
25
而对于n > 2的其他情况,就必须明确地传入n,比如power(5, 3)。
设置默认参数时,有几点要注意:
一是必选参数在前,默认参数在后,否则Python的解释器会报错(思考一下为什么默认参数不能放在必选参数前面);
二是如何设置默认参数。
当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。
使用默认参数有什么好处?最大的好处是能降低调用函数的难度。但是一般不太建议这么做!!!!
默认参数很有用,但默认参数有个最大的坑,演示如下:
先定义一个函数,传入一个list,添加一个’a’再返回:
def add_end(L=[]): add_end(‘a’) add_end([‘a’])
L.append(‘a’)
return L
当你正常调用时,结果似乎不错:
add_end([1, 2, 3])
[1, 2, 3, ‘END’]
add_end([‘x’, ‘y’, ‘z’])
[‘x’, ‘y’, ‘z’, ‘END’]
当你使用默认参数调用时,一开始结果也是对的:
add_end() add_end([])
[‘END’]
但是,再次调用add_end()时,结果就不对了:
add_end()
[‘END’, ‘END’]
add_end()
[‘END’, ‘END’, ‘END’]
很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了’END’后的list。
原因解释如下:
Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。
所以,定义默认参数要牢记一点:默认参数必须指向不变对象!
要修改上面的例子,我们可以用None这个不变对象来实现:
def add_end(L=None):
if L is None:
L = []
L.append(‘END’)
return L
现在,无论调用多少次,都不会有问题:
add_end()
[‘END’]
add_end()
[‘END’]
为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。
可变参数
在Python函数中,还可以定义可变参数。就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。
我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。
要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下:
def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
但是调用的时候,需要先组装出一个list或tuple:
calc([1, 2, 3])
14
calc((1, 3, 5, 7))
84
如果利用可变参数,调用函数的方式可以简化成这样:
calc(1, 2, 3)
14
calc(1, 3, 5, 7)
84
所以,我们把函数的参数改为可变参数:
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
定义可变参数和定义list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:
calc(1, 2)
5
calc()
0
如果已经有一个list或者tuple,要调用一个可变参数怎么办?可以这样做:
nums = [1, 2, 3]
calc(nums[0], nums[1], nums[2])
14
这种写法当然是可行的,问题是太繁琐,所以Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:
numbers = [1, 2, 3]
calc(*numbers)
14
这种写法相当有用,而且很常见。
关键字参数
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。请看示例:
def person(name, age, **kw):
print ‘name:’, name, ‘age:’, age, ‘other:’, kw
函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数:
person(‘tom’, 30)
name: tom age: 30 other: {}
也可以传入任意个数的关键字参数:
person(‘jerry’, 35, city=’Beijing’)
name: jerry age: 35 other: {‘city’: ‘Beijing’}
person(‘july’, 45, gender=’M’, job=’Engineer’)
name: july age: 45 other: {‘gender’: ‘M’, ‘job’: ‘Engineer’}
关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。
和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:
kw = {‘city’: ‘Beijing’, ‘job’: ‘Engineer’}
person(‘Jack’, 24, city=kw[‘city’], job=kw[‘job’])
name: Jack age: 24 other: {‘city’: ‘Beijing’, ‘job’: ‘Engineer’}
当然,上面复杂的调用可以用简化的写法:
kw = {‘city’: ‘Beijing’, ‘job’: ‘Engineer’}
person(‘Jack’, 24, **kw)
name: Jack age: 24 other: {‘city’: ‘Beijing’, ‘job’: ‘Engineer’}
参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。
比如定义一个函数,包含上述4种参数:
def func(a, b, c=0, *args, **kw):
print ‘a =’, a, ‘b =’, b, ‘c =’, c, ‘args =’, args, ‘kw =’, kw
在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。
func(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
func(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
func(1, 2, 3, ‘a’, ‘b’)
a = 1 b = 2 c = 3 args = (‘a’, ‘b’) kw = {}
func(1, 2, 3, ‘a’, ‘b’, x=99)
a = 1 b = 2 c = 3 args = (‘a’, ‘b’) kw = {‘x’: 99}
最神奇的是通过一个tuple和dict,你也可以调用该函数:
args = (1, 2, 3, 4)
kw = {‘x’: 99}
func(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {‘x’: 99}
所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。
小结
Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。默认参数一定要用不可变对象,如果是可变对象,运行会有逻辑错误!要注意定义可变参数和关键字参数的语法:
*args是可变参数,args接收的是一个tuple;
**kw是关键字参数,kw接收的是一个dict。
练习3. 熟悉函数相关的内容
变量可以指向函数
以Python内置的求绝对值的函数abs()为例,调用该函数用以下代码:
abs(-5)
5
但是,如果只写abs呢?
abs
/
可见,abs(-5)是函数调用,而abs是函数本身。
要获得函数调用结果,我们可以把结果赋值给变量:
x = abs(-5)
x
5
但是,如果把函数本身赋值给变量呢?
f = abs
f
结论:函数本身也可以赋值给变量,即:变量可以指向函数。
如果一个变量指向了一个函数,那么,可否通过该变量来调用这个函数?用代码验证一下:
f = abs
f(-5)
5
函数名也是变量
那么函数名是什么呢?函数名其实就是指向函数的变量!对于abs()这个函数,完全可以把函数名abs看成变量,它指向一个可以计算绝对值的函数!
如果把abs指向其他对象,会有什么情况发生?
abs = 1
abs(-1)
Traceback (most recent call last):
File “”, line 1, in
TypeError: ‘int’ object is not callable
把abs指向10后,就无法通过abs(-10)调用该函数了!因为abs这个变量已经不指向求绝对值函数了!
传入函数
既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
一个最简单的高阶函数:
def linear(a, b):
def result(x):
return a*x + b
return result
当我们调用linear(2, 3)时,参数a,b分别接收2,3,根据函数定义,我们可以推导计算过程为:
a ==> 2
b ==> 3
return-> 2*x + 3
用代码验证一下:
linear(2,3)(4)
11def foo(a,b,bar):
return bar(a,b)
def bar(x,y):
return x+y
foo(2,3,bar)
5
高阶函数,就是让函数的参数能够接收别的函数。
匿名函数lambda
当我们在传入函数时,以map()函数为例,计算f(x)=x2时,除了定义一个f(x)的函数外,还可以直接传入匿名函数:
map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]
通过对比可以看出,匿名函数lambda x: x * x实际上就是:
def f(x):
return x * x
关键字lambda表示匿名函数,冒号前面的x表示函数参数。
匿名函数有个限制,就是只能有一个表达式,不用写return,返回值就是该表达式的结果。
用匿名函数有个好处,因为函数没有名字,不必担心函数名冲突。此外,匿名函数也是一个函数对象,也可以把匿名函数赋值给一个变量,再利用变量来调用该函数:
f = lambda x: x * x
f
- Python 基础回顾(三)
- python---基础回顾(爬虫)
- Python 基础回顾(二)
- Python 基础回顾(四)
- Python 基础回顾(五)
- Python 基础回顾(七)
- Python 基础回顾(八)
- python 基础(三)一些要点回顾和字典 (和一些重点)
- OC基础回顾(三)继承
- Java基础回顾(三)
- python基础回顾笔记
- python基础回顾
- Python 基础回顾(六)
- Python 字典基础回顾
- Python基础操作回顾
- android基础回顾(三)基础UI组件
- Python 基础(三)
- Python基础(三)
- ProxySQL--灵活强大的MySQL代理层
- Oracle进阶之你可能会用到的命令(一)
- LAMP环境安装
- 几条汇编指令
- 2016-09-25
- Python 基础回顾(三)
- 遇到问题---java--hibernate多线程中使用getCurrentSession报错innerSetException
- 递归枚举,子集生成,排列生成,回溯都是解决解答树的方法,通过数值跟踪保存排序过程
- UGUI研究院之Text文本渐变
- Java synchronized 理解
- 地址加法器合成物理地址
- 段的概念
- 段寄存器
- 关于SQL的连接查询