python小记(5)

静态方法和类方法

先看下面的代码

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

class Foo(object):        #Python 3: class Foo:
    one = 0

    def __init__(self):
        Foo.one = Foo.one + 1

def get_class_attr(cls):
    return cls.one

if __name__ == "__main__":
    f1 = Foo()
    print "f1:",Foo.one        #Python 3: print("f1:"+str(Foo.one)),下同,从略
    f2 = Foo()
    print "f2:",Foo.one

    print get_class_attr(Foo)

在上述代码中,有一个函数get_class_attr(),这个函数的参数我用cls,从函数体的代码中看,要求它引用的对象应该具有属性one,这就说明,不是随便一个对象就可以的。恰好,就是这么巧,我在前面定义的类Foo中,就有one这个属性。于是乎,我在调用这个函数的时候,就直接将该类对象传给了它get_class_attr(Foo)

其运行结果如下:

f1: 1
f2: 2
2

在这个程序中,函数get_class_attr()写在了类的外面,但事实上,函数只能调用前面写的那个类对象,因为不是所有对象都有那个特别的属性的。所以,这种写法,使得类和函数的耦合性太强了,不便于以后维护。这种写法是应该避免的。避免的方法就是把函数与类融为一体。于是就有了下面的写法。

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

class Foo(object):    #Python 3: class Foo:
    one = 0

    def __init__(self):
        Foo.one = Foo.one + 1

    @classmethod
    def get_class_attr(cls):
        return cls.one

if __name__ == "__main__":
    f1 = Foo()
    print "f1:",Foo.one
    f2 = Foo()
    print "f2:",Foo.one

    print f1.get_class_attr()
    print "f1.one",f1.one
    print Foo.get_class_attr()

    print "*"* 10
    f1.one = 8
    Foo.one = 9
    print f1.one
    print f1.get_class_attr()
    print Foo.get_class_attr()

在这个程序中,出现了@classmethod——装饰器——在函数那部分遇到过了。需要注意的是@classmethod所装饰的方法的参数中,第一个参数不是self,这是和我们以前看到的类中的方法是有区别的。这里我使用了参数cls,你用别的也可以,只不过习惯用cls

再看对类的使用过程。先贴出上述程序的执行结果:

f1: 1
f2: 2
2
f1.one 2
2
**********
8
9
9

分别建立两个实例,此后类属性Foo.one的值是2,然后分别通过实例和类来调用get_class_attr()方法(没有显示写cls参数),结果都相同。

当修改类属性和实例属性,再次通过实例和类调用get_class_attr()方法,得到的依然是类属性的结果。这说明,装饰器@classmethod所装饰的方法,其参数cls引用的对象是类对象Foo

至此,可以下一个定义了。

所谓类方法,就是在类里面定义的方法,该方法由装饰器@classmethod所装饰,其第一个参数cls所引用的是这个类对象,即将类本身作为引用对象传入到此方法中。

理解了类方法之后,用同样的套路理解另外一个方法——静态方法。还是先看代码——一个有待优化的代码。

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

T = 1

def check_t():
    T = 3
    return T 

class Foo(object):        #Python 3: class Foo:
    def __init__(self,name):
        self.name = name

    def get_name(self):
        if check_t():
            return self.name
        else:
            return "no person"

if __name__ == "__main__":
    f = Foo("canglaoshi")
    name = f.get_name()
    print name        #Python 3: print(name)

先观察上面的程序,发现在类Foo里面使用了外面定义的函数check_t()。这种类和函数的关系,也是由于有密切关系,从而导致程序维护有困难,于是在和前面同样的理由之下,就出现了下面比较便于维护的程序。

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

T = 1

class Foo(object):        #Python 3: class Foo:
    def __init__(self,name):
        self.name = name

    @staticmethod
    def check_t():
        T = 1
        return T

    def get_name(self):
        if self.check_t():
            return self.name
        else:
            return "no person"

if __name__ == "__main__":
    f = Foo("canglaoshi")
    name = f.get_name()
    print name        #Python 3: print(name)

经过优化,将原来放在类外面的函数,移动到了类里面,也就是函数check_t()现在位于类Foo的命名空间之内了。但是,不是简单的移动,还要在这个函数的前面加上@staticmethod装饰器,并且要注意的是,虽然这个函数位于类的里面,跟其它的方法不同,它不以self为第一个参数。当使用它的时候,可以通过实例调用,比如self.check_t();也可以通过类调用这个方法,比如Foo.check_t()

