在Python中,一个.py文件就称之为一个模块(Module)。
使用模块有什么好处?
最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。
模块别名:
try:
import cStringIO as StringIO
except ImportError: # 导入失败会捕获到ImportError
import StringIO
面向对象的访问限制:
在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
class Student(object):
def __init__(self, name):
self.__name = name
def getName(self):
return '实例变量:'+self.__name
stu1 = Student('syc')
print stu1.getName() # 实例变量:syc
print stu1.__name # AttributeError: type object 'Student' has no attribute '__name'
有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
继承:
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
class Animal(object):
def run(self):
print 'animail is running'
def eat(self):
print 'animail is eating'
class Horse(Animal):
def run(self):
print 'horse is running'
Animal.eat(self) # 子类中调用父类的方法
hs = Horse()
hs.run()
print type(hs)
结果:
horse is running
animail is eating
<class '__main__.Horse'>
如果要获得一个对象的所有属性和方法,可以使用dir()函数:
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'eat', 'run']
class Horse(object):
name = 'horse'
def run(self):
print 'horse is running'
Animal.eat(self) # 子类中调用父类的方法
hs = Horse()
print hasattr(hs, 'name') # 判断hs对象是否含有name属性,同样也可以进行方法的判断
setattr(hs, 'age', '18') # 增加的是实例变量,不能为对象设置新的方法
print getattr(hs, 'age') # 得到hs的age值,同时可以得到方法的变量
使用__slots__
正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性
class Student(object):
name = 'syc'
def drink(self):
print 'student is drunking'
stu = Student()
stu.age = 18 #给实例增加属性
print stu.age
Student.age =19 # 给类添加属性
print Student.age
def eat(self):
print 'student is eating'
from types import MethodType
stu.eat = MethodType(eat, stu, Student) # 给Student的实例stu添加方法
stu.eat()
stu2 = Student()
# print stu2.eat() # AttributeError: 'Student' object has no attribute 'eat'
Student.eat = MethodType(eat, None, Student) # 给类Student添加方法
stu2.eat()
class Student(object):
__slots__ = ('name', 'age', 'eat')
name = 'syc'
def drink(self):
print 'student is drunking'
stu = Student()
stu.address = 'fuzhou'
结果:AttributeError: 'Student' object has no attribute 'address'
方法也是同样的;
使用__slots__要注意,__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的
class Student(object):
__slots__ = ('name', 'age', 'eat')
name = 'syc'
def drink(self):
print 'student is drunking'
class SubStudent(Student):
pass
substu = SubStudent()
substu.address = 'fuzhou'
print substu.address # fuzhou
使用@property
@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
class Student(object):
@property
def aname(self): # 第一处
return self.__name
@aname.setter # 第二处
def name(self, name): # 第三处
# if name == 'syc':
# raise TypeError('name不能为syc')
self.__name = name
stu = Student()
stu.name = 'syc' # 第四处
print stu.name # 第五处
新增的属性为name,不是__name
多重继承:
Mixin:在设计类的继承关系时,通常,主线都是单一继承下来的,如果需要“混入”额外的功能,通过多重继承就可以实现,这种设计通常称之为Mixin;python中的多重继承类似于java中的类组合;
在多重继承中,最大的问题就是当继承的父类中有同名的方法,这时的优先级问题:
class Grandfa(object):
def hair(self):
print 'no hair'
class Father(Grandfa):
pass
class Mom(object):
def hair(self):
print 'hair'
class Tom(Father,Mom):
pass
tom = Tom()
tom.hair() # no hair 深度优先
定制类:
通过特殊变量,可以为我们定制类,如:__slots__,__len__,__str__等
__str__:
class Student(object):
pass
# def __str__(self):
# return 'a student instance'
stu = Student()
print stu # <__main__.Student object at 0x02634B90>
class Student(object):
# pass
def __str__(self):
return 'a student instance'
stu = Student()
print stu # a student instance
__iter__:
判断对象是否可以进行迭代:
class Student(object):
pass
from collections import Iterable
print isinstance(stu,Iterable) # False
如果需要使对象能够迭代,可以在类中定义__iter__方法:
class Student(object):
def __iter__(self):
return self
def next(self):
self.a, self.b = self.b, self.a + self.b
if self.b >100:
raise StopIteration()
return self.b
stu = Student()
from collections import Iterable
print isinstance(stu,Iterable) # True
stu.a, stu.b = 1,2
print [x for x in stu] # [3, 5, 8, 13, 21, 34, 55, 89]
Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
__getitem__
虽然能作用于for循环
class Student(object):
def __getitem__(self, n):
for x in range(n):
self.a, self.b = self.b, self.a + self.b
return self.b
stu = Student()
from collections import Iterable
print isinstance(stu,Iterable) # False
stu.a, stu.b = 1,2
print stu[1] # [3, 5, 8, 13, 21, 34, 55, 89]
__getattr__
通过__getattr__动态的定义类的属性和方法;
class Student(object):
def __init__(self, name):
self.name = name
def __getattr__(self, item):
if item == 'score': # 自动添加属性
return 99
if item =='getSocre': # 自动添加方法
return lambda :self.score * self.score
stu = Student('syc')
print stu.socre # None ==>当类定义了__getattr__时,即使没有定义socre,也不会报错:AttributeError: 'Student' object has no attribute 'socre'
print stu.score # 99
print stu.getSocre() # 9801
class Student(object):
def __init__(self, path=''):
self.__path = path
def __getattr__(self, item):
if item == "users":
return lambda user: Student("%s/users/:%s" % (self.__path, user))
else:
return Student("%s/%s" % (self.__path, item))
def __str__(self):
return self.__path
print Student().users('syc').repos # /users/:syc/repos
或者:
class Student(object):
def __init__(self, path=''):
self.__path = path
def __getattr__(self, item):
return Student("%s/%s" % (self.__path, item))
def __str__(self):
return self.__path
def __call__(self, name):
return Student("%s/:%s" % (self.__path, name))
print Student().users('syc').repos # /users/:syc/repos
__call__
一个对象实例可以有自己的属性和方法,
当我们调用实例方法时,我们用instance.method()来调用。能不能直接在实例本身上调用呢?类似instance()?在Python中,答案是肯定的。
任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用。请看示例:
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
s = Student('syc')
s() # My name is syc.
那么,怎么判断一个变量是对象还是函数呢?其实,更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,比如函数和我们上面定义的带有__call()__的类实例:
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
s = Student('syc')
print callable(s) # True
print callable([1, 2, 3]) # False
print callable('ABC') # False
print callable(None) # False
使用元类:
创建类有两种方法:自定义:class XXX,type(ClassName, parentClass, dict{fun,property})
def fn(self, name):
print 'Hello %s'% name
Hello = type('Hello', (object,), dict(hello=fn))
Hello().hello('world') # Hello world
要创建一个class对象,type()函数依次传入3个参数:
- class的名称;
- 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
- class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。