python-模块、面向对象

1.1导入模块

使用import语句导入模块

import math

导入模块之后,就可以使用该模块下所定义的所有公开的函数、变量和类

>>> math.pow(2, 0.5) # pow是函数
1.4142135623730951

>>> math.pi # pi是变量
3.141592653589793

如果是导入模块下的某几个函数

例:

from math import pow, sin, log

通过import导入模块名,必须通过模块名引用函数名

例:

import math, logging
print math.log(10)   # 调用的是math的log函数
logging.log(10, 'something')   # 调用的是logging的log函数

通过使用 from import导入可能会引起函数名冲突,则需要别名

例:

from math import log
from logging import log as logger   # logging的log现在变成了logger
print log(10)   # 调用的是math的log
logger(10, 'import from logging')   # 调用的是logging的log


1.2动态导入模块

导入模块不存在,python会报importerror错误:

>>> import something
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named something

有时,两个不同的模块提供了相同的功能,如 StringIO和 cStringIO都提供了StringIO这个功能(原因:Python是动态语言,解释执行,因此Python代码运行慢;为了提高python代码的运行速度,可以把某些关键函数用C重写)

StringIO 是纯Python代码编写的,而 cStringIO 部分函数是 C 写的,cStringIO 运行速度更快。

通过typeError错误,动态导入模块:

例:

try:
    from cStringIO import StringIO #尝试从cStringIO导入
except ImportError:
    from StringIO import StringIO #如果失败了,再尝试从StringIO导入

注:try 的作用是捕获错误,并在捕获到指定错误时执行 except 语句。

利用import ... as也可以动态导入不同名称的模块

例:

try:
  import json
except ImportError:
  import simplejson as json
print json.dumps({'python':2.7})


1.3使用__future__

试用某一新特性,可以通过导入__future__模块的某些功能来实现

例:

#python 2.7 整数除法结果仍是整数
>>> 10 / 3
3
#python3.x 改进了整数的除法运算
>>> 10 / 3
3.3333333333333335
>>> 10 // 3
3

在Python 2.7中引入3.x的除法规则,导入__future__的division

>>> from __future__ import division
>>> print 10 / 3
3.3333333333333335


1.4安装第三方模块

python提供的模块管理工具:

esay_insatll

pip(推荐,已内置python2.7.9)


1.5定义类并创建实例

类通过class 关键字定义

例:

class Person(object):
    pass

按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的

创建实例使用 类名+(),类似函数调用的形式创建:

xiaoming = Person()
xiaohong = Person()

例:

class Person(object):
  pass
xiaoming = Person()
xiaohong = Person()
print xiaoming
print xiaohong
print xiaoming == xiaohong
<__main__.Person object at 0x7fcac56ea450>
<__main__.Person object at 0x7fcac5629ad0>
False


1.6创建实例属性

因为python是动态语言,对每个实例,可以直接给他们属性赋值

例:

xiaoming = Person()
xiaoming.name = 'Xiao Ming'
xiaoming.gender = 'Male'
xiaoming.birth = '1990-1-1'

xiaohong = Person()
xiaohong.name = 'Xiao Hong'
xiaohong.school = 'No. 1 High School'
xiaohong.grade = 2
#实例的属性可以像变量一样进行操作
xiaohong.grade = xiaohong.grade + 1


1.7初始化实例属性

在定义类的时候,可以为该类添加一个特殊的__init__()方法,当创建实例时,__init__()方法被自动调用,就可以为每个实例都统一加上以下属性:

class Person(object):
    def __init__(self, name, gender, birth): #创建实例时,就有name、gender、birth三个属性
        self.name = name
        self.gender = gender
        self.birth = birth

注:__init__() 方法的第一个参数必须是 self(也可以用别的名字,但建议使用习惯用法),后续参数则可以自由指定

xiaoming = Person('Xiao Ming', 'Male', '1991-1-1')
xiaohong = Person('Xiao Hong', 'Female', '1992-2-2')

例:定义Person类的__init__方法,除了接受 name、gender 和 birth 外,还可接受任意关键字参数,并把他们都作为属性赋值给实例。

class Person(object):
  def __init__(self,name,gender,birth,**kw): #**kw定义关键字参数
    self.name=name
    self.gender=gender
    self.birth=birth
    for k, v in kw.iteritems(): #解释器内部会将**kw拆分成对应的dict
      setattr(self, k, v) #setattr()方法接受3个参数:setattr(对象,属性,属性的值)
#setattr(self,k,v)相当于self.k = v
xiaoming = Person('Xiao Ming', 'Male', '1990-1-1', job='Student')

print xiaoming.name
print xiaoming.job


1.8python中访问限制

python中对属性权限的控制是通过变量属性名来实现的,如果一个属性由双下划线开头__,该属性就无法被外部访问。

例:

class Person(object):
    def __init__(self, name):
        self.name = name
        self._title = 'Mr'
        self.__job = 'Student'
p = Person('Bob')
print p.name
# => Bob
print p._title
# => Mr
print p.__job
# => Error
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute '__job'

如果一个属性以"__xxx__"的形式定义,那它又可以被外部访问了,以"__xxx__"定义的属性在Python的类中被称为特殊属性

单下划线开头的属性"_xxx"虽然也可以被外部访问,但是,按照习惯,他们不应该被外部访问。

