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)
        

像这样,同时继承自 BC,也就是 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__:

对 intstr 等内置数据类型排序时,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和传入的实例 进行比较,如果 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


posted @ 2015-03-27 00:00  顾明伟  阅读(287)  评论(0编辑  收藏  举报