当前位置: 首页 > news >正文

中山网站推广外包哪里可以做微网站

中山网站推广外包,哪里可以做微网站,ps自学网官方网站,目前最好的推广平台面向对象oopclass Student(object):def __init__(self,name,score)self.name nameself.score scoredef print_score(self)print(%s: %s % (self.name,self.score))给对象发消息实际上就是调用对象对应的关联函数#xff0c;我们称之为对象的方法(Method)。面向对象的程序写出…面向对象oopclass Student(object):def __init__(self,name,score)self.name nameself.score scoredef print_score(self)print(%s: %s % (self.name,self.score))给对象发消息实际上就是调用对象对应的关联函数我们称之为对象的方法(Method)。面向对象的程序写出来就像这样bart Student(‘zhangyuang’,90)lisa Student(‘janvier’,90)bart.print_score()lisa.print_score()类和实例class Student(object):passclass后面紧接着是类名即Student类名通常是大写开头的单词紧接着是(object),表示该类是从哪个类继承下来的继承的概念一行再讲。通常如果没有合适的继承类就使用object类这是所有类最终都会继承的类。定义好了Student类就可以根据Student类创建出Student的实例创建实例是通过类名()实现 bart Student() bart Studeng可以看到变量bart指向的就是一个Student的实例后面的0x10a67a590是内存地址每个object的地址都不一样而Student本身则是一个类。可以自由的给一个实例变量绑定属性 bart.name zhangyuang bart.namezhangyuang由于类可以起到模版的作用因此在创建实例的时候把一些我们认为必须绑定的属性强制天蝎进去。通过定义一个特殊的init方法在创建实例的时候就把name,score等属性绑上去 class Student(object):def __init__(self,name,score):self.name nameself.score score注意到init方法的第一个参数永远是self.表示创建的实例本身因此在init方法内部就可以把各种属性绑定到self因为self就指向创建的实例本身。有了init方法在创建实例的时候就不能传入空的参数了必须传入与init方法匹配的参数但self不需要传Python解释器自己会把实例变量传进去 bart Student(zhangyuang,90) bart.namezhangyuang bart.score90数据封装面向对象编程的一个重要特点就是数据封装。在上面的Student类中每个实例就拥有各自的name和score这些数据。我们可以通过函数来访问这些数据比如打印一个学生的成绩 def print_score(std):print(%s: %s % (std.name,std.score)) print_score(bart)zhangyuang:90但是既然Student实例本身就拥有这些数据要访问这些数据就没有必要从外面的函数去访问可以直接在Student类的内部定义访问数据的函数这样就把“数据”给封装起来了。这些封装数据的函数是和Student类本身是关联起来的我们称之为类的方法class Student(object):def init(self,name,score):self.name nameself.score scoredef print_score(self):print(‘%s: %s’ % (self.name,self.score))要定义一个方法除了第一个参数是self外其他和普通函数一样。要调用一个方法只需要在实例变量上直接调用除了self不用传递其他参数正常传入。 bart.print_score()zhangyuang: 90封装的另一个好处是可以给Student类增加新的方法比如get_grade:class Student(object):def get_grade(self):if self.score 90:return ‘a’elif self .score 60:return ‘b’else:return ‘c’bart.get_grade()c访问限制如果要让内部属性不被外部访问可以把属性的名称前加两个下划线在python中实例的变量名如果以开头就变成了一个私有变量(private),只有内部可以访问外部不能访问。class Student(object):def init(self,name,score):self.name nameself.score scoredef print_score(self):print(‘%s: %s’ % (self.name,self.score))改完后对于外部代码来说没什么变动但是已经无法从外部访问实例变量.name和实例变量.score了 bart Student(zhangyuang,90) bart.__nameTraceback (most recent call last):File , line 1, in AttributeError: Student object has no attribute __name这样就确保了外部代码不能随意修改对象内部的状态这样通过访问限制的保护代码更加健壮。如果外部代码要获取name和score怎么办可以给Student类增加get_name和get_score这样的方法class Student(object):def get_name(self):return self.namedef get_score(self)return self.score如果又要允许外部代码修改score怎么办可以再给Student类增加set_score方法class Student(object):def set_score(self,score):self.score score你也许会问原先那种直接通过bart.score 59也可以修改啊为什么要定义一个方法大费周折因为在方法中可以对参数做检查避免传入无效的参数class Student(object):def set_score(self,score):if 0score100:self.score scoreelse:raise ValueError(‘bad score’)需要注意的是在Python中变量名类似xxx的也就是以双下划线开头并且以双下划线结尾的是特殊变量特殊变量是可以直接访问的不是private变量所以不能用name、score这样的变量名。有些时候你会看到以一个下划线开头的实例变量名比如_name这样的实例变量外部是可以访问的但是按照约定俗成的规定当你看到这样的变量时意思就是“虽然我可以被访问但是请把我视为私有变量不要随意访问”。继承和多态在OOP程序设计中当我们定义一个class的时候可以从某个现有的class继承新的class称为子类(Subclass)而被继承的class称为基类、父类或超类(Base class、Super class)。比如我们已经编写了一个名为Animal的class有一个run()方法可以直接打印class Animal(object):def run(self):print(‘Animal is running’)当我们需要编写Dog和Cat类时就可以直接从Animal继承class Dog(Animal):passclass Cat(Animal):pass对于Dog来说Animal就是它的父类对于Animal来说Dog就是它的子类。cat和Dog类似。继承有什么好处最大的好处是子嘞获得了父类的全部功能。由于Animal实现了run()方法因此Dog Cat作为它的子类什么事也没干就拥有了run()方法。dog Dog()dog.run()cat Cat()cat.run()Animal is running当然也可以对子类增加一些方法class Dog(Animal):def run(self):print(‘dog is running’)def eat(slef)print(‘eating meat’)继承的第二个好处需要我们对代码做一点改进。你看到了无论是dog还是cat它们run()的时候显示的都是Animal is running 符合逻辑的做法是分别显示dog is running 和 cat is running因此对Dog类和Cat类做如下改进class Dog(Animal):def run(self):print(Dog is running...)class Cat(Animal):def run(self):print(Cat is running...)当子类和父类都存在相同的run()方法时我们说子类的run()覆盖了父类的run()在代码运行的时候总是会调用子类的run()。这样我们就获得了继承的另一个好处多态。要理解什么是多态我们首先要对数据类型再作一点说明。当我们定义一个class的时候我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型比如str、list、dict没什么两样a list() # a是list类型b Animal() # b是Animal类型c Dog() # 是Dog类型判断一个变量是否是某个类型可以用istance()判断 isintance(a,list)True isinstance(b,Animal)True isinstance(c,Dog)True isinstance(c,Animal)True看来b不仅是Dog类型还是Animal类型 b Animal() isinstance(b,Dog)FalseDog可以看成Animal但Animal不可以看成Dog要理解多态的好处我们还需要再编写一个函数这个函数接受一个Animal类型的变量def run_twice(animal):animal.run()animal.run()当我们传入Animal的实例时run_twice()就打印出 run_twice(Animal())Animal is running...Animal is running...当我们传入Dog的实例时run_twice()就打印出 run_twice(Dog())Dog is running...Dog is running...当我们传入Cat的实例时run_twice()就打印出 run_twice(Cat())Cat is running...Cat is running...看上去没啥意思但是仔细想想现在如果我们再定义一个Tortoise类型也从Animal派生 class Tortoise(Animal):def run(self):print(‘tortoise is running’)当我们调用run_twice()时传入Tortoise的实例 run_twice(Tortoise())Tortoise is running slowly...Tortoise is running slowly...你会发现新增一个Animal的子类不必对run_twice()做任何修改实际上任何依赖Animal作为参数的函数或者方法都可以不加修改地正常运行原因就在于多态。多态的好处就是当我们需要传入Dog、Cat、Tortoise……时我们只需要接收Animal类型就可以了因为Dog、Cat、Tortoise……都是Animal类型然后按照Animal类型进行操作即可。由于Animal类型有run()方法因此传入的任意类型只要是Animal类或者子类就会自动调用实际类型的run()方法这就是多态的意思对于一个变量我们只需要知道它是Animal类型无需确切地知道它的子类型就可以放心地调用run()方法而具体调用的run()方法是作用在Animal、Dog、Cat还是Tortoise对象上由运行时该对象的确切类型决定这就是多态真正的威力调用方只管调用不管细节而当我们新增一种Animal的子类时只要确保run()方法编写正确不用管原来的代码是如何调用的。这就是著名的“开闭”原则静态语言 vs 动态语言对于静态语言(例如Java)来说如果需要传入Animal类型则传入的对象必须是Animal类型或者它的子类否则将无法调用run()方法。对于Python这样的动态语言来说则不一定需要传入Animal类型。我们只需要保证传入的对象有一个run()方法就可以了class Timer(object):def run(self):print(Start...)这就是动态语言的“鸭子类型”它并不要求严格的继承体系一个对象只要“看起来像鸭子走起路来像鸭子”那它就可以被看做是鸭子。Python的“file-like object“就是一种鸭子类型。对真正的文件对象它有一个read()方法返回其内容。但是许多对象只要有read()方法都被视为“file-like object“。许多函数接收的参数就是“file-like object“你不一定要传入真正的文件对象完全可以传入任何实现了read()方法的对象。获取对象的信息使用type()判断对象类型使用type()函数基本类型都可以用type() type(123) type(str) type(None)如果一个变量指向函数或者类也可以用type()判断 type(abs) type(a)但是type()函数返回的是什么类型呢它返回对应的Class类型。如果我们要在if语句中判断就需要比较两个变量的type类型是否相同 type(123) type(456)True type(123) intTrue type(abc) type(123)True type(abc) strTrue type(abc) type(123)False判断基本数据类型可以直接写int,str等但如果要判断一个对象是否是函数怎么办可以使用types模块中定义的常量 import types def fn():pass type(fn) types.FunctionTypeTrue type(abs) type.BuiltinFunctionTypeTrue type(lambda x:x) type.LambdaTypeTrue type((x for x in range(10))) types.GeneratorTypeTrue使用isinstance()对于class的继承关系来说使用type()就很不方便。我们要判断class的类型可以使用isinstance()函数我们回顾上次的例子如果继承关系是object-Animal-Dog-Husky那么isinstance()就可以告诉我们一个对象是否是某种类型。先创建3种类型的对象。 a Animal() d Dog() h Husky()然后判断 isinstance(h,Husky)True isinstance(h,Dog)Trueh虽然自身是Husky类型但由于Husky是从Dog继承袭来的所以h也还是Dog类型。换句话说isinstance()判断的是一个对象是否是该类型本身或者位于该类型的父继承链上。并且还可以判断一个变量是否是某些类型中的一种比如下面的代码就可以判断是否是list或者tuple isinstance([1,2,3],(list,tuple))True isinstance((1,2,3),(list,tuple))True使用dir()如果要获得一个对象的所有属性和方法可以使用dir()函数它返回一个包含字符串的list比如获得一个str对象的所有属性和方法 dir(ABC)[__add__, __class__, __contains__, __delattr__, __dir__, __doc__, __eq__, __format__, __ge__, __getattribute__, __getitem__, __getnewargs__, __gt__, __hash__, __init__, __iter__, __le__, __len__, __lt__, __mod__, __mul__, __ne__, __new__, __reduce__, __reduce_ex__, __repr__, __rmod__, __rmul__, __setattr__, __sizeof__, __str__, __subclasshook__, capitalize, casefold, center, count, encode, endswith, expandtabs, find, format, format_map, index, isalnum, isalpha, isdecimal, isdigit, isidentifier, islower, isnumeric, isprintable, isspace, istitle, isupper, join, ljust, lower, lstrip, maketrans, partition, replace, rfind, rindex, rjust, rpartition, rsplit, rstrip, split, splitlines, startswith, strip, swapcase, title, translate, upper, zfill]类似xxx的属性和方法在Python中都是有特殊用途的比如len方法返回长度。在Python中如果你调用len()函数试图获取一个对象的长度实际上在len()函数内部它自动去调用该对象的len()方法所以下面的代码是等价的 len(abc)3 abc.__len__()3我们自己写的类如果也想用len(obj)的话就自己写一个len()方法 class MyDog(object):def __len__(self):return 100dog myDog()len(dog)100剩下的都是普通属性或方法比如lower()返回小写的字符串 ABC.low()abc仅仅把属性和方法列出来是不够的配合getattr(),setattr()以及hasattr()我们可以直接操作一个对象的状态 class MyObject(object):def __init__(self)self.x 9def power(self):return self.x * self .x obj MyObject()紧接着可以测试该对象的属性 hasattr(obj,x) # 有属性x吗True obj.x9 hasattr(obj,y) # 有属性y吗False setattr(obj,y,19) # 设置属性y hasattr(obj,y) # 有属性y吗True getattr(obj,y) # 获取属性y19 obj.y19可以传入一个default参数如果属性不存在就返回默认值: getattr(obj,z,404) # 获取属性z如果不存在返回默认值404404也可以获得对象的方法 hasattr(obj,power) # 有属性power吗True getattr(obj,power) # 获取属性power fn getattr(obj,power) # 获取属性power并复制到变量fn fn()81小结通过内置的一系列函数我们可以对任意一个Python对象进行剖析拿到其内部的数据。要注意的是只有在不知道对象信息的时候我们才会去获取对象信息。如果可以直接写sum obj.x obj.y就不要写sum getattr(obj, x) getattr(obj, y)一个正确的用法的例子如下:def readImage(fp):if hasattr(fp,’read’)return readData(fp)return None假设我们希望从文件流fp中读取图像我们首先要判断fp对象是否存在read方法如果存在则该对象是一个流如果不存在则无法读取。hasattr()就派上了用场。请注意在python这类动态语言中根据鸭子类型有read()方法不代表该fp对象就是一个文件流它也可能是网络流也可能是内存中的一个字节流但只要read()方法返回的是有效的图像数据就不影响读取图像功能。实例属性和类属性由于python是动态语言根据类创建的实例可以任意绑定属性。由给实例绑定属性的方法是通过实例变量或者通过self变量class Student(object):def init(self,name):self.name names Student(‘zhangyuang’)s.score 90但是如果Student类本身需要绑定一个属性呢可以直接在class中定义属性这种属性是类属性。归Student类所有class Student(object):name ‘Student’当我们定义了一个类属性后这个属性虽然归类所有但类的所有实例都可以访问到。 class Student(object):name Student s Student() print(s.name) # 因为实例并没有name属性所以会继续查找class的name属性Student print(Student.name)Student s.name zhangyuang print(s.name)zhangyuang print(Student.name)Student del s.name print(s.name)Student从上面的例子可以看出在编写程序的时候千万不要把实例属性和类属性使用相同的名字因为相同名称的实例属性将屏蔽掉类属性但是当你删除实例属性后再使用相同的名称访问到的将是类属性。使用slots正常情况下当我们定义了一个class创建了一个class的实例后我们可以给该实例绑定任何属性和方法。class Student(object):pass然后尝试给实例绑定一个属性 s Student() s.name zhangyuang print(s.name)zhangyuang还可以尝试给实例绑定一个方法 def set_age(self,age):self.age age from types import MethodType s.set_age MethodType(set_age,s) s.set_age(19) s.age25但是给一个实例绑定的方法对另一个实例是不起作用的 s2 Student() s2.set_age(19)Traceback (most recent call last):File , line 1, in AttributeError: Student object has no attribute set_age为了给所有实例都绑定方法可以给class绑定方法 def set_score(self,score):self.score score Student.set_score set_score通常情况下上面的set_score方法可以直接定义在class中但动态绑定允许我们在程序运行的过程中动态给class加上功能这在静态语言中很难实现。使用slots但是如果我们想要限制实例的属性怎么办比如只允许对Student实例添加name和age属性为了达到限制目的python允许在定义class的时候定义一个特殊的slots变量来限制该class实例能添加的属性 class Student(object):slots (‘name’,’age’)然后我们试试 s Student() s.name zhangyuang s.age 19 s.score 90Traceback (most recent call last):File , line 1, in AttributeError: Student object has no attribute score由于’score’没有被放到slots中所以不能绑定score属性试图绑定score将得到AttributeError的错误。使用slots要注意slots定义的属性仅对当前类实例起作用对继承的子类是不起作用的 class collegestudent(Student):pass g collegestudent() g.score 99除非在子类中也定义slots这样子类实例允许定义的属性就是自身的slots加上父类的slots。在绑定属性时如果我们直接把属性暴露出去虽然写起来很简单但是没办法检查参数导致可以把成绩随便改s Student()s.score 9999这显然不和逻辑。为了限制score的范围可以通过一个set_score()方法来设置成绩再通过一个get_score()来获取成绩这样在set_score()方法里就可以检查参数class Student(object):def get_score(self):return self.scoredef set_score(self,value):if not isinstance(value,int):raise ValueError(‘score must be an integer’)if value 0 or value 100:raise ValueError(‘score must between 0~100!’)现在对任意的Student实例进行操作就不能随心所欲地设置score了 s Student() s.set_score(60) s.get_score()60 s.set_score(9999)Traceback (most recent call last):...ValueError: score must between 0 ~ 100!但是上面的调用方法又略显复杂没有直接用属性这么直接简单。有没有既能检查参数又可以用类似属性这样简单的方式来访问类的变量呢还记得装饰器(decorator)可以给函数动态加上功能吗对于类的方法装饰器一样起作用[email protected]属性调用class Student(object):propertydef score(self):return self._scorescore.setterdef score(self,value):if not isinstance(value, int):raise ValueError(‘score must be an integer!’)if value 0 or value 100:raise ValueError(‘score must between 0 ~ 100!’)self._score valueproperty的实现比较复杂我们先考虑如何使用。把一个getter方法变成属性[email protected][email protected]负责把一个setter方法变成属性赋值于是我们就拥有一个可控的属性操作 s Student() s.score 60 s.score60 s.score 9999Traceback (most recent call last):...ValueError: score must between 0 ~ 100![email protected],[email protected]不是直接暴露的而是通过getter和setter方法来实现还可以定义只读属性只定义getter不定义setter方法就是一个只读属性class Student(object):propertydef birth(self):return self._birthbirth.setterdef birth(self,value):self._birth valuepropertydef age(self):return 2017-self._birth上面的birth是可读写属性而age就是一个只读属性因为age可以根据birth和当前时间计算出来。多重继承继承是面向对象编程的一个重要方式因为通过继承子类就可以扩展父类的功能。多重继承class Animal(object):pass# 大类class Mammal(Animal):passclass Bird(Animal):pass# 各种动物class Dog(Mammal):passclass Bat(Mammal):passclass Parrot(bird):passclass Ostrich(Bird):pass现在我们要给动物再加上Runnable和Flyable的功能只需要预先定义好Runnable和Flyable的类class Runnable(object):def run(self):print(‘running’)class Flyable(object):def flu(self):print(‘flying’)对于需要runnable的动物就多继承一个runnable例如Dogclass Dog(Mammal,Runnable):pass对于需要Flyable功能的动物就多继承一个flyable例如batclass Bat(Mammal,Flyable):pass通过多重继承一个子类就可以同时获得多个父类的所有功能。MixIn在设计类的继承关系时通常主线都是单一继承下来的例如Ostrich继承自Bird。但是如果需要混入额外的功能。通过多重继承就可以实现。比如让Ostrich除了继承自Bird外再同时继承Runnable。这种设计通常称为MixIn.为了更好地看出继承关系。我们把Runnable和Flyable改为RunnableMIxIn和FlyableMixIn。类似的你还可以定义出肉食动物CarnivorousMixIn和植食动物HerbivoresMixIn让某个动物同时拥有好几个MixInclass Dog(Mammal,RunnableMixIn,CarnivorousMixIn):passMixIn的目的就是给一个类增加多个功能这样在设计类的时候我们优先考虑通过多重继承来组合多个MixIn的功能而不是设计多层次的复杂的继承关系。Python自带的很多库也使用了MixIn。举个例子Python自带了TCPServer和UDPServer这两类网络服务而要同时服务多个用户就必须使用多进程或多线程模型这两种模型由ForkingMixIn和ThreadingMixIn提供。通过组合我们就可以创造出合适的服务来。比如编写一个多进程模式的TCP服务定义如下class MyTCPServer(TCPServer,ForkingMixIn):pass编写一个多进程模式的UDP服务定义如下class MyUDPServer(UDPServer,ThreadingMixIn):pass定制类看到类似slots这种形如xxx的变量或者函数名就要注意这些python是有特殊用途的。slots我们已经知道怎么用了len()方法我们也知道是为了让class作用与len()函数。除此之外Python的class中还有许多这样特殊的函数帮助我们定制类。str我们先定义一个Student类打印一个实例 class Student(object):def __init__(self,name):self.name name print(Student(zhangyuang))打印出一堆__main__.student object at不好看。怎么才能打印的好看呢只需要定义好str()方法返回一个好看的字符串就可以了 class Student(object):def __init__(self,name):self.name namedef __str__(self):return Student object (name: %s) % self.name print(Student(zhangyuang))Student object (name: zhangyuang)但是细心的朋友会发现直接敲变量不用print打印出来的实例还是不好看 s Student(zhangyuang) s这是因为直接显示变量调用的str(),而是repr(),两者的区别是str()返回用户看到的字符串而repr()返回程序开发者看到的字符串也就是说repr()是为调试服务的。解决办法是再定义一个repr()。但是通常str()和repr()代码都是一样的所以有个偷懒的写法class Student(object):def init(self,name):self.name namedef str(self):return (‘Student object(name %s’) % self.namerepr striter如果一个类想被用于for….in循环类似list或tuple那样就必须实现一个iter()方法该方法返回一个迭代对象然后python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值直接遇到StpIteration错误时退出。我们以斐波那契数列为例class Fib(object):def init(self):self.a,self.b 0,1def iter(self):return self #实例本身就是迭代对象故返回自己def next(self):self.a,self.b self.b,self.a self.b #计算下一个值if self.a 100000:raise StopIteration()return self.a for n in Fib():print(n)11235....46368getitemFib实例虽然能作用于for循环看起来和list有点像但是把它当list来用还是不行的 Fib()(5)Traceback (most recent call last):File , line 1, in TypeError: Fib object does not support indexing要表现的像list那样按照下标取出元素需要实现getitem()方法class Fib(object):def getitem(self,n):a,b 1,1for x in range(n):a,b b,abreturn a f Fib() f[0]1 f[2]2但是list有个神奇的切片方法 list(range(100))[5:10][5,6,7,8,9]对于Fib却报错。原因是getitem()传入的参数可能是一个int也可能是一个切片对象silce所以要做判断class Fib(object):def getitem(self,n):if isinstance(n,int): # n是索引a,b 1,1for x in range(n):a,b b,abreturn aif isinstance(n,slice): # n是切片start n.startstop n.stopif start is None:start 0a,b 1,1L []for x i range(stop):if xstart:L.append(a)a,b b,abreturn L f Fib() f[0:5][1,1,2,3,5] f[:10][1,1,2,3,.....,21,34,55]正常情况下当我们调用类的方法或属性如果不存在就会报错要避免这个错误除了可以加上改属性外python还有另一个机制那就是写一个getattr()方法动态返回一个属性class Student(object):def init(self):self.name ‘zhangyuang’def getattr(self,attr):if attr ‘score’:return 99if attr ‘age’return lambda:25 s.score99 s.age()25注意只有在没有找到属性的情况下才调用getattr()已有的属性比如name不会在getattr()中查找。此外注意到任意调用如s.abc都会返回None这是因为我们定义的getattr默认返回的就是None。要让class只响应特定几个属性就要按照约定抛出AttributeError错误class Student(object):def getattr(self,attr):if attr ‘age’:return lambda:25raise AttributeError(‘’Student’object has no attribute ’%s’’ % attr)这实际上可以把一个类的所有属性和方法调用全部动态化处理了不需要任何特殊手段。这种完全动态调用的特性有什么实际作用呢作用就是可以针对完全动态的情况作调用。举个例子现在很多网站都搞REST API比如新浪微博、豆瓣啥的调用API的URL类似利用完全动态的getattr我们可以写出一个链式调用class Chain(object):def __init__(self,path):self._path pathdef __getattr__(self,path):return Chain(%s/%s % (self._path,path))def __str__(self):return self.path__repr__ __str__ Chain().status.user.timeline.list/status/user/timeline/list这样无论API怎么变SDK都可以根据URL实现完全动态的调用而且不随API的增加而改变还有些REST API会把参数放到URL中比如GitHub的APIGET /users/:user/repos调用时需要把:user替换为实际用户名。如果我们能写出这样的链式调用Chain().users(michael).repos一个对象实例可以有自己的属性和方法当我们调用实例方法时我们用instance.method()来调用。能不能直接在实例本身上调用呢在python中答案是肯定的。任何类只需要定义一个call()方法就可以直接对实例进行调用class Student(object):def init(self,name):self.name namedef call(self):print(‘My name si %s’ %self.name) s Student(zhangyuang)s()My name is zhangyuang通过callable()函数我们就可以判断一个对象是否是“可调用”对象。 callable(Student())True callable(str)false使用枚举类当我们需要定义常量时一个办法是用大写变量通过整数来定义例如月份JAN 1FEB 2MAr 3好处是简单缺点是类型是int并且仍然是变量。更好的放啊是为了这样的枚举类型定义一个class类型然后每个常量都是class的一个唯一实例。python提供Enum类来实现这个功能。from enum import EnumMonth Enum(‘Month’,(‘Jab’,’Feb’…..,’Nov’,’Dec’))这样我们就获得了Month类型的枚举类可以直接使用Month.Jan来引用一个常量或者枚举它的所有成员for name,member in Month.members.items():print(name,””,member,’,’,member.value)value属性则是自动赋给成员的int常量默认从1开始计数。如果需要更精确地控制枚举类型可以从Enum派生出自定义类from enum import Enum,uniqueuniqueclass weekday(Enum):Sun 0Mon 1Tue 2unique装饰器可以帮助我们检查保证没有重复值。访问这些枚举类型可以有若干种方法 day1 weekday.Mon print(day1)weekday.Mon print(weekday.Mon.value)1 print(weekday(1))weekday.Mon使用元类type()动态语言和静态语言最大的不同就是函数和类的定义不是编译时定义的而是运行时动态创建的。比方说我们要定义一个Hello的class就写一个hello.py模块class Hello(object):def hello(self,name ‘world’):print(‘Hello,%s’ % name)当python解释器载入hello模块时就会依次执行该模块的所有语句执行结果就是动态创建出一个Hello的class对象 from hello import Hello h Hello() h.hello()Hello,world print(type(Hello)) print(type(h))type()函数可以查看一个类或者变量的类型Hello是一个class它的类型就是type(),而h是一个实例它的类型就是class Hello我们说class的定义是运行时动态创建的而创建class的方法就是使用type()函数。type()函数既可以返回一个对象的类型又可以创建出新的类型比如我们可以通过type()函数创建出Hello类而无需通过class Hello(object)…的定义 def fn(self,nameworld): #先定义函数print(hello %s % name) Hello type(Hello,(object,),dict(hello fn))#创建Hello class h Hello() h.hello()Hello,world print(type(Hello)) print(type(h))要创建一个class对象type()函数依次传入3个参数1、class名称2、继承的父类集合注意python支持多重继承如果只有一个父类别忘了tuple的单元素写法3、class的方法名称与函数绑定这里我们把fn绑定到方法名hello上。错误处理程序运行的过程中如果发生了错误可以事先约定返回一个错误代码这样就可以知道是否有错以及出错的原因。在操作系统提供的调用中返回错误码非常常见。比如打开文件的函数open()成功时返回文件描述符(就是一个整数)出错时返回-1。用错误码来表示是否出错十分不便因为函数本身应该返回的正常结果和错误码混在一起造成调用者必须用大量的代码来判断是否出错def foo():r some_function()if r (-1):return (-1)# do somethingreturn rdef bar():r foo()if r (-1):print(Error)else:pass一旦出错还要一级一级上报直到某个函数可以处理该错误(比如给用户输出一个错误信息)所以高级语言通常都内置了一套try…except…finally…的错误处理机制python也不例外try让我们用一个例子来看看try的机制try:print(‘try’)r 10 / 0print(‘result:’,r)except ZeroDivisionError as e:print(‘except:’,e)finally:print(‘finally…’)print(‘end’)当我们认为某些代码可能会出错时就可以用try来运行这段代码如果执行出错则后续代码不会执行而是直接跳转至错误处理代码即except语句块执行完except后如果有finally语句块则执行finally语句块至此执行完毕。上面的代码在计算10/0时会产生一个除法运算错误try…except: division by zerofinallyEND从输出可以看到当错误发生时后续语句print(‘result’,r)except由于补货到ZeroDivisionError,因此被执行。最后finally语句被执行。然后程序继续按照流程往下走。如果把除数0改成2则执行结果如下try…result:5finallyEND由于没有错误发生时所以except语句块不会被执行但是finally如果有则一定会被执行(可以没finally语句)。你还可以猜测错误应该有很多种类如果发生不同类型的错误应该由不同的except语句块出炉。没错可以有多个except来补货不同类型的错误try:print(‘try…’)r 10/int(‘a’)print(‘result’,r)except ValueError as e:print(‘ValueError:’e)except ZeroDivisionError as e:print(‘ZeroDivisionError:’,e)finally:print(‘finally’)print(‘END’)int()函数可能会抛出ValueError,所以我们用一个expcept捕获ValueError用另一个except捕获ZeroDivisionError此外如果没有错误发生可以在except语句块后面加一个else当作没有错误发生时会自动执行else语句try:print(‘try…’)r 10/int(‘2’)print(‘result:’r)except ValueError as e:print(‘ValueError:’,e)except ZeroDivisionError as e:print(‘ZeroDivisionError:’,e)else:print(‘no error’)finally:print(‘finally’)print(‘END’)python的错误其实也是class所有的错误类型都继承自BaseException,所以在使用except时需要注意的是它不但捕获该类型的错误还把其子类也一网打尽try:foo()except ValueError as e:print(‘ValueError’)except UnicodeError as e:print(‘UnicodeError’)第二个except永远也捕获不到UnicodeError,因为UnicodeError是ValueError的子类如果有也被第一个except给捕获了。python所有的错误都是从BaseException类派生的常见的错误类型和继承关系看这里https://docs.python.org/3/library/exceptions.html#exception-hierarchy使用try…except捕获错误还有一个好处就是可以跨越多层调用比如函数main()调用foo(),bar()调用foo(),foo()出错了就可以在main()捕获到就可以处理# err.pydef foo(s):return 10/int(s)def bar(s)return foo(s) * 2def main():try:bar(0)except Exception as e:print(Error:,e)finally:print(finally)调用堆栈如何错误没有被捕获它就会一直往上抛最后被python解释器捕获打印一个错误信息然后程序退出$ python3 err.pyTraceback (most recent call last):File “err.py”, line 11, in main()File “err.py”, line 9, in mainbar(‘0’)File “err.py”, line 6, in barreturn foo(s) * 2File “err.py”, line 3, in fooreturn 10 / int(s)ZeroDivisionError: division by zerologging模块可以记录错误信息import loggingdef foo(s):return 10/int(s)def bar(s):return foo(s) * 2def main():try:bar(0)exception Exception as e:logging.exception(e)main()print(END)同样是出错但程序打印完错误信息后会继续执行并正常退出$ python3 err_logging.pyERROR:root:division by zeroTraceback (most recent call last):File “err_logging.py”, line 13, in mainbar(‘0’)File “err_logging.py”, line 9, in barreturn foo(s) * 2File “err_logging.py”, line 6, in fooreturn 10 / int(s)ZeroDivisionError: division by zeroEND抛出错误如果要抛出错误首先根据需要可以定义一个错误的class选择好继承关系然后用raise语句抛出一个错误# err_raise.pyclass FooError(ValueError):passdef foo(s):n int(s)if n 0:raise FooError(invalid valye: %s % s)return 10/nfoo(0)$ python3 err_raise.pyTraceback (most recent call last):File err_throw.py, line 11, in foo(0)File err_throw.py, line 8, in fooraise FooError(invalid value: %s % s)__main__.FooError: invalid value: 0只有在必要的时候才定义我们自己的错误类型如果可以选择python已有的内置错误类型(ValueError,TypeError)尽量使用内置类型最后我们来看另一种错误处理方式。# err_reraise.pydef foo(s):n int(s)if n 0:raise ValueError(invalid value:%s %s)return 10/ndef bar():try:foo(0)except ValueError as e:print(ValueError)raise在bar()函数中我们明明已经捕获了错误但是打印一个ValueError!后又把错误通过raise语句抛出去了这不有病么其实这种错误处理方式不但没病而且相当常见。捕获错误目的只是记录一下便于后续追踪。但是由于当前函数不知道应该怎么处理该错误所以最恰当的方式是继续往上抛让顶层调用者去处理。好比一个员工处理不了一个问题时就把问题抛给他的老板如果他的老板也处理不了就一直往上抛最终会抛给CEO去处理。调试第一种方法简单粗暴就使用print()把可能有问题的变量打印出来def foo(s):n int(s)print(‘ n %d’ % n)return 10/ndef main():foo(‘0’)main()执行后在输出中查找打印的变量值$ python3 err.py n 0Traceback (most recent call last):...ZeroDivisionError: integer division or modulo by zero用print()最大的坏处是将来还得删掉它想想程序里到处都是print()运行结果也会包含很多垃圾信息。断言凡是用print()来辅助查看的地方都可以用断言(assert)来替代。def foo(s):n int(s)assert n!0,’n is zero’return 10/ndef main():foo(‘0’)assert的意思是表达式n!0应该是True否则根据程序运行的逻辑后面的代码肯定会出错。如果断言失败assert语句本身就会抛出AssertionError:$ python3 err.pyTraceback (most recent call last):…AssertionError: n is zero!程序中如果导出充斥着assert和print()相比也好不到哪去。不过启动python解释器时可以用-O参数来关闭assert$ python3 -O err.pyTraceback (most recent call last):…ZeroDivisionError: division by zero关闭后你可以把所有的assert语句当成pass来看logging把print()替换成logging是第3种方式和assert相比logging不仅会抛出错误而且可以输出到文件impoet loggings ‘0’n int(s)logging.info(‘n %d’ % n)print(10/n)logging.info()就可以输出一段文本。运行发现除了ZeroDivisionError没有任何信息。怎么回事别急在import logging之后添加一行配置再试试import logginglogging.basicConfig(levellogging.INFO)看到输出了$ python3 err.pyINFO:root: n 0Traceback (most recent call last):File “err.py”, line 8, in print(10 / n)ZeroDivisionError: division by zero这就是logging的好处它允许你指定记录信息的级别有debuginfowarningerror等几个级别当我们指定levelINFO时logging.debug就不起作用了。同理指定levelWARNING后debug和info就不起作用了。这样一来你可以放心地输出不同级别的信息也不用删除最后统一控制输出哪个级别的信息。logging的另一个好处是通过简单的配置一条语句可以同时输出到不同的地方比如console和文件。pdb第4种方式是启动python的调试器pdb让程序以单步方式运行可以随时查看运行状态。# err.pys 0n int(s)print(10/n)然后启动python3 -m pdb err.py /Users/zhangyuang/Desktop/python - python3/samples/debug/err.py(2)()- s 0以参数-m pdb启动后pdb定位到下一步要执行的代码- s ‘0’输入命令1来查看代码(pdb)11 #err.py2 - s ‘0’3 n int(s)4 print(10/n)输入命令n可以单步执行代码(pdb)n /Users/zhangyuang/Desktop/python - python3/samples/debug/err.py(3)()- n int(s)/Users/zhangyuang/Desktop/python - python3/samples/debug/err.py(4)()- print(10/n)任何时候都可以输入命令p变量名来查看变量(pdb) p s‘0’(pdb) p n0输入命令q结束调试退出程序(pdb) q这种通过pdb在命令行调试的方法理论上是万能的但实在太麻烦了如果有一千行代码要运行到第999行得敲多少命令啊。还好我们有另一种方法pdb.set_trace这个方法也是用pdb但是不需要单步执行我们只需要import pdb,然后在可能出错的地方放一个pdb.set_trace(),就可以设置一个断点#err.pyimport pdbs 0n int(s)pdb.set_trace() #运行到这里会自动暂停print(10/n)运行代码程序会自动在pdb.set_trace()暂停并进入pdb调试环境可以使用命令p查看变量或者用命令c继续运行$ python3 err.py/Users/zhangyuang/Desktop/python - python3/samples/debug/err.py(7)()- print(10/n)(pdb) p n0(pdb) cTraceback (most recent call last):File err.py, line 7, in print(10 / n)ZeroDivisionError: division by zero这个方式比直接启动pdb单步调试效率要高很多但也高不到哪IDE如果要比较爽地设置断点、单步执行就需要一个支持调试功能的IDE。目前比较好的Python IDE有PyCharm另外Eclipse加上pydev插件也可以调试Python程序。单元测试如果你听说过“测试驱动开发”(TDD:Test-Driven Development),单元测试就不陌生单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。比如对abs(),我们可以编写出以下几个测试用例1、输入正数比如1、1.2、0.99期待返回值与输入相同2、输入负数比如-1、-1.2、-0.99期待返回值与输入相反3、输入0期待返回04、输入非数值类型比如None、[]、{}期待抛出TypeError把上面的测试用例放到一个测试模块里就是一个完整的单元测试。如果单元测试通过说明我们测试的这个函数能够正常工作。如果测试不通过要么函数有Bug要么测试条件输入不正确总之需要修复使单元测试能够通过。单元测试通过后有什么意义呢如果我们对abs()函数代码做了修改只需要再跑一遍单元测试如果通过说明我们的修改不会对abs()函数原有的行为造成影响如果测试不通过说明我们的修改与原有行为不一致要么修改代码要么修改测试。这种以测试为驱动的开发模式最大的好处就是确保一个程序模块的行为符合我们设计的测试用例。在将来修改的时候可以极大程度地保证该模块行为仍然是正确的。我们来编写一个Dict类这个类的行为和dict一致但是可以通过属性来访问。 d Dict(a1,b2) d[a]1 d.a1mydict.py代码如下class Dict(dict):def init(self,kw):super().init(kw)def getattr(self,key):try:return self[key]except KeyError:raise AttributeError(r”‘Dict’object has no attribute ‘%s’” % key)def setattr(self,key,value):self[key] value为了编写单元测试我们需要引入Python自带的unittest模块编写mydict_test.py如下import unittestfrom mydict import Dictclass TestDict(unittest.TestCase):def test_init(self):d Dict(a1,b’test’)self.assertEqual(d.a,1)self.assertEqul(d.b,’test’)self.assertTrue(isinstance(d,dict))def test_key(self):d Dict()d[‘key’] ‘value’self.assertEqual(d.key,’value’)def test_attr(self):d Dict()d.key ‘value’self.assertTrue(‘key’ in d)self.assertEqual(d[‘key’],’value’)def test_keyerror(self):d Dict()with self.assertRaises(KeyError):value d[‘empty’]def test_attrerror(self):d Dict()with self.assertRaises(AttributeError):value d.empty编写单元测试时我们需要编写一个测试类从unittest.TestCase继承以test开头的方法就是测试方法不以test开头的方法不认为是测试方法测试的时候不会执行。对每一类测试都需要编写一个test_xxx()方法。由于unittest.TestCase提供了很多内置的条件判断我们只需要调用这些方法就可以断言输出是否是我们所期望的。最常用的断言就是assertEqual():self.assertEqual(abs(-1),1) #断言函数返回的结果与1相等另一种重要的断言就是期待抛出指定类型的Error比如通过d[‘empty’]访问不存在的key时断言会抛出KeyErrorwith self.assertRaises(KeyError):value d[‘empty’]而通过d.empty访问不存在的key时我们期待抛出AttributeErrorwith self.assertRaises(AttributeError):value d.empty运行单元测试一旦编写好单元测试我们就可以运行单元测试。最简单的运行方法是在mydict_test.py的最好加上两行代码if name ‘main‘unittest.main()这样就可以把mydict_test,py当作正常的python脚本运行$ python3 mydict_test.py另一种方法是在命令行通过参数-m unittest直接运行单元测试$ python3 -m unittest mydict_test........----------------------------Ran 5 tests in 0.000sok这是推荐的做法因为这样可以一次批量运行很多单元测试并且有很多工具可以自动来运行这些单元测试。setUP与testDown可以在单元测试中编写两个特殊的setUp()和tearDown()方法。这两个方法会分别在每调用一个测试方法的前后分别被执行。setUp()和testDown()方法有什么用呢设想你的测试需要启动一个数据库这时就可以在setUp()方法中连接数据库在testDown()方法中关闭数据库这样不必在每个测试方法中重复相同的代码class TestDict(unittest.TestCase):def setUp(self):print(‘setUp…’)def tearDown(self):print(‘tearDown…’)小结单元测试可以有效的测试某个程序模块的行为是未来重构代码的信心保证单元测试的测试用例要覆盖常用的输入组合、边界条件和异常。单元测试代码要非常简单如果测试代码太复杂那么测试代码本身就可能有BUG单元测试通过了并不意味着程序就没有bug了但是不通过程序肯定有bugIO编程文件读写读文件要以读文件的模式打开一个文件使用python内置的open()函数传入文件名和标识符 f open(./test.txt,r)标识符’r’表示读如果文件不存在open()函数就会抛出一个IOError的错误并且给出错误码和详细信息。如果文件打开成功接下来调用read()方法可以一次读取文件的全部内容python把内容读到内存用一个str对象表示 f.read()IO test最后一步是调用close()方法关闭文件文件使用完毕后必须关闭因为文件对象会占用操作系统的资源并且操作系统同一时间能打开的文件数量也是有限的。 f.close()由于文件读写时都有可能产生IOError一旦出错后面的f.close()就不会调用。所以为了保证无论是否出现try:f open(‘./test.txt’,’r’)print(f.read())finally:if f:f.close()但是每次都这么写实在是太繁琐了所以python引入了with语句来自动帮我们调用close()方法with open(‘./test.txt’,’r’) as f:print(r.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,常用作临时缓冲二进制文件前面讲的默认都是读取文本文件并且是UTF-8编码的文本文件。要读取二进制文件比如图片视频用’rb’模式打开文件即可 f open(./test.jpg,rb) f.read()b xffxd8xffxe1x00x18Exifx00x00... #十六进制表示的字节字符编码要读取非UTF-8编码的文本文件需要给open()函数传入encoding参数例如读取GBK编码的文件 f open(./gbk.test,r,encodinggbk) f.read()测试遇到有些编码不规范的文件你可能会遇到UnicodeDecodeError,因为在文本文件中可能夹杂了一些非法编码的字符。遇到这种情况open()函数还接受一个errors参数表示如果遇到编码错误后如何处理。最简单的方式是直接忽略 f open(./gbk.txt,r,encodinggbk,errorsignore)写文件写文件和读文件是一样的唯一区别是调用open()函数时传入标识符’w’或者’wb’表示写文本文件或写二进制文件 f open(./test.txt,w) f.write(hello,world) f.close()你可以反复调用write()来写入文件但是无比要调用f.close()来关闭文件。当我们写文件时操作系统往往不会立刻把数据写入磁盘而是放到内存缓存起来空闲的时候再慢慢写入。只有调用close()方法操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘剩下的丢失了。所以还是用with语句来的保险with open(‘./test.txt’,’w’) as f:f.write(‘hello world’)要写入特定编码的文本文件请给open()函数传入encoding参数将字符串转换为指定编码StringIO和BytesIOStringIO很多时候数据读写不一定是文件也可以在内存中读写。StringIO顾名思义就是在内存中读写str要把str写入StringIO我们需要先创建一个StringIO然后像写文件一样写入即可 from io import StringIO f StringIO() f.write(hello)5 f.write()1 f.write(world!)6 print(f.getvalue())hello worldgetvalue()方法用于获得写入后的str要读取StringIO可以用一个str初始化StringIO然后像读文件一样读取 from io import StringIO f StringIO(hellonHInGoodbye) while True:s f.readline()if s :breakprint(s.strip())HelloHIGoodbyeBytesIOStringIO操作的只能str如果要操作二进制数据就需要使用BytesIOBytesIO实现在内存中读写bytes我们创建一个BytesIO然后写入一些bytes from io import BytesIO f BytesIO() f.write(中文.encode(utf-8))6 print(f.getvalue())bxe4xb8xadxe6x96x87请注意写入的不是str而是经过UTF-8编码的bytes和StringIO类似可以用一个bytes初始化BytesIO然后像读文件一样读取 from io import BytesIO f BytesIO(bxe4xb8xadxe6x96x87) f.read()bxe4xb8xadxe6x96x87小结StringIO和BytesIO是在内存中操作str和bytes的方法是的和读写文件具有一致的借口。操作文件和目录如果我们要操作文件、目录可以在命令行下面输入操作系统提供的各种命令来完成。比如dir、cp等命令。如果要在python程序中执行这些目录和文件的操作怎么办其实操作系统提供的命令只是简单的调用了操作系统提供的借口函数python内置的os模块也可以直接调用操作系统提供的接口函数。打开python交互式命令行 import os os.name #操作系统类型posix如果是posix说明系统是Linux、unix或MacOSX,如果是nt就是windows系统。要获取详细的系统信息可以调用uname()函数 os.uname()posix.uname_result(sysnameDarwin, nodenamezhangyuangdeMBP, release16.0.0, versionDarwin Kernel Version 16.0.0: Mon Aug 29 17:56:20 PDT 2016; root:xnu-3789.1.32~3/RELEASE_X86_64, machinex86_64)注意uname()函数在windows上不提供也就是说os模块的某些函数是跟操作系统相关的环境变量在操作系统中定义的环境变量全部保存在os.environ这个变量中 os.environenviron({TERM_PROGRAM: Apple_Terminal, TERM: xterm-256color, SHELL: /bin/bash, TMPDIR: /var/folders/g7/n76jd7897_s0xtyqlssfk9y00000gn/T/, Apple_PubSub_Socket_Render: /private/tmp/com.apple.launchd.YKTDBWScTk/Render, TERM_PROGRAM_VERSION: 377, TERM_SESSION_ID: 50F4527E-810B-4A61-807C-3D9C8E2B345C, USER: zhangyuang, SSH_AUTH_SOCK: /private/tmp/com.apple.launchd.zdqC9KFAal/Listeners, __CF_USER_TEXT_ENCODING: 0x1F5:0x19:0x34, PATH: /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin, PWD: /Users/zhangyuang/Desktop/github/Learn_python, LANG: zh_CN.UTF-8, XPC_FLAGS: 0x0, XPC_SERVICE_NAME: 0, HOME: /Users/zhangyuang, SHLVL: 1, LOGNAME: zhangyuang, _: /usr/local/bin/python3, OLDPWD: /Users/zhangyuang/Desktop/github, __PYVENV_LAUNCHER__: /usr/local/bin/python3})要获取某个环境变量的值可以调用os.environ.get(‘key’) os.environ.get(PATH)/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin os.environ.get(x,default)default操作文件和目录操作文件和目录的函数一部分方法放在os模块中一部分放在os.path模块中这一点要注意一下。查看、创建和删除目录可以这么调用#查看当前目录绝对路径 os.path.abspath(.)/Users/zhangyuang/Desktop/github/Learn_python#在某个目录下创建一个新目录首先把新目录的完整路径表示出来 os.path.join(/Users/zhangyuang,testdir)/Users/zhangyuang/testdir#然后创建一个目录 os.mkdir(/Users/zhangyuang/testdir)#删掉一个目录 os.rmdir(/User/zhangyuang/testdir)把两个路径合成一个时不要直接拼字符串而是要通过os.path.join()函数这样可以正确处理不同操作系统的路径分隔符。在Linux/Unix/Mac下os.path.join()返回这样的字符串part-1/part-2而windows下会返回这样的字符串part-1part-2同样的道理要拆分路径时也不要直接去拆字符串而要通过os.path.split()函数这样可以把一个路径拆分为两部分后一部分总是最后级别的目录或文件名 os.path.split(/Users/zhangyuang/testdir/file.txt)(/Users/zhangyuang/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.listfir(.) if os.path.isdir(x)][.lein, .local, .m2, .npm, .ssh, .Trash, .vim, Applications, Desktop, ...]要列出所有.py文件 [x for x in os.listdir(x) 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序列化在程序运行的过程中最难过所有的变量都是在内存中比如定义一个dictd dict(name’zhangyuang’,age19,score99)可以随时修改变量比如把name改成janvier但是一旦程序结束变量所占用的内存就被操作系统回收。如果没有把修改后的janvier存储到磁盘上下次重新运行程序变量又被初始化为zhangyuang我们把变量从内存中变成可存储或可传输的过程称之为序列化在python中叫pickling在其他语言中也被称为serialization,marshalling,flattening等等都是一个意思。序列化之后就可以把序列化后的内容写入磁盘或者通过网络传输到别的机器中。反过来把变量内容从序列化的对象重新读到内存里称之为反叙黎话即unpicking。python提供了pickle模块来实现序列化。首先我们尝试把一个对象序列化并写入文件 import pickle d dict(namezhangyuang,age19,score99) pickle.dumps(d)bx80x03}qx00(Xx03x00x00x00ageqx01Kx14Xx05x00x00x00scoreqx02KXXx04x00x00x00nameqx03Xx03x00x00x00Bobqx04u.pickle.dumps()方法把任意对象序列化成一个bytes然后就可以把这个bytes写入文件。或者用另一个方法pickle.dump直接把序列化后写入一个file-like Object: f open(dump.txt,wb) pickle.dump(d,f) f.close()看看写入dump.txt的内容乱七八糟这些都是python保存的对象内部信息。当我们要把对象从磁盘读到内存时可以先把内容读到一个bytes然后用pickle.loads()方法反序列化出对象也可以直接用pickle.load()方法从一个file-like Object中直接反序列化对象。我们打开另一个python命令行来反序列化刚才保存的对象 f open(dump.txt,rb) d pickle.load(f) f.close() d{name:zhangyuang,score:99,age:19}变量的内容又回来了当然这个变量和原来的变量是完全不相干的对象它们只是内容相同而已。JSON如果我们要在不同的编程语言之间传递对象就必须把对象序列化为标准格式比如XML但更好的方法是序列化为JSON因为JSON表示出来就是一个字符串可以被所有语言读取也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式并且比XML更快而且可以直接在Web页面中读取非常方便。JSON表示的对象就是标准的JavaScript语言的对象JSON和Python内置的数据类型对应如下JSON类型 Python类型{} dict[] list“string” str123.56 int或floattrue/false True/Falsenull Nonepython内置的json模块提供了非常完善的Python对象到JSON格式的转换。我们先看看如何把python对象变成一个JSON import json d dict(namezhangyuang,age20,score99) json.dumps(d){age:20,score:99,name:zhangyuang}dumps()方法返回一个str内容就是标准的JSON。类似的dump()方法可以直接把JSON写入一个file-like Object。要把JSON反序列化为python对象用loads()或者对应的load()方法前者把JSON的字符串反序列化后者从file-like Object中读取字符串并反序列化 json_str {age:20,name:zhangyuang,score:99} json.loads(json_str){age:20,score:99,name:zhangyuang}由于JSON标准规定JSON编码是UTF-8所以我们总是能正确的在Python的str与JSON的字符串之间转换。JSON进阶Python的dict对象可以直接序列化为JSON的{},不过很多时候我们更喜欢用class表示对象比如定义Student类然后序列化import jsonclass Student(object):def init(self,name,age,score):self.name nameself.age ageself.score scores Student(‘zhangyuang’,19,99)print(json.dumps(s))运行代码毫不留情地得到一个TypeErrorTraceback (most recent call last):…TypeError: __main__.student object at is not JSON serializable错误的原因是Student对象不是一个可序列化为JSON的对象如果连class的实例对象都无法序列化为JSON这肯定不合理。别急我们仔细看看dumps()方法的参数列表发现除了第一个必须的obj参数外dumps()还提供了一大堆可选参数https://docs.python.org/3/library/json.html#json.dumps这些可选参数就是让我们来定制JSON序列化。前面的代码之所以无法把Student类实例序列化为JSON是因为 默认情况下dumps()方法不知道如何将Student实例变为一个JSON的{}对象。可选参数default就是把任意一个对象编程一个可序列化为JSON的对象我们只需要为Student专门写一个转换函数再把函数传进去即可def student2dict(std):return {‘name’: std.name‘age’: std.age‘score’: std.score}这样Student实例首先被student2dict函数转换成dict然后再顺利序列化为JSON print(json.dumps(s,default student2dict)){age:19,name:zhangyuang,score:99}不过下次如果遇到一个Teacher类的实例照样无法序列化为JSON,我们可以偷个懒把任意class的实例变为dictprint(json.dumps(s,default lambda obj:obj.dict))因为通常class的实例都有一个dict属性它就是一个dict用来存储实例变量。也有少数例外比如定义了slots的class。同样的道理如果我们要把JSON反序列化为一个Student对象实例loads()方法首先转换出一个dict对象然后我们传入的object_hook函数负责把dict转换为Student实例def dict2student(d):return Student(d[‘name’],d[‘age’],d[‘score’])运行结果如下 json_str {age:20,score:99,name:zhangyuang}打印出的是反序列化对象的Student实例对象小结python语言特定的序列化模块是pickle但如果要把序列化搞得通用、更符合web标准就可以使用json模块。json模块的dumps()和loads()函数是定义的非常好的接口的典范。当我们使用时只需要传入一个必须的参数。但是当默认的序列化机制不满足我们的要求时我们又可以传入更多的参数来定制序列化的规则即做到了接口简单易用又做到了充分的扩展性和灵活性。进程和线程多进程要让python程序实现多进程我们先了解操作系统的相关知识。UnixLinux操作系统提供了一个fork()系统调用。它非常特殊。普通的函数调用调用一次返回一次但是fork()调用一次返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程)然后分别在父进程和子进程内返回。子进程永远返回0而父进程返回子进程的ID。这样做的理由是一个父进程可以fork出很多子进程所以父进程要记下每个子进程的ID而子进程只需要调用getppid()就可以拿到父进程的ID。python的os模块封装了常见的系统调用其中就包括fork(),可以在python中轻松创建子进程import osprint(‘Process(%s) start…’ % os.getpid())# only works on Unix/Linux/Macpid os.fork()if pid 0:print(i am child process (%s) and my parent is %s % (os.getpid(),os.getppid()))else:print(i (%s) just created a child process(%s) %(os.getpid(),pid))运行结果如下process(876)starti(876)just created a child process(877)i am child process(877) and my parent is 876有了fork调用一个进程在接到新任务时就可以复制出一个子进程来处理新任务常见的Apache服务器就是由父进程监听端口每当有新的http请求就fork()出子进程来处理新的http请求正则表达式d匹配一个数字w匹配一个字母或数字‘00d’可以匹配’007’但无法匹配’00A’‘ddd’可以匹配’010’‘wwd’可以匹配’py3’.可以匹配任意字符‘py.’可以匹配’pyc’,’pyo’,’py!’*表示匹配任意个字符(包括0个)表示至少一个字符表示0个或1个字符{n}表示n个字符{n,m}表示n-m个字符来看一个复杂的例子d{3}sd{3,8}我们从左到右解读一下1、d{3}表示匹配3个数字例如’010’2、s可以匹配一个空格(也包括Tab等空白符)所以s表示至少有一个空格例如匹配’ ‘,’ ‘3、d{3,8}表示3-8个数字例如’1234567’综合起来上面的正则表达式可以匹配以任意个空格隔开的带区号的电话号码。如果要匹配’010-12345’这样的号码由于’-‘是特殊字符在正则表达式要用’’转义所以上面的正则是d{3}-d{3,8}但是仍然无法匹配’010 - 12345’因为带有空格。进阶要做更精确的匹配可以用[]表示范围比如1、[0-9a-zA-Z_]可以匹配一个数字、字母或者下划线2、[0-9a-zA-Z_]可以匹配至少由一个数字、字母或者下划线组成的字符串比如’a100’,’0Z’,’Py3000’3、[a-zA-Z][0-9a-zA-Z_]*可以匹配由字母或下划线开头后接任意个由一个数字、字母或者下划线组成的字符串也就是Python合法的变量4、[a-zA-Z_][0-9a-zA-Z_]{0,19}更精确的限制变量的长度时1-20个字符(前面1个字符后面最多19个字符)A|B可以匹配A或B所以(P|p)ython可以匹配’Python’或者’python’^表示行开头^d表示以数字开头$表示行结尾d$表示以数字结尾你可能注意到了py也可以匹配’python’,但是加上^py$酒变成了整行匹配只能匹配’py’了re模块Python提供re模块包含所有正则表达式的功能。由于Python的字符串本身也用转义所以要特别注意s ‘ABC-001’ #python字符串#对应的正则表达式字符串变成# ABC-001因此我们强烈建议使用Python的r前缀就不用考虑转义的问题了s r’ABC-001’#对应的正则表达式字符串不变#ABC-001先看看如何判断正则表达式如何匹配 import re re.match(r^d{3}-d{3-8}$,010-12345) re.match(r^d{3}-d{3-8}$,010 12345)match()方法判断是否匹配如果匹配成功返回一个Match对象否则返回None。常见的判断方法就是test ‘用户输入的字符串’if re.match(r’正则表达式’,test):print(‘ok’)else:print(‘failed’)切分字符串用正则表达式切分字符串比固定的字符更灵活请看正常的切分代码 a b c.split()[a,b,,,c]嗯无法识别连续的空格用正则表达式试试 re,split(rs,a b c)[a,b,c]无论多少个空格都可以正常分割。加入,试试 re.split(r[s,],a,b,c d)[a,b,c,d]再加入试试 re.split(r[s,;],a,b;;c d)[a,b,c,d]分组除了简单的判断是否匹配之外正则表达式还有提取字串的强大功能。用()表示要提取的分组。比如^(d{3})-(d{3,8})$分别定义了两个组可以直接从匹配的字符串中提取出区号和本地号码 m re.match(r^(d{3})-(d{3-8})$,010-12345) m m.group(0)010-12345 m.group(1)010 m.group(2)12345如果正则表达式定义了组就可以在Match对象上用group()方法提取出字串来。注意到group(0)永远是原始字符串、group(1),group(2)表示第12个字串提取字串非常有用来看一下更凶残的例子 t 19:05:30 m re.macth(r^(0[0-9]|1[0-9]|2[0-3]|[0-9]):(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9]):(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$, t) m.groups()(19,05,30)这个正则表达式可以直接识别合法的时间。到那时有时候用正则表达式也无法做到完全验证比如识别日期对于2-3-,4-31这样的非法日期还是识别不了这时候需要程序配合识别。贪婪匹配最后需要指出的是正则匹配默认是贪婪匹配也就是匹配尽可能多的字符。 re.macth(r^(d)(0*)$,102300).groups()(102300,)由于d采用贪婪匹配直接把后买呢0全部匹配了结果0*只能匹配空字符串了。必须让d采用非贪婪匹配(也就是尽可能少匹配)此啊能把后面的0匹配出来加个就可以让d采用非贪婪匹配 re.match(r^(d?)(0*)$,102300).groups()(1023,00)datetime获取当前日期和时间 from datetime import datetime now datetime.now() #获取当前datetime print(now)2015-05-18 16:23:23.192343 print(type(now))获取指定日期和时间要指定某个日期和时间我们直接用参数构造一个datetime from datetime import datetime dt datetime(2015,4,19,12,20)print(dt)2015-04-19 12:20:00datetime转换为timestamp在计算机中时间上实际上是用数字表示的。我们把1970年1月1日00:00:00 UTC 00:00时区的时刻称为epochtime,计为0(1970年以前的时间timestamp为负数)当前时间就是相对于epoch time的秒数称为timestamp你可以认为timestamp 0 1970-1-1 00:00:00 UTC0:00timestamp 0 1970-1-1 08:00:00 UTC8:00可见timestamp的值与时区毫无关系因为timestamp一旦确定其UTC时间就确定了转换到任意时区的时间也是完全确定的这就是为什么计算机存储的当前时间是以timestamp表示的因为全球各地的计算机在任意时刻的timestamp都是完全相同的把一个datetime类型转换为timestamp只需要简单调用timestamp()方法 from datetime import datetime dt datetime(2015,4,19,12,20) #用指定日期创建datetime dt.timestamp()1429417200.0注意python的timestamp是一个浮点数。如果有小数位小数位表示毫秒数某些编程语言(如java和javascript)的timestamp使用整数表示毫秒数这种情况下只需要把timestamp除以1000就得到python的浮点表示方法。timestamp转换为datetime要把timestamp转换为datetime使用datetime提供的fromtimestamp()方法 from datetime import datetime t 1429417200.0 print(datetime.fromtimestamp(t))2015-04-19 12:20:00注意到timestamp是一个浮点数它没有时区的概念而datetime是有时区的。上述转换是在timestamp和本地时间做转换。本地时间是指当前操作系统设定的时区。例如北京时区是东8区则本地时间2015-04-19 12:20:00实际上就是UTC8:00时区的时间2015-04-19 12:20:00 UTC8:00timestamp也可以直接被转换到UTC标准时区的时间 from datetie import datetime t 1429417200.0 print(datetime.fromtimestamp(t))#本地时间2015-04-19 12:20:00 print(datetime.utcfromtimestamp(t))2015-04-19 04:20:00str转为datetime很多时候用户输入的日期和时间是字符串要处理日期和时间首先必须把str转换datetime。转换方法是通过datetime.strptime()实现需要一个日期和时间的格式化字符串 from datetime import datetime cday datetime.strptime(2015-6-1 18:19:59,%Y-%m-%d %H:%M:%s) print(cday)2015-06-01 18:19:59datetime转换为str如果已经有了datetime对象要把它格式化为字符串显示给用户就需要转换为str转换方法是通过strftime()实现的同样需要一个日期和时间的格式化字符串 from datetime import datetime now datetime.now() print(now.strftime(%a,%b,%d %H:%M))Mon,May 05 16:28datetime加减对日期和时间进行加减实际上就是把datetime往后或往前计算得到新的datetime。加减可以直接用和-运算符不过需要导入timedelta这个类 from datetime import datetime,timedelta now datetime.now() nowdatetime.datetime(201551816573540997) now timedelta(hours10)datetime.datetime(2015,5,19,2,57,3,540997) now - timedelta(days1)datetime.datetime(2015,5,17,16,57,3,540997) now timedelta(days2,hour12)datetime.datetime(2015,5,21,4,57,3,540997)可见使用timedelta你可以很容易的算出前几天和后几天的时刻本地时间转换为UTC时间本地时间是指系统设定时区的时间例如北京时间是UTC8:00时区的时间 而UTC时间指UTC0:00时区的时间。一个datetime类型有一个时区属性tzinfo,但默认为None,所以无法区分这个datetime到底是哪个时区除非强行给datetime设置一个时区 from datetime import datetime,timedelta,timezone tz_utc_8 timezone(timedelta(hours8))#创建时区UTC8:00 now datetime.now()小结datetime表示的时间需要时区信息才能确定一个特定的时间否则只能视为本地时间。如果要存储datetime最佳方法是将其转换为timestamp再存储因为timestamp的值与时区完全无关collectionscollections是python内建的一个集合模块提供了许多有用的集合类。namedtuple我们知道tuple可以表示不变的集合例如一个点的二维坐标就可以表示成 p (1,2)但是看到(1,2)很难看出这个tuple是用来表示一个坐标的。定义一个class又小题大做了这时namedtuple就爬上了用场 from collections import namedtuple Point namedtuple(Point,[x,y]) p Point(1,2) p.x1 p.y2namedtuple是一个函数它用来创建一个自定义的tuple对象并且规定了tuple元素的个数并可以用属性而不是索引来引用tuple的某个元素这样以来我们用namedtuple可以很方便的定义一种数据类型它具备tuple的不变性又可以根据属性来引用可以验证创建的Point对象是tuple的一种子类 isinstance(p,Point)True isinstance(p,tuple)True类似的如果要用坐标和半径表示一个圆也可以用namedtuple定义# namedtuple(名称,[属性list])Circle namedtuple(Circle,[x,y,r])deque使用list存储数据时按索引访问元素很快但是插入和删除元素就很慢了因为list是线性存储访问量大的时候插入和删除效率很低。deque是为了高效实现插入和删除操作的双向列表适用于队列和栈 from collections import deque q deque([a,b,c]) q.append(x) q.appendleft(y) qdeque([y,a,b,c,x])deque除了实现list的append()和pop()外还支持appendleft()和popleft()这样就可以非常高效的往头部添加或删除元素。defaultdict使用dict时如果引用的key不存在就会抛出KeyError.如果希望key不存在时返回一个默认值就可以用defaultdict: from collections import defaultdict dd defaultdict(lambda: N/A) dd[key1] abc dd[key1]abc dd[key2]N/AOrderedDict使用dict时Key是无序的。在对dict做迭代时我们无法确定Key的顺序。如果要保持Key的顺序可以用OrderedDict: from collections import OrderedDict d dict([(a,1),(b,2),(c,3)]) d{a:1,c:3,b:2} od OrderedDict([(a,1),(b,2),(c,3)]) odOrderedDict([(a,1),(b,2),(c,3)])注意OrderedDict的Key会按照插入的顺序排列不是Key本身排序 od OrderedDict() od[z] 1 od[y] 2 od[x] 3 list(od.keys())[z,y,x]CounterCounter是一个简单的计数器例如统计字符出现的个数 from collections import Counter c Counter() for ch in programmingc[ch] c[ch] 1 cCounter({g: 2, m: 2, r: 2, a: 1, i: 1, o: 1, n: 1, p: 1})base64base64是一种用64个字符来表示任意二进制数据的方法。用记事本打开exe、jpg、pdf这些文件时我们都会看到一大堆乱码因为二进制文件包含很多无法打印和显示的字符所以如果要让记事本这样的文本处理软件能处理二进制数据就需要一个二进制到字符串的转换方法。Base64是一种最常见的二进制编码方法。Base的原理很简单首先准备一个包含64个字符的数组[‘A’,’B’,’C’,….,’a’,’b’,’c’……,’0’,’1’…’’,’/‘]然后对二进制数据进行处理每3个字节一组一共是3*824bit,划分为4组魅族正好6个bit.这样我们得到4个数字作为索引然后查表获得相应的4个字符就是编码后的字符串。所以Base编码会把3字节的二进制数据编码为4个字节的文本数据长度增加33%好处是编码后的文本数据可以在邮件正文、网页等直接显示。如果要编码的二进制数据不是3的倍数最后会剩下1个或2个字节怎么办Base用x00字节在末尾补足后再在编码的末尾加上1个或2个号表示补了多少字节解码的时候会自动去掉。python内置的base64可以直接进行base64的编解码 import base64 base64.b64encode(bbinaryx00string)bYmluYXJ5AHN0cmluZw base64.b64decode(bYmluYXJ5AHN0cmluZw)bbinaryx00string由于标准的Base64编码后可能出现的字符和/,在URL中就不能直接作为参数所以又有一种”url safe”的base64编码其实就是把字符和分别变成-和_ base64.b64encode(bixb7x1dxfbxefxff)babcd// base64.urlsafe_b64encode(bixb7x1dxfbxefxff)babcd--__ base64.urlsafe_b64decode(abcd--__)bixb7x1dxfbxefxffHTMLParser如果我们要编写一个搜索引擎第一步是用爬虫把目标网站的页面抓下来第二步就是解析该HTML页面到底是新闻、图片还是视频。假设第一步已经完成了第二步应该如何解析HTML呢HTML本质是XML的子集但是HTMl的语法没有XML那么严格所以不能用标准的DO们或SAX来解析HTML。好在python提供了HTMLParser来解析HTML只需简单几行代码 from html.parser import HTMLParser from hrml.entities import name2codepointclass MyHTMLParser(HTMLParser):def handle_starttag(self,tag,attrs):print( % tag)def handle_endtag(self,tag):print(%s % tag)def handle_startendtag(self,tag,attrs):print( % tag)def handle_data(self,data):print(data)def handle_comment(self,data):print()def handle_entityref(self,name):print(%s; % name)def handle_charref(self,name):print(%s; % name)parser MyHTMLPaeser()paser.feed(Some html HTML tutorial...END)feed()方法可以多次调用也就是不一定一次把整个HTML字符串都塞进去可以一部分一部分塞进去。特殊字符有两种一种是英文表示的 一种是数字表示的Ӓ这两种字符都可以通过Parser解析出来。urlliburillib提供了一系列用于操作URL的功能。Geturllib的request模块可以非常方便的抓取URL内容也就是发送一个GET请求到指定的页面然后返回HTTP响应例如对豆瓣的一个URLhttps://api.douban.com/v2/book/2129650进行抓取并返回响应from urllib import requestwith request.urlopen(‘https://api.douban.com/v2/book/2129650)as f:data f.read();print(‘Status:’,f.status,f.reason)for k,v in f.getheaders():print(‘%s: %s’ % (k,v))print(‘Data:’,data.decode(‘utf-8’))可以看到HTTP响应头和JSON数据Status: 200 OKServer: nginxDate: Tue, 26 May 2015 10:02:27 GMTContent-Type: application/json; charsetutf-8Content-Length: 2049Connection: closeExpires: Sun, 1 Jan 2006 01:00:00 GMTPragma: no-cacheCache-Control: must-revalidate, no-cache, privateX-DAE-Node: pidl1Data: {“rating”:{“max”:10,”numRaters”:16,”average”:”7.4”,”min”:0},”subtitle”:””,”author”:[“廖雪峰编著”],”pubdate”:”2007-6”,”tags”:[{“count”:20,”name”:”spring”,”title”:”spring”}…}如果我们想要模拟浏览器发送GET请求就需要使用Request对象通过往Request对象添加HTTp头我们就可以把请求伪装成浏览器。例如模拟iphone6去请求豆瓣首页from urllib import requestreq request.Request(‘http://www.douban.com/‘)req.add_header(‘User-Agent’, ‘Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25’)with request.urlopen(req) as f:print(‘Status:’,f.status,f.reason)for k,v in f.getheaders():print(‘%s: %s’ % (k,v))print(‘Data:’,f.read().decode(‘utf-8’))这样豆瓣会返回适合iphone的移动版网页……Post如果要以POST发送一个请求只需要把参数data以bytes形式传入。我们模拟一个微博登录先读取登陆的邮箱和口令然后按照weibo.cn的登陆页格式以usernamexxxpasswordxxx的编码传入from urllib import request,parseprint(‘Login to weibo.cn…’)email input(‘Email:’)passwd input(‘Password:’)login_data parse.urlencode([(‘username’,email),(‘password’,passwd),(‘client_id’,’’),(‘savestate’,’1’)(‘ec’,’’),(‘pagerefer’,’https://passport.weibo.cn/signin/welcome?entrymweiborhttp%3A%2F%2Fm.weibo.cn%2F‘)])req request.Request(‘https://passport.weibo.cn/sso/login‘)req.add_header(‘Origin’,’https://passport.weobo.cn‘)req.add_header(‘User-Agent’, ‘Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25’)req.add_header(‘Referer’, ‘https://passport.weibo.cn/signin/login?entrymweiboreswelwm3349rhttp%3A%2F%2Fm.weibo.cn%2F‘)with request.urlopen(req,datalogin_data.encode(‘utf-8’)) as f:print(‘Status:’,f.status,f.reason)for k,v in f.getheaders():print(‘%s: %s’ % (k,v))print(‘Data:’,f.read().decode(‘utf-8’))如果登陆成功我们获得的响应如下Status:200 okServer: nginx/1.2.0…Set-Cookie: SSOLoginState1432620126; path/; domainweibo.cn…Data: {“retcode”:20000000,”msg”:””,”data”:{…,”uid”:”1658384301”}}如果登陆失败我们获得的响应如下…Data: {“retcode”:50011015,”msg”:”u7528u6237u540du6216u5bc6u7801u9519u8bef”,”data”:{“username”:[email protected],”errline”:536}}Handler如果还需要更复杂的控制比如通过一个Proxy去访问网站我们需要利用ProxyHandler来处理实例代码如下proxy_handler urllib.request.ProxyHandler({‘http’: ‘http://www.example.com:3128/})proxy_auth_handler urllib.request.ProxyBasicAuthHandler()proxy_auth_handler.add_password(‘realm’, ‘host’, ‘username’, ‘password’)opener urllib.request.build_opener(proxy_handler, proxy_auth_handler)with opener.open(‘http://www.example.com/login.html‘) as f:pass
http://www.pierceye.com/news/909574/

