Life Since 1985

Happy Hacking

python新式类的继承方式

最近在读《python学习手册》,发现python新式类的继承方式很有意思,而且据说在python3.0里面所有的类都将变成新式类,在此让同是跟我一样在Python2.x入门的人尝个鲜。

在python的普通中类中,继承的模式是深度优先的,也就是说对于一个对象的搜索遵循从左至右、从下到上的原则,而这从下到上的原则又优于从左至右。发觉语言上的描述十分晦涩,举个例子吧。

# -*- coding:utf-8 -*-
class A():
    """
    作为所有类的基类
    """
    value = 1
    
    def __init__(self, ):
        """
        """
        
class B(A):
    """
    D的基类,继承自A
    """
    
    def __init__(self, ):
        """
        """

class C(A):
    """
    D的基类,继承自A
    并且将基类中的变量值修改
    """
    value = 3
    
    def __init__(self, ):
        """
        """
        
class D(B, C):
    """
    """
    
    def __init__(self, ):
        """
        """
        
x = D()
print x.value

对于以上的代码输出的结果将是1。

因为对于经典类来说,在类D中调用对象value,首先要查找类D中是否有value,如果没有则按顺序查找B->A->C。它是一种广度优先的查找方式,所以首先会在基类A中查找到对象value,然后输出1。

以下是新式类的例子:

# -*- coding:utf-8 -*-
class A(object):
    """
    作为所有类的基类
    """
    value = 1
    
    def __init__(self, ):
        """
        """
        
class B(A):
    """
    D的基类,继承自A
    """
    
    def __init__(self, ):
        """
        """

class C(A):
    """
    D的基类,继承自A
    并且将基类中的变量值修改
    """
    value = 3
    
    def __init__(self, ):
        """
        """
        
class D(B, C):
    """
    """
    
    def __init__(self, ):
        """
        """
        
x = D()
print x.value

对于这个例子输出的结果将是3。

因为基类A继承于object,而所有继承于object的类都将是新式类。对于新式类来说,在类D中调用对象value,它首先查找的依然是类D。如果没有查找到的话,他会依次查找B->C->A。在我看来,它是一种按层查找的原则,会在较低层查找对象,如果没有的话再到较高层查找。所以对于这个例子来说,value在类C中被查找到,所以它的值将会是3。

这种继承方式的查找还是挺有意思的,我本人是比较喜欢新式类的继承方式,因为毕竟如果在继承类中有对于基类中对象的修改,那么这种修改应该是有意义的,而经典类的继承方式就有可能因为基类顺序的问题将这种有意义的修改屏蔽掉,所以还是新式类会比较好一些。而对于python语言的发展来说,python3.0以后所有的类继承方式都将是新式类的继承,也就说所有的类都将是新式类,所以这种继承方式也是我们有必要去掌握的。

115诡异的乱码

今天下载115网盘的资源,文件名一堆乱码,以前就出现过这种状况。其实也不是乱码,仔细看了一下应该是用%分隔的unicode码。反正也是闲的没事自己就用python写了一个恢复正常文件名的小程序,还算比较简单,主要就是读取文件名,然后将文件名按照%分隔,再手动设置一个溢出判断,超出两个字符就算溢出,溢出的部分和在文件名中的位置偏移另存,然后转换为字符就行了,最后将转换完的文件名存储。

python确实比较方便啊,不过十几二十行的代码而已,要是这个程序用c 或者java写的话……

# -*- coding:gb2312 -*-
F = open('datafile')
s = F.readlines()
s = [c.rstrip() for c in s]
ls = [c.split('%') for c in s]
result  = []
for c in ls:
    del c[0]
    isLarge = False
    sTag = None
    nTag = None
    n = -1
    for i in c:
        n = n + 1
        if len(i) > 2:
            isLarge = True
            sTag = i[2:]
            c[n] = i[:2]
            nTag = n + 1
            #print sTag
            #print nTag
    c = ['0x' + p for p in c]
    c = [eval(p) for p in c]
    c = [chr(p) for p in c]
    if isLarge == True:
        c.insert(nTag, sTag)
    result.append(''.join(c) + '\n')
    #print c

F.close()
F = open('myfile', 'w')
F.writelines(result)
'''
for i in result:
    print i
'''

str() VS repr()

        内建函数str()和repr()可以方便地以字符串的方式获取对象的内容、类型、数值属性等信息。

       str()函数得到的字符串可读性好,而repr()函数得到的字符串通常可以用来重新获得该对象,通常情况下obj == eval(repr(obj)) 这个等式是成立的。这两个函数接受一个对象作为其参数,返回适当的字符串。

>>> str(4.53-2j)
'(4.53-2j)'
>>>
>>> str(1)
'1'
>>>
>>> str(2e10)
'20000000000.0'
>>>
>>> str([0, 5, 9, 9])
'[0, 5, 9, 9]'
>>>
>>> repr([0, 5, 9, 9])
'[0, 5, 9, 9]'
>>>
>>> `[0, 5, 9, 9]`
'[0, 5, 9, 9]'

        尽管str()和repr()运算在特性和功能方面都非常相似,事实上repr返回的是一个对象的“官方”字符串表示,也就是说绝大多数情况下可以通过求 值运算(使用内建函数eval())重新得到该对象,但str()则有所不同。str()致力于生成一个对象的可读性好的字符串表示,它的返回结果通常无 法用于eval()求值,但很适合用于print语句输出。需要再次提醒的是,并不是所有repr()返回的字符串都能够用 eval()内建函数得到原来的对象。

>>> eval(`type(type))`) 
File "<stdin>", line 1
eval(`type(type))`)
^  
SyntaxError:invalid syntax

        也就是说 repr() 输出对 Python比较友好,而str()的输出对用户比较友好。虽然如此,很多情况下这三者的输出仍然都是完全一样的。

python中文支持

在开头进行编码声明:

# -*- coding:gb2312 -*-

在声明之后就可以使用中文字符了,即便不用在字符串之前声明位unicode编码也不会出现乱码了。