python面向对象变成进阶篇
1. 类成员之–字段
字段类型:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同,
- 普通字段属于对象,每创建一个实例就会在内存中保存一个
- 静态字段属于类,类在初始化的时候就创建了,无论后来创建了多少个实例,在内存中只有一份
字段的调用:静态字段可以通过对象或者类进行访问,但是普通字段只能通过对象进行调用访问
1.1 一般静态字段用法示例:
class Province(object):
country = 'china'#可以通过实例的id来感受,所有实例的country属性id都是相同的
def __init__(self,name):
self.name = name
def showProvince(self):
print self.name,self.country
p = Province('Qinghai')
print p.country
\# 通过实例访问静态字段
print Province.country
\# 通过类直接访问静态字段
应用场景: 通过类创建对象时,如果每个对象都具有相同的字段,那么就使用静态字段,内存占用就会降低
1.2 私有静态字段:
__private_attrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中调用: self.__private_attrs。
class Province(object):
__country = 'china'
def __init__(self,name):
self.name = name
def showProvince(self):
print self.name,self.__country
p = Province('Qinghai')
#print p.__country 或者 #print p.country
#上边调用会报错,因为私有字段不能在类的外部通过实例被访问
p.showProvince()
#可以通过方法来显示类的私有属性,且只能通过方法显示!!!
#print Province.__country 或者 #print Province.country
#上边调用会报错,因为私有字段不能在类的外部通过类来进行访问
print pq._Province__country
#强制访问私有字段
如果想要强制访问私有字段,可以通过 【对象.类名_私有字段明 】访问(如:obj._C__foo),不建议强制访问私有成员。
2. 类成员之–方法
类成员方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
静态方法:由类调用;无默认参数;
类方法:
class DateTest(object):
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
def show(self):
return 'year:{} \nmonth:{}\nday:{}'.format(self.year,self.month,self.day)
@classmethod
#类方法的格式,一个装饰器
def get_str_date(cls,s):
yeara, montha, daya= map(int, s.split('-'))
dateout = cls(yeara,montha,daya)
return dateout
d = DateTest.get_str_date('2017-09-05')
print d.show()
静态方法:
class DateTest(object):
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
def show(self):
return 'year:{} \nmonth:{}\nday:{}'.format(self.year,self.month,self.day)
@classmethod
def get_str_date(cls,s):
if cls.is_valid_date(s):
yeara, montha, daya= map(int, s.split('-'))
dateout = cls(yeara,montha,daya)
return dateout
raise Exception("Invalid date!")
@staticmethod
#静态方法的格式,也是一个装饰器
def is_valid_date(s):
yeara, montha, daya = map(int, s.split('-'))
return yeara >=1970 and 1<=montha<=12 and 1<=daya<=31
try:
d = DateTest.get_str_date('2017-19-05')
print d.show()
except:
print 'Failed to create date!'
相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
不同点:方法调用者不同、调用方法时自动传入的参数不同。
3. 类成员之–属性
Python中的属性其实是普通方法的变种。
由属性的定义和调用要注意一下几点:
定义时,在普通方法的基础上添加 @property 装饰器;
定义时,属性仅有一个self参数
调用时,无需括号
方法:foo_obj.func()
属性:foo_obj.prop
注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象
属性由方法变种而来,如果Python中没有属性,方法完全可以代替其功能。
实例:对于主机列表页面,每次请求不可能把数据库中的所有内容都显示到页面上,而是通过分页的功能局部显示,所以在向数据库中请求数据时就要显示的指定获取从第m条到第n条的所有数据(即:limit m,n),这个分页的功能包括:
根据用户请求的当前页和总数据条数计算出 m 和 n
根据m 和 n 去数据库中请求数据
Python的属性的功能是:属性内部进行一系列的逻辑计算,最终将计算结果返回。
class Pager:
def __init__(self, current_page):
# 用户当前请求的页码(第一页、第二页...)
self.current_page = current_page
# 每页默认显示10条数据
self.per_items = 10
@property
def start(self):
val = (self.current_page - 1) * self.per_items
return val
@property
def end(self):
val = self.current_page * self.per_items
return val
p = Pager(1)
print p.start,p.end
#根据传入的当前页数,然后返回下一次的起始页
#1 10
p1 = Pager(2)
print p1.start,p1.end
#10 20
注:经典类中的属性只有一种访问方式,其对应被 @property 修饰的方法
新式类中的属性有三种访问方式,并分别对应了三个被@property、@方法名.setter、@方法名.deleter修饰的方法
由于新式类中具有三种访问方式,我们可以根据他们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除
4. 类的特殊成员 __str__
如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
如果没有定义__str__方法的话则输出类型以及内存地址
class Halo:
def __str__(self):
return 'lockey'
obj = Foo()
print obj