类高级方法、反射、异常、动态导入模块

1. 静态方法

class Animal(object):
    def __init__(self,name):
        self.name = name
        
    @staticmethod     #静态方法的调用方式
    def eat(self,food):
        print('% is eating %s' % (self.name,food))
d = Animal('zhang')
d.eat('hanb')


#直接按上面写然后执行,会报错:TypeError: eat() missing 1 required positional argument: 'food'。说是缺少一个food参数,可是我们不是传了一个food参数hanb嘛,我们稍后再说,看下面代码。


class Animal(object):
    def __init__(self,name):
        self.name = name
        
    @staticmethod
    def eat(food):
        print('%s is eating %s' % ('zhangshanci',food))
d = Animal('zhang')
d.eat('hanb')

#不给eat方法传self了,直接传一个food,代码运行结果:zhangshanci is eating hanb
#这次就没错了,但是类里面的每个方法不是都要传一个self参数嘛,为什么eat不传也不报错呢,接下来看下面的代码,不给eat传任何参数了,


class Animal(object):
    def __init__(self,name):
        self.name = name
        
    @staticmethod
    def eat():
        print('%s is eating %s' % ('zhangshanci','hanb'))
d = Animal('zhang')
d.eat()

#运行结果是:zhangshanci is eating hanb,也没有报错。


#通过上面的例子,我们总结出来,静态方法其实跟类没有半毛钱关系,它只是通过类的实例来调用而已,类的self、类的属性、类的任何任何都不会传给静态方法使用,所以上面的eat(self,food),需要这样用:eat('zhangshanci','chifan'),手动传给它两个参数,因为eat里的self参数并不是类的对象,而是一个普普通通需要传入的参数而已。


#那么静态方法如何使用类的属性呢,看如下代码:
class Animal(object):
    def __init__(self,name):
        self.name = name
        
    @staticmethod
    def eat(self):
        print('%s is eating %s' % (self.name,'hanb'))
d = Animal('zhang')
d.eat(d)

#把类的对象传入eat方法作为一个参数,然后再调用。这样其实没啥卵用,实际工作中好像也没有用到的地方,不过要知道这个方法,遇到了能看懂。

2.类方法

class Animal(object):
    def __init__(self,name):
        self.name = name
    @classmethod
    def eat(self):
        print('%s is eating %s' % (self.name,'hanb'))
d = Animal('zhang')
d.eat()

#上面的代码报错如下:
#print('%s is eating %s' % (self.name,'hanb'))
#AttributeError: type object 'Animal' has no attribute 'name'。说是Animal这个类没有name属性,但是构造方法里明明有啊,我们接着看下面的代码。

class Animal(object):
    name = 'zhangshanci'     #加了一个类变量
    def __init__(self,name):
        self.name = name
    @classmethod
    def eat(self):
        print('%s is eating %s' % (self.name,'hanb'))
d = Animal('zhang')
d.eat()

#结果如下:
#zhangshanci is eating hanb

#由此可见,类方法只能调用类变量。实际工作中也几乎用不到,知道有这个就行了。

3.属性方法

#我们还是一点点来,通过用多个例子的结果慢慢引入属性方法的特点、使用

class Animal(object):
    def __init__(self,name):
        self.name = name
    @property     #定义属性方法的装饰器
    def eat(self):
        print('%s is eating %s' % (self.name,'hanb'))
d = Animal('zhang')
d.eat()

#上面的代码报错:d.eat()
#TypeError: 'NoneType' object is not callable。说这个eat()方法不能被调用,这是为啥呢,上面的类里都定义了啊,那我们尝试把括号去掉,如下,

class Animal(object):
    def __init__(self,name):
        self.name = name
    @property
    def eat(self):
        print('%s is eating %s' % (self.name,'hanb'))
d = Animal('zhang')
d.eat     #调用时去掉了括号

#结果:zhang is eating hanb。可见,属性方法的调用方式是把方法像属性那样调用,属性方法就是把一个方法变成一个属性了,不用加括号直接可调用;
#那能不能给属性方法传参数呢?就上面的代码来看是不可以的,因为嫁入eat(self,food)这样定义,那调用时这样写d.eat('chirou')和这样写d.eat都会报错缺少一个参数。
#那怎么解决呢?既然属性方法是把方法变成了一个属性,属性可以赋值,所以我们利用给属性赋值的方法来把参数传进去,看下面代码,

class Animal(object):
    def __init__(self,name):
        self.name = name
    @property
    def eat(self):
        print('%s is eating %s' % (self.name,'baozi'))
d = Animal('zhang')
d.eat
d.eat = 'junzi'