_xxx 可以在子类中使用。__xxx 不可以在子类中使用。


1.9创建类属性

类是模板,而实例则是根据类创建的对象。

实例属性每个实例各自拥有,互相独立,而类属性有且只有一份。

定义类属性可以直接在class中定义

例:

class Person(object):
    address = 'Earth' #类属性
    def __init__(self, name):
        self.name = name

类属性直接绑定在类上的,访问类属性不需要创建实例,可直接访问

print Person.address
# => Earth

所有实例都可以访问到它所属的类的属性

例:

p1 = Person('Bob')
p2 = Person('Alice')
print p1.address
# => Earth
print p2.address
# => Earth

类属性也是可以动态添加和修改的

例:

Person.address = 'China'
print p1.address
# => 'China'
print p2.address
# => 'China'

例:给 Person 类添加一个类属性 count,每创建一个实例,count 属性就加 1,这样就可以统计出一共创建了多少个 Person 的实例。

class Person(object):
  count = 0
  def __init__(self, name):
    Person.count = Person.count + 1
    self.name = name

p1 = Person('Bob')
print Person.count

p2 = Person('Alice')
print Person.count

p3 = Person('Tim')
print Person.count

>>>1
2
3

注:创建实例必定会调用__init__()方法


2.0类属性和实例属性名冲突怎么办

例:

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

总结:当实例属性和类属性重名时,实例属性优先级高,将屏蔽掉类属性的访问

在实例上修改类属性,它实际上并没有修改类属性,而是给实例绑定了一个实例属性。

del p1.address #删除p1的address实例属性
print p1.address
# => Earth


2.1定义实例方法

实例的私有属性就是以__开头的属性,无法被外部访问,但是从类的内部可以访问。

可以在定义实例的属性,还可以定义实例的方法

实例的方法就是在类中定义的函数,第一个参数永远是self,指向调用该方法的实例本身。

例:

class Person(object):

    def __init__(self, name): #可以看成一个特殊的实例方法
        self.__name = name

    def get_name(self): #实例方法
        return self.__name

调用实例方法必须在实例上调用:

p1 = Person('Bob')
print p1.get_name()  # self不需要显式传入
# => Bob

总结:在实例方法内部,可以访问所有实例属性,如果外部需要访问私有属性,可以通过方法调用获得,这种数据封装的形式除了能保护内部数据一致性外,还可以简化外部调用的难度。

例: Person 类增加一个私有属性 __score,表示分数,再增加一个实例方法 get_grade(),能根据 __score 的值分别返回 A-优秀, B-及格, C-不及格三档。

class Person(object):

  def __init__(self, name, score):
    self.name=name
    self.__score=score

  def get_grade(self):
    if self.__score >= 80:
      return 'A'
    if self.__score >= 60:
      return 'B'
    return 'C'

p1 = Person('Bob', 90)
p2 = Person('Alice', 65)
p3 = Person('Tim', 48)

print p1.get_grade()
print p2.get_grade()
print p3.get_grade()


2.2python中方法也是属性

在class中定义的实例方法其实也是属性,实际上是一个函数对象

例:

class Person(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
    def get_grade(self):
        return 'A'

p1 = Person('Bob', 90)
print p1.get_grade #返回的是函数对象,绑定到实例的函数
# => <bound method Person.get_grade of <__main__.Person object at 0x109e58510>>
print p1.get_grade() #方法的调用
# => A

方法是一个属性,所以可以动态地添加到实例上,通过types.MethodType()把一个函数变成一个方法:

例:

import types
def fn_get_grade(self):
    if self.score >= 80:
        return 'A'
    if self.score >= 60:
        return 'B'
    return 'C'

class Person(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

p1 = Person('Bob', 90)
p1.get_grade = types.MethodType(fn_get_grade, p1, Person)
print p1.get_grade()
# => A
p2 = Person('Alice', 65)
print p2.get_grade()
# ERROR: AttributeError: 'Person' object has no attribute 'get_grade'
# 因为p2实例并没有绑定get_grade

给一个实例动态添加方法并不常见,直接在class中定义要更直观

例:

class Person(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score
        self.get_grade = lambda: 'A'

p1 = Person('Bob', 90)
print p1.get_grade #是函数
print p1.get_grade()
>>>
at 0x7f01d02ab5f0>
A

总结:直接把 lambda 函数赋值给 self.get_grade 和绑定方法有所不同:函数调用不需要传入 self,方法调用需要传入 self


2.3定义类方法

和属性类似,分为实例方法和类方法

class中定义的全部是实例方法,实例方法第一个参数 self 是实例本身。

例:

class Person(object):
    count = 0
    
    @classmethod #将该方法绑定到person类上,而非类的实例
    def how_many(cls): #类方法的第一个参数将传入类本身,通常将参数名命名为 cls
        return cls.count #cls.count 实际上相当于Person.count。
        
    def __init__(self, name):
        self.name = name
        Person.count = Person.count + 1

print Person.how_many()
p1 = Person('Bob')
print Person.how_many()

总结:类方法无法获得任何实例变量,只能获得类的引用(因为是在类上调用,而非实例上调用)


译者介绍:家华,从事mysqlDBA的工作,记录自己的一些总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值