Python语言学习笔记(三)
Python语言学习笔记(三)
面向对象高级编程
__slots__的使用
由于python允许程序动态绑定,如果我们想要限制实例的属性,我们可以在class定义时,定义一个特殊变量__slots__。比如,只允许对Student实例添加name和age属性:
|
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
|
这样,如果在类外动态添加属性,那么会报错。
另外__slots__定义的属性仅对当前类实例起作用,对继承的子类不起作用。
@property的使用
为了将类方法可以像类属性一样的方式来调用,python提供了内置的@property装饰器。来看下函数的API:
|
property(fget=None, fset=None, fdel=None, doc=None)
|
|
#1.
class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
#2.
class Student(object):
def score(self):
return self._score
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
60
|
实质上,这是通过getter和setter方法来实现的。
还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性。
参考:
@property如果要懂property,强烈建议看一下这篇。
定制类
1.__len__()
2.__str__()
by the print statement to compute the “informal” string representation of an object
3.__repr__
by string conversions (reverse quotes) to compute the “official” string representation of an object
|
#1.
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name=%s)' % self.name
Student object (name: Michael)
<__main__.Student object at 0x109afb310>
#2.
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name=%s)' % self.name
__repr__ = __str__
Student object (name: Michael)
|
4.__iter__
如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。
|
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 实例本身就是迭代对象,故返回自己
def __next__(self):
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 100000: # 退出循环的条件
raise StopIteration()
return self.a # 返回下一个值
...
1
1
2
3
5
...
46368
75025
|
5.__getitem__
6.__getattr__
7.__call__
参考:
定制类-廖雪峰
使用元类
type
python中,class的定义是运行时动态创建的,而创建class的方法就是使用type()函数。type()函数既可以返回一个对象的类型,又可以创建出新的类型。
|
type(object) -> the object's type
type(name, bases, dict) -> a new type
|
|
...
Hello, world.
|
要创建一个class对象,type()函数依次传入3个参数:
1. class的名称;
2. 继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
3. class的方法名称与函数绑定,这里我们把函数`fn`绑定到方法名`hello`上。
通过type()函数创建的类和直接写class是完全一样的,因为Python解释器遇到class定义时,仅仅是扫描一下class定义的语法,然后调用type()函数创建出class。
metaclass
除了使用type()动态创建类以外,要控制类的创建行为,还可以使用metaclass。
先定义metaclass,就可以创建类,最后创建实例。
|
# metaclass是类的模板,所以必须从`type`类型派生:
class ListMetaclass(type):
def __new__(cls, name, bases, attrs):
attrs['add'] = lambda self, value: self.append(value)
return type.__new__(cls, name, bases, attrs)
|
正常情况下会很少用到,但是总会遇到需要通过metaclass修改类定义的。ORM就是一个典型的例子。
可以直接去参考廖雪峰的教程
其他
自省
自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。一旦您使用了支持自省的编程语言,就会产生类似这样的感觉:“未经检查的对象不值得实例化。“
1.联机帮助(help())
2.sys模块
3.dir函数
4.文档字符串__doc__
5.检查python对象
名称:__name__,类型:type(),属性:hasattr()、getattr(),可调用:callable(),实例isinstance()、子类:issubclass()
参考:Python自省指南
装饰器@staticmethod和@classmethod
@staticmethod和@classmethod都可以直接类名.方法名()来调用(staticmethod也可以用实例名.方法名()来调用),那它们的区别在哪里呢?
|
class A(object):
bar = 1
def foo(self, x):
print ("executing foo(%s,%s)"%(self,x))
def class_foo(cls,x):
print ("executing class_foo(%s,%s)"%(cls,x))
print ("bar: %s" % cls.bar)
def static_foo(x):
print ("executing static_foo(%s)"%x)
print ("bar: %s" % A.bar)
a = A()
A.static_foo()
A.class_foo()
|
1.@classmethod的第一个参数必须是表示自身类的cls参数。而@staticmethod不需要self也不需要cls参数,就跟使用函数一样。
2.如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等。
参考:
装饰器@staticmethod和@classmethod有什么区别
__new__和__init__的区别
__init__方法为初始化方法,__new__方法才是真正的构造函数。
1、__new__方法默认返回实例对象供__init__方法、实例方法使用
2、__init__方法为初始化方法,为类的实例提供一些属性或完成一些动作
3、__new__方法创建实例对象供__init__方法使用,__init__方法定制实例对象。__new__ 方法必须返回值,__init__方法不需要返回值。(如果返回非None值就报错)
4、一般用不上__new__方法,__new__方法可以用在下面二种情况。
python中的单例模式
1.使用模块
2.使用__new__
3.使用装饰器(重点看看)
4.使用元类
请参考Python中的单例模式
python中的copy和deepcopy
1、赋值:简单地拷贝对象的引用,两个对象的id相同。
2、浅拷贝:创建一个新的组合对象,这个新对象与原对象共享内存中的子对象。
常见的浅拷贝有:切片操作、工厂函数如list()、对象的copy()方法、copy模块中的copy函数
3、深拷贝:创建一个新的组合对象,同时递归地拷贝所有子对象,新的组合对象与原对象没有任何关联。虽然实际上会共享不可变的子对象,但不影响它们的相互独立性。常见的深拷贝方式,只有copy模块中的deepcopy函数。
|
import copy
a = [1, 2, 3, 4, ['a', 'b']] #原始对象
b = a #赋值,传对象的引用
c = copy.copy(a) #对象拷贝,浅拷贝
d = copy.deepcopy(a) #对象拷贝,深拷贝
a.append(5) #修改对象a
a[4].append('c') #修改对象a中的['a', 'b']数组对象
print 'a = ', a
print 'b = ', b
print 'c = ', c
print 'd = ', d
输出结果:
a = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
b = [1, 2, 3, 4, ['a', 'b', 'c'], 5]
c = [1, 2, 3, 4, ['a', 'b', 'c']]
d = [1, 2, 3, 4, ['a', 'b']]
|
请参考赋值、浅拷贝、深拷贝
python的垃圾回收机制GC(Garbage Collection)
Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。
可参考Python垃圾回收机制

浙公网安备 33010602011771号