#直接给属性方法赋值是会报错的:    d.eat = 'junzi'
#AttributeError: can't set attribute,提示不能设置这个属性,需要特殊处理才能赋值,接着往下看,


class Animal(object):
    def __init__(self,name):
        self.name = name
    @property    #定义属性方法
    def eat(self):
        print('%s is eating %s' % (self.name,'baozi'))
    @eat.setter    #给属性方法赋值
    def eat(self,food):
        print('eat set food:',food)
d = Animal('zhang')
d.eat
d.eat = 'junzi'

#结果:
#zhang is eating baozi
#eat set food: junzi
#可见,直接调用属性方法,它会执行@property下面的方法;给属性方法赋值,会执行@eat.setter下面的方法;他俩的方法名必须是一样的,这样就起到了给属性方法传参数的效果。(d.eat = 'juanzi' 就好像是 d.eat('jaunzi'))

下面的代码依然是给属性方法传参,更接近实际使用,如下,
class Animal(object):
    def __init__(self,name):
        self.name = name
        self.__food = None
    @property
    def eat(self):
        print('%s is eating %s' % (self.name,self.__food))
    @eat.setter
    def eat(self,food):
        self.__food = food
d = Animal('zhang')
d.eat = 'junzi'     #先给属性赋值(也就是变相的传参)
d.eat    #再调用属性

#结果:
#zhang is eating junzi  #本来self.__food是None,经过d.eat='juanzi'后,d.eat再执行时self.__food就变成了juanzi。



接下来的问题是,既然属性方法是一个属性,那怎么删除呢?我们还是直接删除看看,
class Animal(object):
    def __init__(self,name):
        self.name = name
        self.__food = None
    @property
    def eat(self):
        print('%s is eating %s' % (self.name,self.__food))
    @eat.setter
    def eat(self,food):
        self.__food = food
d = Animal('zhang')
d.eat
d.eat = 'junzi'
d.eat
del d.eat    #尝试删除这个属性
#结果报错:del d.eat
#AttributeError: can't delete attribute,提示不能删除这个属性,跟设置属性值一样,我们需要稍微处理一下,代码如下,

class Animal(object):
    def __init__(self,name):
        self.name = name
        self.__food = None
    @property
    def eat(self):
        print('%s is eating %s' % (self.name,self.__food))
    @eat.setter
    def eat(self,food):
        self.__food = food
    @eat.deleter   #删除属性方法的装饰器
    def eat(self):
        del self.__food
        print('delete self.__food')
d = Animal('zhang')
d.eat
d.eat = 'junzi'
d.eat
del d.eat     #删除属性d.eat
d.eat

#结果:
#zhang is eating None
#zhang is eating junzi
#delete self.__food
#   print('%s is eating %s' % (self.name,self.__food))
#AttributeError: 'Animal' object has no attribute '_Animal__food',提示Animal这个类对象没有__food变量,这是因为执行del d.eat时调用了eat@deleter下面的方法,方法里有个del self.__food,既然删了自然就找不到了。

#总结:直接调用属性方法,会调用@property下面的方法;给属性方法赋值,会调用@func_name.setter下面的方法;删除属性方法,会调用@func.deleter下面的方法;至于各个方法里写什么就比较灵活了,写什么执行什么。

好吧,把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:

1. 连接航空公司API查询

2. 对查询结果进行解析 

3. 返回结果给你的用户

因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以,明白 了么?实例代码如下,

 

class Flight(object):
    def __init__(self,name):
        self.flight_name = name


    def checking_status(self):
        print("checking flight %s status " % self.flight_name)
        return  1


    @property
    def flight_status(self):
        status = self.checking_status()
        if status == 0 :
            print("flight got canceled...")
        elif status == 1 :
            print("flight is arrived...")
        elif status == 2:
            print("flight has departured already...")
        else:
            print("cannot confirm the flight status...,please check later")
   
    @flight_status.setter #修改
    def flight_status(self,status):
        status_dic = {
            0 : "canceled",
            1 :"arrived",
            2 : "departured"
        }
        print("\033[31;1mHas changed the flight status to \033[0m",status_dic.get(status) )

    @flight_status.deleter  #删除
    def flight_status(self):
        print("status got removed...")

f = Flight("CA980")
f.flight_status
f.flight_status =  2 #触发@flight_status.setter 
del f.flight_status #触发@flight_status.deleter 

5.类的特殊成员方法

1. __doc__  打印类的描述信息,类的描述信息一般写在类名的下一行。

class Foo:
    """ 描述类信息,这是用于看片的神奇 """
 
    def func(self):
        pass
 
print Foo.__doc__
#输出:类的描述信息

