【3.1.1】认识python的类

断断续续的写过几个类之后,对类有了一些基本的认知。突然认识到去年年初的时候,小龚看了我的代码,来了一句,我靠,你的class里面怎么都是staticmethod呀?

一、类的属性

要知道一个类有哪些属性,有两种方法。最简单的是使用 dir() 内建函数。另外是通过访问类的字典属性 dict

	>>> dir(MyClass)
	['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__form
	at__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__',
	 '__lt__', '__module__', '__ne__', '__new__', '__qualname__', '__reduce__', '__r
	educe_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook
	__', '__weakref__', 'myVersion', 'showMyVersion']

	>>> MyClass.__dict__
	mappingproxy({'__module__': '__main__', '__qualname__': 'MyClass', '__weakref__'
	: <attribute '__weakref__' of 'MyClass' objects>, 'showMyVersion': , '__dict__': <attribute '__dict__' of 'MyClass ' objects>, 'myVersion': '1.1', '__doc__': 'MyClass class definition'})
	dir() 返回的仅是对象的属性的一个名字类表,而 __dict__

返回的是一个字典,它的键(key)是属性名,键值(value)是相应的属性对象的数据值。

特殊的类属性

C.__name__	类C的名字(字符串)
C.__doc__	        类C的文档字符串
C.__bases__	        类C的所有父类构成的元组
C.__dict__	        类C的属性
C.__module__	        类C定义所在的模块
C.__class__	        实例C对应的类
__name__ 是给定类的字符名字。它适用于那种只需要字符串(类对象的名字),而非对象本身的情况。
__doc__是类的文档字符串,与函数及模块的文档字符串相似,必须紧随头行后的字符串。文档字符串不

能被派生类继承,也就是说派生类必须含有他们自己的文档字符串。__bases__用来处理继承,它包含了一个由所有父类组成的元组。__dict__属性包含一个字典,由类的数据属性组成。

	>>> MyClass.__name__
	'MyClass'
	>>> MyClass.__doc__
	'MyClass class definition'
	>>> MyClass.__bases__
	(<class 'object'>,)
	>>> print(MyClass.__dict__)
	{'__module__': '__main__', '__qualname__': 'MyClass', '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, 'showMyVersion': , '__dict__': <attribute '__dict__' of 'MyClass' objects>, '
	myVersion': '1.1', '__doc__': 'MyClass class definition'}

一、classmethod和staticmethod区别

类和实例都是对象.

所以它们可以有方法.

类的方法就叫类方法.

实例的方法就叫实例方法.

至于静态方法就是写在类里的方法,必须用类来调用(极少数情况下使用,一般都在全局里直接写函数了)

class Kls(object):
    def __init__(self, data):
        self.data = data
    def printd(self):
        print(self.data)
    @staticmethod
    def smethod(*arg):
        print('Static:', arg)
    @classmethod
    def cmethod(*arg):
        print('Class:', arg)

	>>> ik = Kls(23)
	>>> ik.printd()
	23
	>>> ik.smethod()
	Static: ()
	>>> ik.cmethod()
	Class: (<class '__main__.Kls'>,)
	>>> Kls.printd()
	TypeError: unbound method printd() must be called with Kls instance as first argument (got nothing instead)
	>>> Kls.smethod()
	Static: ()
	>>> Kls.cmethod()
	Class: (<class '__main__.Kls'>,)
	class Data_test2(object):
	    day=0
	    month=0
	    year=0
	    def __init__(self,year=0,month=0,day=0):
	        self.day=day
	        self.month=month
	        self.year=year

	    @classmethod
	    def get_date(cls,data_as_string):
	        #这里第一个参数是cls, 表示调用当前的类名
	        year,month,day=map(int,string_date.split('-'))
	        date1=cls(year,month,day)
	        #返回的是一个初始化后的类
	        return date1

	    def out_date(self):
	        print "year :"
	        print self.year
	        print "month :"
	        print self.month
	        print "day :"
	        print self.day

在Date_test类里面创建一个成员函数, 前面用了@classmethod装饰。 它的作用就是有点像静态类,比静态类不一样的就是它可以传进来一个当前类作为第一个参数。

r=Data_test2.get_date("2016-8-6")
r.out_date()
输出:

year :
2016
month :
8
day :
1

案例

import os
os.chdir('E:\\py\\chapter6')

def sanitize(time_string):
    if '-' in time_string:
        splitter='-'
    elif ':' in time_string:
        splitter=':'
    else:
        return(time_string)
    (mins,secs)=time_string.split(splitter)
    return(mins +'.' + secs)

class Athlete:
    def __init__(self,a_name,a_dob=None,a_times=[]):
        self.name=a_name
        self.dob=a_dob
        self.times=a_times
    def top3(self):
        return(sorted(set([sanitize(t) for t in self.times]))[0:3])
    def add_time(self,time_value):
        self.times.append(time_value)
    def add_times(slef,list_of_times):
        self.times.extend(list_of_times)
        

def get_coach_data(filename):
    try:
        with open(filename) as f:
            data=f.readline()
            templ=data.strip().split(',')
            return(Athlete(templ.pop(0),templ.pop(0),templ))
    except IOError as ioerr:
        print('File error:' +str(ioerr))
        return(None)


sarah=get_coach_data('sarah2.txt')
print(sarah.name+"'s fastest times are:"+str(sarah.top3()))

也可调用内置的类,建立类的父子关系

import os
os.chdir('E:\\py\\chapter6')

def sanitize(time_string):
    if '-' in time_string:
        splitter='-'
    elif ':' in time_string:
        splitter=':'
    else:
        return(time_string)
    (mins,secs)=time_string.split(splitter)
    return(mins +'.' + secs)

class Athlete(list):
    def __init__(self,a_name,a_dob=None,a_times=[]):
        list.__init__([])
        self.name=a_name
        self.dob=a_dob
        self.extend(a_times)
    def top3(self):
        return(sorted(set([sanitize(t) for t in self]))[0:3])
    

def get_coach_data(filename):
    try:
        with open(filename) as f:
            data=f.readline()
            templ=data.strip().split(',')
            return(Athlete(templ.pop(0),templ.pop(0),templ))
    except IOError as ioerr:
        print('File error:' +str(ioerr))
        return(None)


sarah=get_coach_data('sarah2.txt')
print(sarah.name+"'s fastest times are:"+str(sarah.top3()))

参考资料

药企,独角兽,苏州。团队长期招人,感兴趣的都可以发邮件聊聊:tiehan@sina.cn
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn