`

python class

阅读更多
引用
类是创建新对象类型的机制。
类定义了一组属性,这些属性与一组叫做实例的对象相关且由其共享。
类通常是由函数、变量和计算出的属性组成的集合。

类中最常用的就是构造方法析构方法
构造方法__init__(self,....)在生成对象时调用,可以用来进行一些初始化操作,不需要显示去调用,系统会默认去执行。
构造方法支持重载,如果用户自己没有重新定义构造方法,系统就自动执行默认的构造方法。
析构方法__del__(self)在释放对象时调用,支持重载,可以在里面进行一些释放资源的操作,不需要显示调用。
类方法(@classmethod)vs静态方法(@staticmethod)?
可以参考:
以前的总结链接:http://2057.iteye.com/blog/1826514
@classmethod 类方法第一个参数必须是cls。
普通的方法至少需要一个self参数,代表类对象实例。
类方法,有子类继承的时候,调用该类的方法,cls是子类,而不是父类。
使用@staticmethod修饰的静态方法对它所在class一无所知,它只是接受调用的参数。没有隐式的第一参数。使用@staticmethod在python中基本上没用,和把方法放到module文件中没什么区别。
而用@classmethod修饰的是类方法。 这种方法的第一个参数是他所在的类。当你想使用工厂模式时会很有用。你可以传一个指定类的子类给类方法,然后返回子类的实例。
如果在编写类时需要采用很多不同的方式来创建新实例,则常常使用静态方法。因为类中只能有一个__init__()函数。
继承
在继承基类的时候(__init__()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用。
super是一个内建类型,用来访问属于某个对象的超累中的特性(attribute)。
super的用法:

引用
首先我们理解方法解析顺序(MRO)才能更好的理解super的用法。
python的方法解析顺序。
MRO 描述了C3构建一个类的线性化(也成为优先级,即祖先的一个排序列表)的方法。这个列表被用于特性的查找。
MRO的变化用于解决创建公用基本类型(obejct)所引入的问题。
MRO是基于一个基类之上的递归调用。
L[MyClass(Base1, Base2)] = MyClass + merge(L[Base1],L[Base2],Base1,Base2)
L[MyClass]是MyClass类的线性化,而merge是合并多个线性化结果的具体算法。
综合的描述应该是:
C的线性化是C加上父类的线性化和父类列表的合并的综合。
merge算法负责删除重复项并保持正确的顺序。
取第一个列表的头,也就是L[Base1][0].如果这个头不在任何表的尾部,那么将它加到MyClass的线性化中,并且从合并中的列表里删除;否则查找下一个列表的头,如果是好的表头则取用它。
然后重复该操作,直到所有类都被删除或者不能找到好的表头。

head是列表的第一个元素,而tail则包含其余蒜素。
换句话说,C3在每个父类上进行递归深度查找以获得列表的顺序。然后当一个类设计多个列表时,计算一个从左到右的规则使用层次二义性消除来合并所有类表。

#!/usr/bin/env python
#-*-coding:utf-8-*-

class Base(object):

    def method(self):
        print 'Base'

class Base1(Base):
    pass

class Base2(Base):
    def method(self):
        print 'Base2'

class MyClass(Base1,Base2):
    pass

def L(klass):
    return [k.__name__ for k in klass.__mro__]

here = MyClass()
here.method()
print L(MyClass)

类的__mro__特性用来存储线性化计算的记过,计算将在类定义载入时完成。
还可以调用MyClass.mro()来计算并获得结果。

super的缺陷:
当使用了多重继承的层次结构时,再使用它将是相当危险的,这主要是因为类的初始化。
在Python中,基类不会在__init__中被隐式地调用,所以依靠开发人员来调用它们。
super方法的另一个问题是初始化中的参数传递。类在没有相同签名的情况下怎么调用基类的__init__代码?
修复的方法是用用*args和**kw魔法参数。这样,所有的构造程序将传递所有的参数,及时不使用它们。但是这是一个槽糕的修复方法,因为它使所有构造程序将接受任何类型的参数。这会导致代码变得很脆弱,因为任何参数都被传递并且通过。

为了避免上面所述的问题,必须考虑一下几点
1、应该避免多重继承
2、super的使用必须一致,在类层次机构中,应该在所有的地方都使用super或者彻底不使用它。混用super和传统调用是一种混乱的方法,人们倾向于避免使用super,这样代码会更明晰。
3、不要混用老式和新式的类 两者都具备的代码库将导致不同的MRO表现。
4、调用父类时必须检查类层次 为了避免出现任何问题,每次调用父类时,必须快速递查看一下所涉及的MRO(使用__mro__)。
描述符和属性
描述符用来自定义在引用一个对象上的特性时所应该完成的事情。
引用
描述符基于三个必须实现的特殊方法:
__set__  在任何特性被设置的时候调用,setter
__get__ 在任何特性被读取的时候调用,getter
__delete__在特性上请求del时调用

属性(Property)
可以参考
http://2057.iteye.com/blog/1826973
属性提供了一个内建的描述符类型,它知道如何讲一个特性链接到一组方法上。
属性采用fget参数和三个可选的参数(fset、fdel和doc).
槽(slots)
它允许使用__slots__特性为指定的类设置一个静态特性的列表,并且跳过每个类实例中__dict__列表中的创建工作。它们用来为特性很少的类节省存储空间,因为将不再每个实例中初见__dict__.
引用
在实际使用中,__slots__从未被当做一种安全的特性来实现。它实际上是对内存和执行速度的一种性能优化。使用__slots__的类的实例不再使用字典来存储实例数据。相反,会使用基于数组的更加紧凑的数据结构。在会创建大量对象的程序中,使用__slots__可以显著减少内存占用的执行时间。
注意,__slots__与继承的配合使用需要一定的技巧。如果类继承自使用__slots__的基类,那么它也需要定义__slots__来存储自己的属性(即使它不会添加任何属性也是如此)这样才能充分利用__slots提供的优势。如果忘记这一点,派生类的运行速度将更慢,占用的内存比未在任何类上使用__slots__时多。

元编程
new-style类带来了一种能力,可以通过两个特殊的方法__new__和__metaclass__在运行时修改类和对象的定义。
__new__方法 是一个构造程序,每当一个对象必须被factory类实例化时就将调用它。
__new__方法必须返回一个类的实例,因为它可以在对象创建之前或者之后修改类。
这样对于确保对象狗仔程序不会被设置成一个不希望的状态,或者添加一个不能被构造程序删除的初始化是有帮助的。
网络套接字或数据库初始化应该在__new__中而不是__init__中控制。它在类的工作必须完成这个初始化以及必须被继承的时候通知我们。
__new__是对于对象状态隐式初始化需求的回应。它是的可以在比__init__更低的层次上定义一个初始化,这个初始化纵使会被调用。
可以参考
http://2057.iteye.com/blog/1837026
__metaclass__方法
元类提供了在类对象通过其工厂方法(factory)在内存中创建时进行交互的能力。
它们的效果与__new__类似,只不过在类级别上运行。
__metaclass__特性必须被设置为:
接受和type相同的参数
返回一个类对象。
引用
它们有很强大的表现——可以动态地在已经被实例化的类定义上创建许多不同的变化。
在任何情况下,请记住元类或动态增强只是一种补丁,它可能会很快地使精心定义的、清晰的类层次结构变得一团糟。它们应该只在以下情况下使用:
在框架级别,一个行为在许多类中是强制的时候;
当一个特殊的行为被添加的目的不是与注入记录日志这样的类提供的功能交互时。

对象内存管理:
实例的创建包含两个步骤:使用特殊方法__new__()创建新实例,然后使用__init__()初始化该实例。
引用
类的__new__()方法很少通过用户代码定义。如果定义了它,它通常是用原型__new__(cls,*args,**kwargs)编写的,其中args和kwargs与传递给__init__()的参数相同。__new__()始终是一个类方法,接受类对象作为第一个参数。尽管__new__()会创建一个实例,但它不会自动调用__init__()方法。
如果看到在类中定义了__new__() 通常表明这个类会做两件事之一。首先,该类可能继承自一个基类,该基类的实例是不可变的。如果定义的对象继承自不变的内置类型(如整数、字符串或元组),常常会遇到这种情况,因为__new__()是唯一在创建实例之前执行的方法,也是唯一可以修改值的地方(也可以在__init__()中修改,但这时修改可能为时已晚)。

class Upperstr(str):
     def __new__(cls, value=''):
          return str.__new__(cls, value.upper())
u = Upperstr("hello") # 值为HELLO

__new__的另一个主要用途是在定义元类的时候使用。
参考资料:
http://stackoverflow.com/questions/12179271/python-classmethod-and-staticmethod-for-beginner
http://pythoncentral.org/difference-between-staticmethod-and-classmethod-in-python/

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics