《Python核心编程》笔记
1 python是大小写敏感的
2 遍历一个字典的键值:
for a in dict_obj.keys(): print a
3 列表解析功能可以让代码很简洁,比如:
squared = [x ** 2 for i in range(0, 3)]
还可以加上筛选条件:
squared = [x ** 2 for i in range(0, 3) if not x % 2]
4 python的一些命名风格:
__xxx__:系统定义的名字
__xxx:类中的私有变量名
5 在python程序中,我们经常看到
if __name__ == '__main__'这样的语句,这条语句一般写为顶级执行代码,__name__是一个系统变量,当程序是被其它模块导入时,该值为模块名字,当直接执行该文件时该值为'__main__'
6 del语句能够直接释放资源
7 python的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器,循环垃圾收集器是指会尝试清理未引用的循环
8 使用局部变量替换模块变量,可以加快查找速度,因为省去了名字查询,举例:
ls = os.linesep
os.linesep返回的是当前系统的行终止符,比如linux系统的是'\n',windows系统的是'\r\n',Mac系统的是'\r'
如果每次都使用os.linesep则解释器需要先确认os是一个模块,然后从该模块中找linesep变量,取一个本地变量名,查找速度会快很多,所以如果频繁使用时可以使用本地变量来替换模块变量
9 Python提供了is和is not运算符来测试两个变量是否指向同一个对象
a is b 等价于 id(a) == id(b)
10 [::1]这是一种扩展切片操作,其第三个参数你可以看成是range函数的那个步长参数,比如
str = 'abcdefg'
则str[::2]就等于aceg
str[::-1]就等于gfedcba
11 在python中单引号和双引号括起来的字符串是没有区别的,不像其它脚本语言,在双引号还有些转义的东西,因为python对字符串的处理是当做一个标量,创建了后是不改变的,修改则是创建了一个新的字符串标量对象
12 for-else语句是指如果for循环中全部循环完了没有break则会执行else语句
所以这里有个巨坑:
for j in range(i+step, num_len, step): pass
以为当j不满足num_len时退出,以为j>=num_len,结果是如果j+step>=num_len就退出,j并没有加上step
解决方法可以:
for j in range(i+step, num_len, step): pass else: j += step
13 格式化字符串有两种,一种是元组作为参数类型的,类似于C模式的格式化输出,另外一种是字典作为参数的,分别示例如下:
'yy:%s %s' %('oo', 'ii')
'yy%(abc)s' %{'oo':77, 'abc':99}
字符串模板:它相当于定义了一个模板,传参套用即可,substitute还有个相似的成员函数:safe_substitute,区别是后者如果遇到key不存在时不是抛错,而是将模板字符串原封不动输出
from string import Template
s = Template('abc ${haha} abc')
print s.substitute(haha='99')
14 原始字符串操作符:r/R
用法是在字符串引号前加上小写r或大写R:比如r'\n'
也就是说它消除了转义符等,表达了真实要表达的字符
print '\n'会输出换行的空行
print r'\n'则是输出\n
r'\n'相当于字符串'\\n'
15 python的三引号可以用来包含多行字符的字符串,字符串中可以包含换行符、制表符等
16 列表可以使用大部分的对象和序列类型的操作符,此外,列表也有属于自己的方法,比如列表解析,在逻辑上描述要创建的列表的内容,举例:
>>> [i * 2 for i in [8, -2, 5]]
[16, -4, 10]
17 字符串排序使用的是字典序,而不是字母序,即比较ASCII码值,比如:
>>> s = ['aaa', 'TTT']
>>> print sorted(s)
['TTT', 'aaa']
因为'T'的ASCII码值比'a'的小
18 python中也是有数组模块的,array模块,不过一般可用list替代
19 检查一个字典中包含某个键可以用has_key方法或者用in和not in来检查,has_key方法在后面可能会被弃用
if uuu.has_key('ddd'): xxx if 'ddd' in uuu: xxx
20 字典的键必须是可哈希的,可以使用hash函数来判断键是否是可哈希的,如果是则返回哈希后的值,否则抛出异常
21 字典的keys()、values()和items()方法都是返回列表,iterkeys()、itervalues()和itemvalues()返回的是一个迭代器,所以当字典量大,要遍历时iter的这些方法优势就是节省内存。
for i in kk.keys(): print i for i in kk.iterkeys(): print i
结果是一样的
print kk.keys() print kk.iterkeys()
这两者则不同了,可自己打出来看下
22 python中有一个叫集合的数据结构,集合的元素必须是可哈希的,可使用set工厂方法来创建,创建不变的集合使用frozenset工厂方法
>>>s = set('ghj') >>>s set(['g', 'h', 'j'])
集合的特别是处就在于它跟数学中的集合概念很相似,同时提供了一些操作符很方便的操作集合,比如大于小于号用来判断子集关系,-用于补集,&用于交集,|用于并集,+号不是集合类型的运算符
23 类似C语言中的三元操作符:samller = x if x < y else y
24 python的zip函数,以可迭代对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。例:
>>>a = [1, 2, 3] >>>b = [4, 5, 6, 7] >>>zipped = zip(a, b) [(1, 4), (2, 5), (3, 6)]
利用*号操作符可将元组加压为列表
>>>zip(*zipped)
[(1, 2, 3), (4, 5, 6)]
25 迭代器从根本上来说是一个next()方法的对象,条目全部获取完成后会引发一个StopInteration异常来告诉外部调用者迭代完成了。
它的作用:
(1)带来访问性能上的提升
(2)可创建更简洁可读的代码
创建迭代器的方法:
iter(obj)可返回一个对象的迭代器,调用了该对象的__iter__方法和next方法
iter(func, sentinel);如果是传递了两个参数给iter函数,则它会重复的调用func,直到迭代器的下个值等于sentinel。
文件也是可迭代的python数据类型,文件对象生成的迭代器会自动调用readline方法,所以有:
for eachLine in myFile:
26 列表解析
解析语法:
[expr for iter_var in iterable]
eg:[x ** 2 for x in range(6)]
扩展版本的语法:
[expr for iter_var in iterable if cond_expr]
eg:[x for x in seq if x % 2]
列表解析支持多重嵌套for 循环以及多个 if 子句
eg:[(x+1,y+1) for x in range(3) for y in range(5)]
27 生成器表达式
生成器是特定的函数,允许你返回一个值,然后“暂停”代码的执行,稍后恢复。
为啥需要生成器表达式:列表解析的一个不足就是必要生成所有的数据, 用以创建整个列表. 这可能对有大量数据的迭
代器有负面效应. 生成器表达式通过结合列表解析和生成器解决了这个问题,是一个内存使用更友好的结构。
生成器表达式:(expr for iter_var in iterable if cond_expr)
举例:sum(len(word) for line in data for word in line.split())
28 可以从sys.argv对象中获取程序参数,类似于C语言中的argv参数,sys.argv[0]永远是程序的名称。
29 可使用pickle模块将对象进行序列化,包括用户自己定义的类,cPickle是pickle的一个更快的C语言编译版本。shelve则不仅提供了序列化功能还提供了对象的永久性存储功能。
30 异常处理
try xxx except Exception1, e: pass except Exception2, e: pass
如果两个异常类型使用同一种方法处理,则可以把异常类型一同放在元组里
try: xxx except (Exception1, Exception2), e: pass
BaseException是所有异常类的基类,KeyboardInterrupt和systemExit被从Exception中移出来,和Exception处于同级,其它的内建异常类都是以Exception为基类
try-except-else-finally
31 可以对一个实例进行__class__函数调用,可以显示出该实例属于哪个类
32 with
with context_expr [as var]:
with_suite
with语句仅能工作于支持上下文管理协议的对象,只有内建了"上下文管理"的对象可以和 with 一起工作。
下面列出一些支持该协议对象的第一批成员简短列表:
file
decimal.Context
thread.LockType
threading.Lock
threading.RLock
threading.Condition
threading.Semaphore
threading.BoundedSemaphore
以打开文件举例:
with open('/etc/passwd', 'r') as f: for eachLine in f: # ...do stuff with eachLine or f...
这里是with语句帮你打开文件和结束时自动关闭文件,实现原理:
上下文表达式(context_expr),上下文管理器
当with语句执行时便开始执行上下文符号(with和as之间的内容)来获得一个上下文管理器,上下文管理器用来提供一个上下文对象。这是通过调用__context__()方法来实现的,该方法返回一个上下文对象。获取上下文对象后会执行__enter__()方法来做with包含的语句块执行前的准备工作,如果有as声明变量,则该变量会被赋值为__enter__()方法返回的值。
无论with语句块正常执行结束还是异常结束,结束时都会先调用__exit__()方法,比如可以在该方法中关闭上下文对象,该方法会有三个参数,如果正常结束,则返回3个None,如果异常结束,等同于调用sys.exc_info()函数返回的三个值:类型(异常类)、值(异常实例)和回溯(traceback)。__exit__方法返回值是true or false决定了会往下执行with后的代码还是抛出异常给用户。
33 exc_info函数
是另一种获取异常信息的途径,返回一个元组,包含3个对象,分别是:
(1)exc_type:异常类
(2)exc_value:异常类的实例
(3)exc_traceback:追踪(traceback)对象
eg:
try: float('jjf') except: import sys exc_tuple = sys.exc_info() for each_item in exc_tuple: print each_item
34 装饰器
首先介绍一个装饰器实用的地方,比如定义一个类的静态方法,如果没有使用装饰器,需要在该方法的第一行加上staticFoo = staticmethod(staticFoo),显得臃肿,如果使用装饰器则只需要在方法的上面加上@staticmethod即可。
@deco2 @deco1 def func(arg1, arg2, ...): pass
等价于:
def func(arg1, arg2, ...): pass func = deco2(deco1(func))
先调用deco2,然后在deco2里调用deco1,最后deco1里调用func
上面说的是无参数的装饰器,下面说下有参数的装饰器:
@decomaker(deco_args) def foo(): pass
需要自己返回以函数foo作为参数的装饰器。换句话说,decomaker()用 deco_args 做了些事并返回
函数对象(装饰器返回的函数,不是foo),而该函数对象正是以 foo 作为其参数的装饰器。简单的说来:
foo = decomaker(deco_args)(foo)
所以有参数和无参数的装饰器结合起来就是:
@deco1(deco_arg) @deco2 def func(): pass
等价于:
func = deco1(deco_arg)(deco2(func))
举例(不带参数的):
#!/usr/bin/env python from time import ctime, sleep def tsfunc(func): def wrappedFunc(): print '[%s] %s() called' % (ctime(), func.__name__) return func() return wrappedFunc @tsfunc def foo(): print 'ok' foo() sleep(4) for i in range(2): sleep(1) foo()
输出:
[Sun Mar 10 01:29:36 2019] foo() called
ok
[Sun Mar 10 01:29:41 2019] foo() called
ok
[Sun Mar 10 01:29:42 2019] foo() called
ok
疑问地方:
(1)
def tsfunc(func): #def wrappedFunc(): # print '[%s] %s() called' % (ctime(), func.__name__) # return func() #return wrappedFunc print '[%s] %s() called' % (ctime(), func.__name__) return func
为什么需要闭包函数,为什么这样子进行调用只打了一次时间戳?
举例(带参数的):
def outer(outer_args): def middle(func): def wrapper(*args,**kwargs): print("before func") print("use args: "+outer_args) wrapper_result=func(*args,**kwargs) print("after func") return wrapper_result return wrapper return middle @outer("hello") def foo(a,b): return a+b
35 函数的参数
可以传递元组或者字典,*tuple_param,**dict_param
这里可以区分下非关键字参数和关键字参数,像b='1'这样的就叫做关键字参数,所以字典即是关键字参数;非关键字参数需要放到关键字参数之前
test(*tuple, **dict_param)
python是允许传递默认参数的,比如你经常会看到一个函数的定义的参数末尾是这样的,uuu='abc',但要注意所有的必要参数要放在默认参数的后面,为什么要这样规定呢,简单来说就是如果允许这样随意混杂,有些情况会有歧义的。
比如不允许这样:def test(a, b='1', c)
应该这样:def test(a, c, b='1')
对于函数的参数定义同样很灵活,可以通过元组和字典定义可变参数的函数:def function_name([formal_args,][*vargst,] **vargsd)
其实就是对于非关键字参数formal_args中没有的则会放到vargst元组里,对于关键字参数就放到vargsd中
36 匿名函数与 lambda
lambda [arg1[, arg2, ... argN]]: expression
eg:
>>> hh = lambda x, y=3: x+y >>> hh(5) 8 >>> hh(5, 9) 14 >>> type(hh) <type 'function'>
37 函数式编程的内建函数,apply,filter,map和reduce:
apply(func[, nkw][, kw]) :用可选的参数来调用func函数,该函数其实已被抛弃,因为现在的函数已经支持可选参数调用了。
eg:
apply(test, *tuple_param)
filter(func, seq):调用一个返回布尔值的函数func来迭代sql中的每个元素,如果是返回True的则插入到要返回的列表中
eg:
filter(test, [1, 4, 8])
比如test是对偶数进行删选的函数,则返回[4, 8]
map(func, seq1[,seq2...]):该函数跟filter函数有点像,不过func函数不一定是要布尔函数,它可以对序列里的每个元素进行处理并返回值,该值再插入到列表中,最后返回列表。
reduce(func, seq[, init]):func是一个二元函数,作用于seq序列的元素,每次携带一对(先前的结果以及下一个序列元素),这样一直计算到最后一个。
eg:
reduce(lambda x, y:x+y, [1, 2, 3])
算法实现是先拿出第一个,然后陆续从第2个开始。
>>> reduce(lambda x, y:x-5, [1, 3, 5])
-9
>>> reduce(lambda x, y:x-5, [1])
1
下面这个例子就可以看出来,先拿出1得到1,然后拿出3,得到-4,然后拿出5得到-9
38 使用global关键字可引用全局变量
ii = 3 def test(): global ii ii = 7 print ii
39 生成器
生成器是一个带 yield 语句的函数。一个函数或者子程序只返回一次,但一个生成器能暂停执行并返回一个中间的结果----那就是 yield 语句的功能, 返回一个值给调用者并暂停执行。当生成器的 next()方法被调用的时候,它会准确地从离开地方继续。
简单的生成器例子:
#!/usr/bin/env python def simpleGen(): yield 1 yield '2' gs = simpleGen() print gs.next() print gs.next() #print gs.next() # StopIteration for item in simpleGen(): print item
除了next方法,加强的生成器还有send和close方法,send方法用于向生成器传递值,比如下面例子的val,close方法用来关闭生成器,比如下面例子的最后一行就会报stopInteration异常
#!/usr/bin/env python def counter(start_at=0): count = start_at while True: val = (yield count) if val is not None: count = val else: count += 1 kk = counter(10) print kk.next() print kk.next() print kk.send(1) print kk.next() kk.close() print kk.next()
输出:
10
11
1
2
Traceback (most recent call last):
File "test_python.py", line 16, in <module>
print kk.next()
StopIteration
40 模块和命名空间相关
一个文件被看作是一个独立模块, 一个模块也可以被看作是一个文件。 模块的文件名就是模块的名字加上扩展名 .py。
sys.path可以看到当前的搜索路径,import的时候就是去这些路径下找文件模块的
如果想添加新得搜索路径,可以调用sys.path.append('xxx'),比如sys.path.append('/root/oo/')
sys.modules则可以看到当前导入的模块名称和对应的物理位置,是字典对象,key为模块名,value为物理位置,比如'kk': <module 'kk' from '/root/oo/kk.py'>
名称空间是名称(标识符)到对象的映射
在程序执行时会有3个名称空间:这三个名称空间分别是局部名称空间, 全局名称空间和内建名称空间
Python 解释器首先加载内建名称空间。 它由 __builtins__ 模块中的名字构成。 随后加载执行模块的全局名称空间, 它会在模块开始执行后变为活动名称空间,在函数调用时就会出现有局部名称空间。
通过 globals() 和 locals() 内建函数判断出某一名字属于哪个名称空间。
globals() 和 locals() 内建函数分别返回调用者全局和局部名称空间的字典。
举例:
#!/usr/bin/env python o = 8 def yy(): i = 9 print locals() print globals() print locals().keys() yy()
输出:
{'i': 9}
{'__builtins__': <module '__builtin__' (built-in)>, '__file__': 'test_python.py', 'o': 8, '__package__': None, 'yy': <function yy at 0x7fedd7c6e578>, '__name__': '__main__', '__doc__': None}
['i']
所以可以判断一个变量在当前名称空间是否存在,可以这样判断if 'xxx' in locals().keys()
当你得到一个函数实例或一个类实例时,相当于你创建了一个名称空间,你可以将想要的东西放入这个名称空间里,比如:
#!/usr/bin/env python def foo(): pass foo.__doc__ = 'Oops, forgot to add doc str above!' foo.version = 0.2 print foo.version class abc(): pass a = abc() a.uu = 9 print a.uu
模块导入的方式有好几种:
import xxx
from xx import xxx
from xx import xxx as x
加载模块会让该模块的顶层代码被执行。
41.包
包是一个有层次的文件目录结构, 它定义了一个由模块和子包组成的Python应用程序执行环境
每个包的目录都会有__init__.py文件,可以是空文件,有时在from-import导入子包时会用到它
导入有绝对导入和相对导入两种方式,绝对导入是默认的比较常用的方式,import只支持绝对导入,from-import支持相对导入
相对导入:语法的第一部分是一个句点, 指示一个相对的导入操作。 之后的其他附加句点代表当前from起始查找位置后的一个级别,可以相对导入看起来没有那么清晰
只要在你的 Python 模块头部加入一个额外的编码指示说明就可以让导入者使用指定的编码解析你的模块, 编码对应的 Unicode 字符串
比如utf-8编码:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
有时我们会遇到包的循环导入问题,比如A文件中import B,B中又也是import A,解决方法可以是如果某方只是想要某个函数用一些另外一个模块的,可以在那个函数里内部导入下,因为此时运行时就不会有互相导入导致循环问题,或者引入第三方,把要调用的集成到另外一个公共模块
42.类
初始化一个类实例时会调用类的__init__方法,你可以把它理解为类的构造方法
python的OOP面相对象编程中的常用术语:
(1)抽象/实现:抽象就是对现实问题的一种抽象建模,以程序的方式来描述现实;实现则是根据建好的模赋予真实数据并交互起来
(2)封装/接口:封装即是把具体实现隐藏起来,只需要提供相对应的调用接口即可,告诉用户只要这样调用接口就能实现相对应的功能
(3)合成:一个类里面可能引用了其它类,几个类联合起来解决实际的问题
(4)派生/继承:派生就是继承了一个父类后子类自己定义的方法实现,父类没有的,继承即是继承了父类的一些属性和方法
(5)泛化/特化:泛化是指子类、父类及其祖先都有的一个特定属性功能,比如各种人本质都是一个人,有追根溯源的味道,特化是指子类有其自己特定的某些功能,即虽然都是人,但是我有其它人不会的技能
(6)多态:多态的概念指出了对象如何通过他们共同的属性和动作来操作及访问,而不需考虑他们具体的类。最简单的实用例子就是我们可以根据不同的配置选择不同的driver类实现,然后调用对应类的方法,因为这些类都有这些方法,但实际调用哪个类,则要看driver是实例化了哪个子类。
(7)反射:这个性质展示了某对象是如何在运行期取得自身信息的。如果传一个对象给你,你可以查出它有什么能力,dir()和 type()内建函数即是用到了这种能力。
类的数据属性:数据属性仅仅是所定义的类的变量,我们成为静态变量,类似于C++中的在一个变量定义前加了个static
#!/usr/bin/env python class A(object): jk = 1 def update(self, value): self.jk = value # 并没有影响到类的属性jk,只是创建了个实例属性 print A.jk a = A() a.update(3) print A.jk print a.jk
输出:
1
1
3
在类属性可变的情况下,比如类属性是dict结构的,类实例可以改变掉类对象的属性值:
class A(object): jk = 1 kk = {'a': 1} a = A() a.jk = 2 a.kk['a'] = 2 print A.jk print A.kk
输出:
1
{'a': 2}
要知道类的属性可以有几种方法:
(1)通过调用内建函数dir()
(2)访问类的__dict__属性
(3)内建的vars()函数接受类对象作为参数,返回类的__dict__属性的内容
特殊类属性
A.__name__ 类A的名字(字符串)
A.__doc__ 类A的文档字符串
A.__bases__ 类A的所有父类构成的元组
A.__dict__ 类A的属性
A.__module__ 类A定义所在的模块(1.5 版本新增)
A.__class__ 实例A对应的类(仅新式类中)
显示调用父类方法:
class A(object): jk = 1 def __init__(self): print 'A class' class B(A): def __init__(self): print('B class') super(B, self).__init__() # 或者是:A.__init__(self) kb = B()
与__init__()相比,__new__()方法更像一个真正的构造器。__new__()必须返回一个合法的实例,这样解释器在调用__init__()时,就可以把这个实例作为 self 传给它
__del__() "解构器"方法
除非你知道你正在干什么,否则不要去实现__del__()
如果你定义了__del__,并且实例是某个循环的一部分,垃圾回收器将不会终止这个循环——你需要自已显式调用 del
类里面有staticmethod()和 classmethod()内建函数,可以将方法变为静态方法和类方法,现在一般用装饰器来实现静态方法和类方法的转换,静态方法我们比较熟悉,比较不熟悉的是类方法,类方法区别去静态方法的是它需要传递一个类对象参数,它的比较大的用处在于让我们尝试一种另类的构造函数。可看下面例子:
class Date(object): @classmethod def from_string(cls, date_as_string): day, month, year = map(date_as_string.split('-')) date1 = cls(day, month, year) return date1 date2 = Date.from_string('11-09-2012')
cls表示类对象,而不是类实例
相当于我们调用了类方法from_string来构造一个类实例并返回
其实重写覆盖__new__方法也一样实现这个功能
class RoundFloat(float): def __new__(cls, val): return float.__new__(cls, round(val, 2)) #或者return super(RoundFloat, cls).__new__(cls, round(val, 2))
注意python的类的方法是不支持重载特性的,但可覆盖方法,也就是说不能像C++那样,参数多少都可以被重载为两个不同的方法
isinstance函数可以用来判断一个对象是否属于某个给定的类的实例:
i = 8 if isinstance(i, int): print 'yes' else: print 'no'
类属性的一些常用方法:
hasattr():返回值示Boolean型的,查询是否有该属性;
getattr():获取某个属性的值,如果没有会引发AttributeError异常,除非有给默认参数;
setattr():设置属性
delattr():删除属性
重写一些方法可以定制类的特殊方法,这些特殊方法都是__开头的:
__cmp__(self, obj) 对象比较;内建 cmp()
还有很多大于小于加减乘除等
43 网络编程相关
套接字有两种,分别是基于文件型的和基于网络型的,分别是AF_UNIX(AF_LOCAL)和AF_INET
python还支持一种套接字AF_NETLINK,AF_NETLINK套接字家族让用户代码与内核代码之间的IPC可以使用标准BSD套接字接口。
无论是哪种类型的套接字,都分为两种类型套接字,面向连接和无连接套接字。
面向连接套接字通讯前要先建立一条连接,这种通讯方式提供了顺序的、可靠的、不会重复的数据传输,而且也不会被加上数据边界。实现这种连接的主要协议就是传输控制协议(TCP),套接字类型对应为SOCK_STREAM。这些套接字使用Internet协议(IP协议)来查找主机,所以联合起来是TCP/IP。
无连接套接字与面向连接相反,发送数据前不用先建立连接,但这也意味着数据不一定保证送到,且发送数据顺序和数据包重复无法得到保证,但这样的好处是性能好,在某些场景下有用。
实现这种连接的主要协议是数据报协议(UDP),套接字类型为SOCK_DGRAM,UDP/IP。
使用socket.socket()函数来创建套接字
socket(socket_family, socket_type, protocol=0)
socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。
套接字对象的常用函数:
服务器端套接字函数
s.bind() 绑定地址(主机,端口号对)到套接字
s.listen() 开始 TCP 监听
s.accept() 被动接受 TCP 客户的连接,(阻塞式)等待连接的到来
客户端套接字函数
s.connect() 主动初始化 TCP 服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛异常
公共用途的套接字函数
s.recv() 接收 TCP 数据
s.send() 发送 TCP 数据
s.sendall() 完整发送 TCP 数据
s.recvfrom() 接收 UDP 数据
s.sendto() 发送 UDP 数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
Blocking-Oriented Socket Methods
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间
面向文件的套接字的函数
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字关连的文件
一个简单的socket服务器例子:
#!/usr/bin/env python from socket import * from time import ctime HOST = '' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) tcpSerSock = socket(AF_INET, SOCK_STREAM) tcpSerSock.bind(ADDR) tcpSerSock.listen(5) while True: print 'waiting for connection...' tcpCliSock, addr = tcpSerSock.accept() print '...connected from:', addr try: while True: data = tcpCliSock.recv(BUFSIZ) if not data: break tcpCliSock.send('[%s] %s' % (ctime(), data)) except Exception, e: print e tcpCliSock.close() tcpSerSock.close()
一个简单的客户端例子:
#!/usr/bin/env python from socket import * HOST = 'localhost' PORT = 21567 BUFSIZ = 1024 ADDR = (HOST, PORT) tcpCliSock = socket(AF_INET, SOCK_STREAM) tcpCliSock.connect(ADDR) while True: data = raw_input('> ') if not data: break tcpCliSock.send(data) data = tcpCliSock.recv(BUFSIZ) if not data: break print data tcpCliSock.close()
SocketServer模块:
#!/usr/bin/env python from SocketServer import (TCPServer as TCP, StreamRequestHandler as SRH) from time import ctime HOST = '' PORT = 21567 ADDR = (HOST, PORT) class MyRequestHandler(SRH): def handle(self): print '...connected from:', self.client_address self.wfile.write('[%s] %s' % (ctime(), self.rfile.readline())) # self.request.send('[%s] %s' % (ctime(), self.request.recv(1024))) tcpServ = TCP(ADDR, MyRequestHandler) print 'waiting for connection...' tcpServ.serve_forever()