2. __module__ 和  __class__ 

__module__ 显示当前操作的对象在哪个模块

__class__     显示当前操作的对象的是哪个类

在lib下建一个aa模块,内容如下:

class C(object):
def __init__(self):
self.name = 'zsc'

然后在lib的同级目录建立一个index模块,把aa模块的类C导入到index,如下图,

可见,__module__打印出了这个对象是从哪包导入过来的;__class__打印出了这个对象是哪个类实例出来的。

3. __init__ 构造方法,通过类创建对象时,自动触发执行。

4.__del__

 析构方法,当对象在内存中被释放时,自动触发执行。

#注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的

 5. __call__ 对象后面加括号,触发执行

class Dog(object):
    def __init__(self):
        self.name = 'zsc'
        
d = Dog()
d()
直接在对象后面加括号调用,会报错:d()
#TypeError: 'Dog' object is not callable

class Dog(object):
    def __init__(self):
        self.name = 'zsc'
    def __call__(self,*args,**kwargs):
        print('this is call,',args,kwargs)   
d = Dog()
d(1,2,3,name='zsc')

#结果:
#this is call, (1, 2, 3) {'name': 'zsc'}
#可见,当在对象后面加括号时会调用这个对象的类的__call__方法。

6. __dict__ 查看类或对象中的所有成员  

7.__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

class Dog(object):
    def __init__(self):
        self.name = 'zsc'
d = Dog()
print(d)
#结果:<__main__.Dog object at 0x0000026023C5C4A8>


class Dog(object):
    def __init__(self):
        self.name = 'zsc'
    def __str__(self, *args, **kwargs):  #加了个__str__方法。
        return "<obj:%s>" % self.name
d = Dog()
print(d)
#结果:<obj:zsc>    
#可见__str__方法可以控制打印对象时的返回值。

8.__getitem__、__setitem__、__delitem__

使方法变得可以像字典一样使用,下面代码,

 

class Dog(object):
    def __init__(self):
        self.data = {}
    def __getitem__(self,key):       
        print('get')
        return self.data.get(key)
    def __setitem__(self,key,value):
        self.data[key] = value
        print('set')
    def __delitem__(self,key):
        del self.data[key]
        print('del')
d = Dog()
print(d['name'])
print('----------------------')
d['name'] = 'zsc'
print(d['name'])
print('----------------------')
del d['name']
print(d['name'])

#结果:
#get
None
----------------------
set
get
zsc
----------------------
del
get
None

 

可见,取值调用__getitem__方法;设置值调用__setitem__方法;删除值调用__delitem__方法。

9. __new__ \ __metaclass__

9.1 type类
class Foo(object): 
    def __init__(self,name):
        self.name = name
obj = Foo("alex")

上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。

如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

print type(obj) # 输出:<class '__main__.Foo'>     表示,obj 对象由Foo类创建
print type(Foo) # 输出:<type 'type'>              表示,Foo类对象由 type 类创建

所以,obj对象是Foo类的一个实例Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。

其实创建类有两种方式,

a).普通方式:
class Foo(object):  
    def func(self):
        print 'hello zsc'
b). 特殊方式
def func(self):
    print 'hello zsc'
  
Foo = type('Foo',(object,), {'talk': func})
#type第一个参数:类名
#type第二个参数:当前类的基类
#type第三个参数:类的成员

用特殊方式创建带有构造函数的类,

def func(self):
    print("hello %s"%self.name)

def __init__(self,name,age):
    self.name = name
    self.age = age
Foo = type('Foo',(object,),{'func':func,'__init__':__init__})

f = Foo("jack",22)
f.func()

#加上构造方法

所以请记住,类是由type类实例化产生的。

那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?

答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。

9.2 __new__方法
class Foo(object):
    def __init__(self):
        print('__init')
    def __new__(cls, *args, **kwargs):
        print('__new')
        return object.__new__(cls, *args, **kwargs)

obj = Foo()

#结果:
__new
__init
#可见实例化Foo对象后,会调用__init__和__new__方法,而且__new__方法在__init__之前被调用。

下面我们注释了__new__里的return,
class Foo(object):
    def __init__(self):
        print('__init')
    def __new__(cls, *args, **kwargs):
        print('__new')
#         return object.__new__(cls, *args, **kwargs)

obj = Foo()

#结果:__new。发现没有调用__init__方法,不是说所有类实例化时都会执行__init__方法吗?原因是,所有类的基类object里有一个__new__方法,这个方法会去调用类里的__init__方法,假如子类重写了__new__方法同时又不调用object.__new__方法的话,就会出现上面的情况;在obj = Foo()等于没有实例化对象。

