python学习笔记:2.面向对象

模块

一个py文件,就是一个模块(module),相同函数和变量名可以存在不同的模块中。一个py模块就是一个类,可以这么理解

为了避免类的冲突,引入包的概念。注意每一个包下面,都会有一个init.py的文件,他的模块名就是包名

作用域

  • 正常的函数和变量名是公开的(public),可以被直接引用,比如:abc,x123,PI等;

  • 类似_xxx和xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,abc等;

之所以我们说,private函数和变量“不应该”被直接引用,而不是“不能”被直接引用,是因为Python并没有一种方法可以完全限制访问private函数或变量,但是,从编程习惯上不应该引用private函数或变量。

命令行运行
在命令行运行py文件时,Python解释器把一个特殊变量name置为main
因此以下代码

1
2
if __name__=='__main__':
test()

$ python hello.py运行时,会执行test(),但是import时不会执行

安装第三方模块

安装pip
使用pip安装,可在命令行检查输入pip,检查是否安装。
如果安装不成功,可以直接去官网地址下载

下载完成之后,解压到一个文件夹,用CMD控制台进入解压目录,输入:

1
python setup.py install

然后输入pip命令,检测是否安装成功

安装PIL
PIL是一个图片处理库,而且是跨平台的。
当我们执行以下失败时

1
pip install PIL

换成

1
pip install pillow

然后引入时fom PIL import Image

在python2中使用python3

1
2
3

from __future__ import unicode_literals
from __future__ import division

2.x里的字符串用’xxx’表示str,Unicode字符串用u’xxx’表示unicode
在3.x中,所有字符串都被视为unicode,写u’xxx’和’xxx’是完全一致的,但是str就必须写成b’xxx’,来表示“二进制字符串”

面向对象编程

给对象发消息实际上就是调用对象对应的关联函数,我们称之为对象的方法(Method)。这里指明了方法跟函数概念上的区别

数据封装、继承和多态是面向对象的三大特点。

如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线,在Python中,实例的变量名如果以开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问

继承和多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#父类
class Animal(object):
def run(self):
print "Animal is running"

class Dog(Animal):
pass
class Cat(Animal):
pass

dog = Dog()
dog.run()
cat = Cat()
cat.run()

  • type(),来判断对象类型。

  • 通过内置的一系列函数,我们可以对任意一个Python对象进行剖析,拿到其内部的数据。

  • dir(),来获得一个对象的所有属性跟方法。

高级特性:多重继承,定制类,元类

动态绑定
动态绑定允许我们在程序运行的过程中动态给class加上功能,这在静态语言中很难实现

以下给一个实例绑定方法,其他实例没有这个方法:

1
2
3
4
5
6
7
8
# 给dog对象动态新增方法set_age

def set_age(self,age): #定义一个函数作为实例方法
self.age = age

dog.set_age = MethodType(set_age,dog,Dog)# 给实例绑定一个方法
dog.set_age(25)
print 'dog的age:%s' % dog.age

以下是给对象绑定方法,它的所有实例都会有这个方法

1
2
3
4
5
6
7
8
def set_price(self,price): #定义一个函数作为实例方法
self.price = price

Animal.set_price = MethodType(set_price,None,Animal)# 给类绑定一个方法
dog.set_price('200$')
cat.set_price('300$')
print dog.price
print cat.price

@property
类似java的get set,避免把属性直接暴露

1
2
3
4
5
6
7
8
9
class Student(object):

@property
def birth(self):
return self._birth

@birth.setter
def birth(self, value):
self._birth = value

多重继承

区别于java的单继承

1
2
3
4
class Dog(Mammal, RunnableMixin, CarnivorousMixin):
pass

这样Dog类就继承了Mammal类,RunnableMixin类,CarnivorousMixin类

定制类
__str__
__repr__
用法:

1
2
3
4
5
6
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name=%s)' % self.name
__repr__ = __str__

__iter__用法:
如果一个类想被用于for … in循环,类似list或tuple那样,就必须实现一个iter()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。

__getattr__
利用完全动态的getattr写一个链式调用

1
2
3
4
5
6
7
8
9
10
11
12
13
class Chain(object):
# class实例化调用
def __init__(self,path = ''):
self._pathh = path
# 调用Chain不存在的属性时
def __getattr__(self, path):
return Chain('%s/%s' % (self._pathh,path))
def __str__(self):
return self._pathh

print Chain().statu.v2.member.center
结果
/statu/v2/member/center

__call()__可以使对象被当成函数进行调用

使用元类

  • type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的
  • type()函数既可以返回一个对象的类型,又可以创建出新的类型

    1
    2
    3
    4
    5
    def fn(self, name='world'): # 先定义函数
    print('Hello, %s.' % name)
    Hello = type('Hello', (object,), dict(hello=fn)) # 创建Hello class
    h = Hello()
    h.hello()
  • metaclass
    控制类的创建行为,还可使使用这个,元类
    先定义metaclass,就可以创建类,最后创建实例。所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。

调试

  • try catach
  • assert 断言,类似于print,输出内容
  • logging.info(),可以指定输出的级别
    1
    2
    import logging
    logging.basicConfig(level=logging.INFO)

单元测试
被测试文件mydict.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding:utf-8 -*-
# 单元测试
class Dict(dict):

def __init__(self, **kw):
super(Dict, self).__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

我们需要写的测试代码mydict_test.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# -*- coding:utf-8 -*-
# 进行单元测试
import unittest
from mydict import Dict
class TestDict(unittest.TestCase):

def test_init(self):
d = Dict(a=1, b='test')
self.assertEquals(d.a, 1)
self.assertEquals(d.b, 'test')
self.assertTrue(isinstance(d, dict))

def test_key(self):
d = Dict()
d['key'] = 'value'
self.assertEquals(d.key, 'value')

def test_attr(self):
d = Dict()
d.key = 'value'
self.assertTrue('key' in d)
self.assertEquals(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

def setUp(self):
print 'setUp...开始测试'

def tearDown(self):
print 'tearDown...测试结束'