python学习——基础(七)
2015-10-23 00:00
671 查看
摘要: 模块、面向对象编程、面向对象特性编程
在Python中,一个.py文件就称之为一个模块(Module)。
使用模块有什么好处?
最大的好处是大大提高了代码的可维护性。其次,编写代码不必从零开始。当一个模块编写完毕,就可以被其他地方引用。我们在编写程序的时候,也经常引用其他模块,包括Python内置的模块和来自第三方的模块。
模块别名:
面向对象的访问限制:
在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑。
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问
需要注意的是,在Python中,变量名类似__xxx__
的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__
、__score__
这样的变量名。
有些时候,你会看到以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,当你看到这样的变量时,意思就是,“虽然我可以被访问,但是,请把我视为私有变量,不要随意访问”。
继承:
在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
如果要获得一个对象的所有属性和方法,可以使用dir()函数:
仅仅把属性和方法列出来是不够的,配合getattr()
、setattr()
以及hasattr()
,我们可以直接操作一个对象的状态:
使用__slots__
正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性
但是,如果我们想要限制class的属性怎么办?
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__
变量,来限制该class能添加的属性和方法
方法也是同样的;
使用__slots__要注意,__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的
使用@property
@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
第一处和第二处的name必须相同,第三处、第四处、第五处必须相同
新增的属性为name,不是__name
多重继承:
Mixin:在设计类的继承关系时,通常,主线都是单一继承下来的,如果需要“混入”额外的功能,通过多重继承就可以实现,这种设计通常称之为Mixin;python中的多重继承类似于java中的类组合;
在多重继承中,最大的问题就是当继承的父类中有同名的方法,这时的优先级问题:
从例子可以看出,遵从的是深度优先的准则;
定制类:
通过特殊变量,可以为我们定制类,如:__slots__,__len__,__str__等
__str__:
还有一个类似的__repr__;
两者的区别是__str__()
返回用户看到的字符串,而__repr__()
返回程序开发者看到的字符串,也就是说,__repr__()
是为调试服务的。
__iter__:
判断对象是否可以进行迭代:
如果需要使对象能够迭代,可以在类中定义__iter__方法:
Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
__getitem__
虽然能作用于for循环
,但是不能像list按照下标取出元素,需要实现__getitem__方法:
__getattr__
通过__getattr__动态的定义类的属性和方法;
或者:
__call__
一个对象实例可以有自己的属性和方法,
当我们调用实例方法时,我们用instance.method()来调用。能不能直接在实例本身上调用呢?类似instance()?在Python中,答案是肯定的。
任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用。请看示例:
__call__()
还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。
那么,怎么判断一个变量是对象还是函数呢?其实,更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个Callable对象,比如函数和我们上面定义的带有__call()__的类实例:
通过callable()
函数,我们就可以判断一个对象是否是“可调用”对象。
使用元类:
创建类有两种方法:自定义:class XXX,type(ClassName, parentClass, dict{fun,property})
要创建一个class对象,type()函数依次传入3个参数:
class的名称;
继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
class的方法名称与函数绑定,这里我们把函数fn绑定到方法名hello上。
通过type()
函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()
函数创建出class。
在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'
需要注意的是,在Python中,变量名类似__xxx__
的,也就是以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的,不是private变量,所以,不能用__name__
、__score__
这样的变量名。
有些时候,你会看到以一个下划线开头的实例变量名,比如_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']
仅仅把属性和方法列出来是不够的,配合getattr()
、setattr()
以及hasattr()
,我们可以直接操作一个对象的状态:
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的属性怎么办?
为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__
变量,来限制该class能添加的属性和方法
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,不是__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
还有一个类似的__repr__;
两者的区别是__str__()
返回用户看到的字符串,而__repr__()
返回程序开发者看到的字符串,也就是说,__repr__()
是为调试服务的。
__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]
,但是不能像list按照下标取出元素,需要实现__getitem__方法:
__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.
__call__()
还可以定义参数。对实例进行直接调用就好比对一个函数进行调用一样,所以你完全可以把对象看成函数,把函数看成对象,因为这两者之间本来就没啥根本的区别。
那么,怎么判断一个变量是对象还是函数呢?其实,更多的时候,我们需要判断一个对象是否能被调用,能被调用的对象就是一个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
通过callable()
函数,我们就可以判断一个对象是否是“可调用”对象。
使用元类:
创建类有两种方法:自定义: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上。
通过type()
函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()
函数创建出class。
相关文章推荐
- Python知识(1)----基础入门和进阶总结。
- python例子-Django之传递json到js脚本中。
- 谈谈 Python 程序的运行原理
- python问与答常识
- fedora下python3 安装tkinter和pygame
- python用法笔记(数组(list、touple、dict)、字符串)
- Python学习笔记 -- 第六章 文件操作
- opencv-python学习一--人脸检测
- python获取cookies
- python
- 安装easy_install,setuptool
- python装饰器学习笔记
- python os模块常用方法
- 优秀Python学习资源收集汇总
- 在win7下的简单的备份python脚本
- [No000028]Python的使用之禅及程序员应该明白的一些道理
- python内置函数大全
- python3中的range函数
- Getting started with machine learning in Python
- Python通过Manager方式实现多个无关联进程共享数据