从上面的程序可以看出,尽管check_t()位于类的命名空间之内,它却是一个独立的方法,跟类没有什么关系,仅仅是为了免除前面所说的维护上的困难,写在类的作用域内的普通函数罢了。但,它的存在也是有道理的,以上的例子就是典型说明。当然,在类的作用域里面的时候,前面必须要加上一个装饰器@staticmethod。我们将这种方法也给予命名,称之为静态方法。

方法,是类的重要组成部分。本节专门讲述了方法中的几种特殊方法,它们为我们使用类的方法提供了更多便利的工具。但是,类的重要特征之一——继承,还没有亮相。

时间: 2024-12-13 16:45:33

python小记(5)的相关文章

python小记(3)

使用with 在对文件进行写入操作之后,一定要牢记一个事情:file.close(),这个操作千万不要忘记,忘记了怎么办,那就补上吧,也没有什么天塌地陷的后果. 有另外一种方法,能够不用这么让人揪心,实现安全地关闭文件. >>> with open("130.txt","a") as f: ... f.write("\nThis is about 'with...as...'") ... >>> with op

python小记--格式化输出

python print格式化输出. 1. 打印字符串 print ("His name is %s"%("Aviad")) 效果: 2.打印整数 print ("He is %d years old"%(25)) 效果: 3.打印浮点数 print ("His height is %f m"%(1.83)) 效果: 4.打印浮点数(指定保留小数点位数) print ("His height is %.2f m&qu

[python小记]使用lxml修改xml文件,并遍历目录

这次的目的是遍历目录,把目标文件及相应的目录信息更新到xml文件中.在经过痛苦的摸索之后,从python自带的ElementTree投奔向了lxml.而弃用自带的ElementTree的原因就是,namespace. XML命名空间 作用是为避免元素命名冲突,当出现命名冲突的时候,可以使用前缀来避免命名冲突,就如: <h:table> <h:tr> <h:td>App Store</h:td> <h:td>Google Play</h:td

python小记--解释器

Cpython     linux 自带的解释器,用C语言写的,应该是最常用的python解释器了 Ipython      基于Cpython的交互式解释器 Pypy          使用JIT技术,能对python代码进行动态编译(而不是编译),显著提高代码执行速度,几乎兼容Cpython的代码,如果想让你的python程序快起来,就用它吧 Jpython    Java语言写的python ironpython  用C#语言写的python

python小记(4)

在Python 3中,你可以使用nonlocal关键词,如下演示. 1 def foo(): 2 a = 1 3 def bar(): 4 nonlocal a 5 a = a + 1 6 print("bar()a=",a) 7 bar() 8 print("foo()a=",a) 9 10 foo() 11 #output 12 #bar()a= 2 13 #foo()a= 2

python小记-1

在Python中,能够直接处理的数据类型有以下几种: 1.整数 多采用16进制,由0x 前缀.0-9.a-f 组成.例:0xff00 2.浮点数(小数) 科学计数法写法:1.23x10^9 ——> 1.23e+9 3.字符串 用 ' '/" "括起来的任意文本 (1)如果字符串内部既包含'又包含",可以用转义字符\来标识,比如: 'I\'m \"OK\"!' 为了简化,Python还允许用r''表示''内部的字符串默认不转义 如果字符串内部有很多换行

Python小记5

接https://www.cnblogs.com/airlinp/p/12516653.html 8. 循环 8.1 Python程序的三个流程方式 顺序 — 从上往下,顺序执行代码: 分支 — 根据判断条件,决定代码执行的分支: 循环 — 让指定代码重复执行: 8.2 while 8.1 while基本语法 初始条件 - 计数器初始化 while 条件(判断计数器是否达到目标): 条件满足,执行事件1 条件满足,执行事件2 条件满足,执行事件3 … 处理条件(计数器+1) 有上可知: 初始条件

Python小记

赛选回文数 def is_palindrome(num): return num > 9 and str(num) == str(num)[::-1] output = filter(is_palindrome,range(1,10000)) print(list(output)) 对L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]分别按名字和分数排序 L = [('Bob', 75), ('Adam', 92), ('Bar

python小记(1)

“*” 字符串中的“乘法”,这个乘法,就是重复那个字符串的含义.在某些时候很好用的.比如我要打印一个华丽的分割线: >>> str1*3 'abcdabcdabcd' >>> print "-"*20 #不用输入很多个`-` --------------------