#注:__new__里的cls参数实际是Foo这个类,把这个类传给了__new__方法。

#作用:假如有一些方法是需要在构造方法之前执行的,就可以重写__new__方法。
9.3 __metaclass__

这个的话,了解了解吧,基本上讲了一个意思:创建对象的的过程是,object类里的__call__方法调用__new__方法,并且生成一个obj的内存地址(其实就是实例出的类对象),然后__new__方法调用__init__方法并且把刚才生成的内存地址传入__init__。这就比较底层了,比如想要所有创建的类都有一个默认的字典,则可以在object的__call__方法里定义一个字典,这样所有的子类都默认都一个字典了。

 

7.反射

hasattr,判断一个对象里是否有对应的字符串的方法或属性,例如:hasattr(obj,string),有就返回True,没有就返回False。

getattr,getattr(obj,string),如果input_string是一个方法,此处会根据这个字符串获取对象obj里对应的方法的内存地址;如果input_string是一个属性值,此处会根据这个字符串获取对象obj里对应的属性值,而不是内存地址了。

setattr,通过字符串设置新的属性或方法;setattr(obj,string,z) ,把obj这个对象的string(可以是属性或方法)设置为z(可以是一个方法或者一个属性值)。

delattr,delattr(obj,string),删除obj这个对象里的string(可以是方法或者属性)。

下面的代码使用到了hasattr、getattr、setattr、delattr,

def talk(name):
    print('this is talk %s' % name)

class Foo(object):
    def __init__(self):
        self.name = 'zsc'       
    def eat(self):
        print('%s is eating.' % self.name)

obj = Foo()
choice = input('>>')
if hasattr(obj, choice):     #判断是否有用户输入的方法
    getattr(obj, choice)()   #如果有,就调用这个方法;如果choice是个属性,就去掉后面的括号。
else:
    setattr(obj, choice, talk)   #如果没有就设置这个方法,设置为已有的talk方法
    getattr(obj, choice)('zhangshanci')
delattr(obj, choice)     #删除这个方法
getattr(obj, choice)()   #删除后,再用getattr就会报错:没有对应方法。

 

9.异常处理

9.1 捕捉系统自带的异常

list_a = ['zsc','csz']
dic_a = {'name':'zsc','age':'27'}
try:
#     dic_a['fdsaf']
#     list_a[3]
    pass
except (KeyError,IndexError) as e:   #捕捉多个异常
    print('fault:',e)
except KeyError as e:    #捕捉一个异常
    print('fault:',e)
except Exception as e:   #捕捉所有异常(缩进错误还有一些错误是抓不到的),应该放到最后,上面的都没捕捉到再执行捕捉所有,因为它范围太大了,不好定位异常位置。
    print('all exception:',e)
else:              #如果没有异常被触发就会执行这段
    print('如果没有异常就会执行这个。')
finally:           #不管有没有异常都会执行这个
    print('不管有没有异常都会执行这个。')

9.2 自定义异常

class TestException(Exception):
    def __init__(self,msg):
        self.msg = msg
    def __str__(self, *args, **kwargs):  #这个方法去掉也行,这是重写了父类Exception的__str__方法。
        return self.msg
try:
    raise TestException('数据库连接异常')    #自定义的异常必须主动出发,系统无法感知自定义的异常。
except TestException as e:
    print(e)

9.3 异常种类

AttributeError #试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError #输入/输出异常;基本上是无法打开文件
ImportError #无法引入模块或包;基本上是路径问题或名称错误
IndentationError #语法错误(的子类) ;代码没有正确对齐
IndexError #下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
KeyError #试图访问字典里不存在的键
KeyboardInterrupt #Ctrl+C被按下
NameError #使用一个还未被赋予对象的变量
SyntaxError #Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError #传入对象类型与要求的不符合
UnboundLocalError #试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError #传入一个调用者不期望的值,即使值的类型是正确的

常用异常
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError

更多异常

9.4断言

name = 'zhangshanci'
assert type(name) is str
print('result')

#因为name是str类型的,所以assert断言通过,继续下面的代码,打印'result'

name = 123
assert type(name) is str
print('result')
#因为name是int类型的,但是assert断言它是str类型的,所以assert断言不通过,就会触发AssertionError异常,退出程序,后面的代码也不会执行。


#用途:假如后面的代码强烈依赖于前面执行成功,就可以加个断言,就像一道安检一样,通过了就继续执行后面的代码,不通过就退出。

 

 

11.Socket 编程

socket是依靠建立tcp/ip连接来通信的,ip:port。

#服务端伪代码
import socket
socket.TCP/IP
listen(ip:port)
waiting()
recv()
send()