相关文章:

  • 企业策划 企业网站建设 品牌设计下载住小帮app看装修
  • wordpress文章内图片不显示不出来成都seo整站
  • 鞍钢节能公司网站开发陈仓网站建设
  • 手机网站怎样排版最好东莞常平招聘网最新招聘信息
  • 网站推广途径选择com域名和网站
  • 建设网站后如何上线免费的网站app下载
  • 哪些动物可以做网站名天津免费建站
  • 网站关键字优化技巧如何做推广麦当劳的网站
  • 广州公司注册场地要求网站怎么优化排名的方法
  • 自己做网站用什么软件建设银行网站联系电话
  • 做一个论坛网站需要多少钱推广型网站制作公司
  • 网站介绍页面网站建设怎么找客户资源
  • 我的百度网盘登录入口大兵seo博客
  • 注册监理工程师注册查询系统关于进一步优化 广州
  • 建设网站怎样挣钱网页设计培训班哪里好
  • 类似+wordpress+建站wordpress教程视频教程
  • wordpress多个网站百度识图扫一扫入口
  • 广州网站建设的费用网站建设外包必须注意几点
  • 蓬莱做网站公司辽宁省网站备案要求
  • 西安做网站价格女装标题优化关键词
  • 三门峡市建设局网站wordpress安装伪静态
  • 校园兼职网站开发用例图最厉害的搜索引擎
  • 企业网站seo哪里好10黄页网站建设
  • 中国空间站网站色彩的应用
  • 网站分为哪些部分组成部分wordpress 用户密码加密方式
  • 产品展示栏目在网站中的作用电子商务网站建设实训方案
  • 做外贸网站需要请外贸文员吗pc端设计网站
  • 免费按模板制作微网站厦门十大软件公司
  • 免费网站模板在哪下载什么网站做的最好
  • 在智联招聘网站做销售医疗软件网站建设公司排名