Python进阶(三)
一.Python模块
导入模块:
>>> import math >>> math.pow(2,2) 4.0 >>>
导入指定函数:
>>> from math import pow,sin,log >>> pow(2,10) 1024.0 >>> sin(90) 0.8939966636005579 >>>
使用from example import function时出现的名字冲突问题:
>>> from math import log >>> from logging import log as logger >>> print log(10) 2.30258509299 >>> logger(10,'importt from logging') >>>
动态导入模块:try:except ImportError:
>>> try:from cStringIO import StringIO except ImportError: from StringIO import StringIO
使用__future__:
当新版本的一个特性与旧版本不兼容时,该特性将会在旧版本中添加到__future__中,以便旧的代码能在旧版本中测试新特性。
要试用某一新的特新,就可以导入__future__模块的功能来实现
在Python 2.7中:
>>> 10 / 3 3在Python 3.x中:
>>> 10 / 3 3.3333333333333335 >>> 10 // 3 3在2.7中试用3.x的功能:
>>> from __future__ import division >>> print 10 / 3 3.3333333333333335
Python管理第三方模块的方式:
1.easy_install
2.pip(推荐,内置在2.7.9中)
确保安装了pip的情况下在命令提示符输入:pip install web.py(//第三方模块)等待下载就可以了
二.Python面向对象特征:
创建一个类,初始化两个该类的示例,进行打印和对比操作:
class Person(object): pass xiaoming=Person() xiaohong=Person() print xiaoming print xiaohong print xiaoming==xiaohong >>> <__main__.Person object at 0x02840970> <__main__.Person object at 0x0295C650> False创建一个类,初始化三个类的实例,给增加属性(python是动态语言,对于每个属性都直接可以给他们赋值):
class Person(object): pass p1 = Person() p1.name = 'Bart' p2 = Person() p2.name = 'Adam' p3 = Person() p3.name = 'Lisa' L1 = [p1, p2, p3] L2 = sorted(L1,lambda p1,p2:cmp(p1.name,p2.name)) print L2[0].name print L2[1].name print L2[2].name >>> Adam Bart Lisa
尽管python可以给示例随便增加属性,但是,现实世界中同一个类应该拥有相同的属性,此时我们使用__init__() 方法来同意定义属性,类似java中的构造方法,第一个参数必须是self,如下:
class Person(object): def __init__(self, name, gender, birth): self.name = name self.gender = gender self.birth = birth创建实例的时候我们就可以这样了:
xiaoming = Person('Xiao Ming', 'Male', '1991-1-1') xiaohong = Person('Xiao Hong', 'Female', '1992-2-2')试编写除了接受固定参数之外还可以接受不确定的参数:**kw
class Person(object): def __init__(self, name, gender, birth, **kw): self.name = name self.gender = gender self.birth = birth for k, v in kw.iteritems(): setattr(self, k, v) xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student') print xiaoming.name print xiaoming.job
访问限制:
属性前面加 '__' (双下划线) 就无法被外部访问。
xiaoming.__name='Xiao Ming'前后都加 '__' 的为特殊属性,python中有很多预定义的特殊属性可以用,通常我们不需要把普通属性用 __xxx__ 定义。以单下划线开头的属性"_xxx"虽然也可以被外部访问,但是,按照习惯,他们不应该被外部访问。
class Person(object): def __init__(self,name,score): self.name=name self.__score=score p=Person('Bob',69) print p.name print p.__score >>> Traceback (most recent call last): File "C:/Users/Administrator.2013-20140717HS/Desktop/aaa", line 7, in <module> print p.__score AttributeError: 'Person' object has no attribute '__score'
创建类属性:
class Person(object): sex='M' def __init__(self,name,score): self.name=name self.score=score p1=Person('Bob',69) p2=Person('Jim',89) print p1.sex print p1.sex >>> M M >>>类属性也可以动态创建:
class Person(object): sex='M' def __init__(self,name,score): self.name=name self.score=score Person.countrycode='CN' p1=Person('Bob',69) p2=Person('Jim',89) print p1.sex print p1.sex print p1.countrycode print p1.countrycode >>> M M CN CN >>>
类属性和示例属性冲突时:
class Person(object): address = 'Earth' def __init__(self, name): self.name = name p1 = Person('Bob') p2 = Person('Alice') print 'Person.address = ' + Person.address p1.address = 'China' print 'p1.address = ' + p1.address print 'Person.address = ' + Person.address print 'p2.address = ' + p2.address >>> Person.address = Earth p1.address = China Person.address = Earth p2.address = Earth可见,可见,当实例属性和类属性重名时,实例属性优先级高,它将屏蔽掉对类属性的访问。
原因是 p1.address = 'China'并没有改变 Person 的 address,而是给 p1这个实例绑定了实例属性address ,对p1来说,它有一个实例属性address(值是'China'),而它所属的类Person也有一个类属性address,所以:
访问 p1.address 时,优先查找实例属性,返回'China'。
访问 p2.address 时,p2没有实例属性address,但是有类属性address,因此返回'Earth'。
定义实例的方法:
实例的方法就是在类中定义的函数,它的第一个参数永远是 self,指向调用该方法的实例本身,其他参数和一个普通函数
class Person(object): def __init__(self, name): self.__name = name def get_name(self): return self.__name
定义类方法:
和属性类似,方法也分为实例方法和类方法,在class 中定义的全部是实例方法,实例方法的第一个参数是self本身。如下:@classmethod
class Person(object): sex='M' count=0 @classmethod def many(cls): return cls.count def __init__(self,name): self.name=name Person.count=Person.count+1 print Person.many() p=Person('Jim') print Person.many() >>> 0 1 >>>通过标记一个 @classmethod,该方法将绑定到 Person 类上,而非类的实例。类方法的第一个参数将传入类本身,通常将参数名命名为 cls,上面的 cls.count 实际上相当于 Person.count。因为是在类上调用,而非实例上调用,因此类方法无法获得任何实例变量,只能获得类的引用。
类的继承:
class Person(object): def __init__(self,name,sex): self.name=name self.sex=sex class Student(Person): def __init__(self,name,sex,age): super(Student,self).__init__(name,sex) self.age=age p=Person('Jim','M') print p.name s=Student('Tom','W',19) print s.name >>> Jim Tom >>>Python集成的特点:
总是从某一个类集成,默认继承object
调用super().__init__() 用来初始化父类
isinstance()判断类型
isinstance() 可以判断一个变量的类型,既可以用在python内置的数据类型又可以用在我们自己定义的类,本质上都是数据类型,拿上面的代码为例,判断:
print isinstance(p,Person) print isinstance(p,Student) print isinstance(s,Person) print isinstance(s,Student) >>> True False True True >>>
多态
类具有继承关系,并且子类类型可以向上转型做父类类型,我们在给Person,Student,Teacher,都加上toString()方法
class Person(object): def __init__(self,name,sex): self.name=name self.sex=sex def toString(self): return 'this is Person,person name is %s'%self.name class Student(Person): def __init__(self,name,sex,age): super(Student,self).__init__(name,sex) self.age=age def toString(self): return 'this is Studnet,student name is %s'%self.name def f(x): print x.toString() p=Person('Jim','M') s=Student('Alice','W',19) f(p) f(s) >>> this is Person,person name is Jim this is Studnet,student name is Alice >>>说明:子类和父类分别有自己的toString()方法,方法调用作用在实例的实际类型上,Student实际上拥有自己的toString()和来自父类的toString(),调用时总是先找到自己定义的toString(),如果找不到才会向上找,直到找到为止。
由于Python是动态语言,传递给f()的类型不一定是Person或者其子类,任何类型都可以。只要有一个toString()方法就可以,如下:
class Book(object): def toString(self): return 'book' def f(x): print x.toString() b=Book() f(b) >>> book >>>这是动态语言和静态语言(例如Java)最大的差别之一。动态语言调用实例方法,不检查类型,只要方法存在,参数正确,就可以调用。
多重继承:
class A(object): def __init__(self, a): self.a = a class B(A): def __init__(self, a): super(B, self).__init__(a) class C(A): def __init__(self, a): super(C, self).__init__(a) class D(B, C): def __init__(self, a): super(D, self).__init__(a)
像这样,D 同时继承自 B 和 C,也就是 D 拥有了 A、B、C 的全部功能。多重继承通过 super()调用__init__()方法时,A 虽然被继承了两次,但__init__()只调用一次
多重继承的目的是从两种继承树中分别选择并继承出子类,以便组合功能使用。
例子:
+-Person
+- Student
+- Teacher
是一类继承树;
+- SkillMixin
+- BasketballMixin
+- FootballMixin
是一类继承树。
通过多重继承,请定义“会打篮球的学生”和“会踢足球的老师”。
class Person(object): pass class Student(Person): pass class Teacher(Person): pass class SkillMixin(object): pass class BasketballMixin(SkillMixin): def skill(self): return 'basketball' class FootballMixin(SkillMixin): def skill(self): return 'football' class BStudent(Student, BasketballMixin): pass class FTeacher(Teacher, FootballMixin): pass s = BStudent() print s.skill() t = FTeacher() print t.skill()
获取对象信息:
type()
>>> type(123) <type 'int'> >>> s = Student('Bob', 'Male', 88) >>> type(s) <class '__main__.Student'>dir()
>>> dir(123) # 整数也有很多属性... ['__abs__', '__add__', '__and__', '__class__', '__cmp__', ...] >>> dir(s) ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'gender', 'name', 'score', 'whoAmI']dir()返回的属性是字符串列表,如果已知一个属性名称,要获取或者设置对象的属性,就需要用getattr() 和 setattr( )函数了:
>>> getattr(s, 'name') # 获取name属性 'Bob' >>> setattr(s, 'name', 'Adam') # 设置新的name属性 >>> s.name 'Adam' >>> getattr(s, 'age') # 获取age属性,但是属性不存在,报错: Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Student' object has no attribute 'age' >>> getattr(s, 'age', 20) # 获取age属性,如果属性不存在,就返回默认值20: 20
特殊方法:
__str__:把一个类变成str
class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender def __str__(self): return '(Person: %s, %s)' % (self.name, self.gender) >>> p = Person('Bob', 'male') >>> print p (Person: Bob, male)Python 定义了__str__()和__repr__()两种方法,__str__()用于显示给用户,而__repr__()用于显示给开发人员。
__cmp__:
对 int、str 等内置数据类型排序时,Python的 sorted() 按照默认的比较函数 cmp 排序,但是,如果对一组 Student 类的实例排序时,就必须提供我们自己的特殊方法__cmp__():
class Student(object): def __init__(self, name, score): self.name = name self.score = score def __str__(self): return '(%s: %s)' % (self.name, self.score) __repr__ = __str__ def __cmp__(self, s): if self.name < s.name: return -1 elif self.name > s.name: return 1 else: return 0上述 Student 类实现了__cmp__()方法,__cmp__用实例自身self和传入的实例 s 进行比较,如果 self 应该排在前面,就返回 -1,如果s 应该排在前面,就返回1,如果两者相当,返回 0。
__len__
如果一个类表现得像一个list,要获取有多少个元素,就得用 len() 函数。
要让 len() 函数工作正常,类必须提供一个特殊方法__len__(),它返回元素的个数。
class Students(object): def __init__(self, *args): self.names = args def __len__(self): return len(self.names)
斐波那契数列是由 0, 1, 1, 2, 3, 5, 8...构成。
请编写一个Fib类,Fib(10)表示数列的前10个元素,print Fib(10) 可以打印出数列的前 10 个元素,len(Fib(10))可以正确返回数列的个数10。
class Fib(object): def __init__(self, num): a, b, L = 0, 1, [] for n in range(num): L.append(a) a, b = b, a + b self.numbers = L def __str__(self): return str(self.numbers) __repr__ = __str__ def __len__(self): return len(self.numbers) f = Fib(10) print f print len(f)
数学运算:
定义一个Rational 和加减乘除预算
def gcd(a, b): if b == 0: return a return gcd(b, a % b) class Rational(object): def __init__(self, p, q): self.p = p self.q = q def __add__(self, r): return Rational(self.p * r.q + self.q * r.p, self.q * r.q) def __sub__(self, r): return Rational(self.p * r.q - self.q * r.p, self.q * r.q) def __mul__(self, r): return Rational(self.p * r.p, self.q * r.q) def __div__(self, r): return Rational(self.p * r.q, self.q * r.p) def __str__(self): g = gcd(self.p, self.q) return '%s/%s' % (self.p / g, self.q / g) __repr__ = __str__ r1 = Rational(1, 2) r2 = Rational(1, 4) print r1 + r2 print r1 - r2 print r1 * r2 print r1 / r2 >>> 3/4 1/4 1/8 2/1 >>>
类型转换:
Rational类实现了有理数运算,但是,如果要把结果转为 int 或 float 怎么办?要让int()函数正常工作,只需要实现特殊方法__int__():
class Rational(object): def __init__(self, p, q): self.p = p self.q = q def __int__(self): return self.p // self.q
__slots__
__slots__是指一个类允许的属性列表:__slots__的目的是限制当前类所能拥有的属性,如果不需要添加任意动态的属性,使用__slots__也能节省内存。
class Student(object): __slots__ = ('name', 'gender', 'score') def __init__(self, name, gender, score): self.name = name self.gender = gender self.score = score
__call__
一个类实例也可以变成一个可调用对象,只需要实现一个特殊方法__call__()。我们把 Person 类变成一个可调用对象:
class Person(object): def __init__(self, name, gender): self.name = name self.gender = gender def __call__(self, friend): print 'My name is %s...' % self.name print 'My friend is %s...' % friend