#客户端伪代码
import socket
socket.TCP/IP
connect(ip:port)
send()
recv()
close()

Socket Families(地址簇)

socket.AF_UNIX unix本机进程间通信 

socket.AF_INET IPV4 

socket.AF_INET6  IPV6

These constants represent the address (and protocol) families, used for the first argument to socket(). If the AF_UNIX constant is not defined then this protocol is unsupported. More constants may be available depending on the system.

 

Socket Types

socket.SOCK_STREAM  #for tcp

socket.SOCK_DGRAM   #for udp 

socket.SOCK_RAW     #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。

socket.SOCK_RDM  #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。

socket.SOCK_SEQPACKET #废弃了

These constants represent the socket types, used for the second argument to socket(). More constants may be available depending on the system. (Only SOCK_STREAM and SOCK_DGRAM appear to be generally useful.)

11.1 简单的client和server的练习

import socket

client = socket.socket()    #socket类构造方法参数是:self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None
client.connect(('localhost',6969))
client.send(b'hi!')
data = client.recv(1024)
print(data)
client.close()



import socket

server = socket.socket()
server.bind(('localhost',6969))
server.listen()
conn, addr = server.accept()

data = conn.recv(1024)
print('server:',data)
conn.send(data.upper())
server.close()

#先执行server端代码;再执行client端代码。

下面演示要传入的数据包含中文的,

import socket

client = socket.socket()    #socket类构造方法参数是:self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None
client.connect(('localhost',6969))
client.send('中国人'.encode())
data = client.recv(1024)
print(data.decode())
client.close()



import socket

server = socket.socket()
server.bind(('localhost',6969))
server.listen()
conn, addr = server.accept()

data = conn.recv(1024)
print('server:',data.decode())
conn.send('是的,我是中国人'.encode())
server.close()

#发数据要encode()一下;收数据要decode()一下。

 下面的代码在linux里运行,

import socket,os

server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
server.bind(('localhost',9527))
server.listen()

while True:
    conn,addr = server.accept()
    while True:
        data = conn.recv(1024000)
        if not data:break
        result = os.popen(data.decode()).read()
        if result == '':   #如果命令不存在,此时的result就是空;如果不加这个判断,收到空命令程序会卡主,因为server没有东西发给client,client接收不到东西就一直卡住。
            conn.send('command not found.'.encode())
            continue
        conn.send(result.encode())
server.close()


import socket

client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
client.connect(('localhost',9527))

while True:
    u_input = input('>')
    client.send(u_input.encode())
    data = client.recv(1024000)
    print(data.decode())
    
client.close()

#注:如果命令的结果超过了客户端一次最多接收的字节数,比如返回的字节是5000,而客户端一次接1024,那就会先给客户端显示1024字节的内容,把剩下的内容存到客户端的内存中,等下次别管调用什么命令,都会直接把内存里的数据返回回去,所以客户端有必要调大接收字节数。
#举例:客户端输入top命令,然后服务端把top命令结果返回给客户端,但是客户端只能显示1024字节,下次客户端输入df命令或者ls命令,收到的还是上次未显示完的top命令的结果。

 

send会一次性把所有字节发过去,但是接收方会一点点接收,所以接收方需要有一个while循环(直到没有数据才break),没有循环的话接收方只会读一段数据就停止了,如下代码:

#!/usr/bin/env python

import socket
client = socket.socket()
client.connect(('localhost', 6969))
f = open("test.avi", "wb")
while True:
    data = client.recv(10240000)
    if len(data) == 0:
        break
    f.write(data)
client.close()

#client是接收方,把接收到的数据写入test.avi里,所以必须有个while循环读数据。

#!/usr/bin/env python

import socket
server = socket.socket()
server.bind(('localhost', 6969))
server.listen()
conn, addr = server.accept()

f = open('shipin.avi', 'rb')
file = f.read()
conn.send(file)
server.close()

#server是发送方,会把read出来的数据一次性的发送给client。

12.动态导入模块

module1 = 'aa'
from lib import module1
#用上面的方法导入包会报错,因为import module1不会自动解析成import aa;那如何才能import字符串格式的模块名呢?这就是下面动态导入的方法。


module = 'lib.aa'
import importlib
aa = importlib.import_module(module)或者aa = importlib.import_module('lib.aa')
print(aa.C().name)
#这样就导入了lib包下的aa模块,直接用aa.C()创建一个类C的对象。


动态导入模块的作用:根据用户输入的或者从其他地方获取到的字符串来导入需要的模块。

 

 

 

 

posted @ 2016-09-06 10:00  freedom_dog  阅读(529)  评论(0编辑  收藏  举报