python进行描述性统计分析,python怎么做描述性统计

大家好,小编为大家解答python语言的描述错误的选项的问题。很多人还不知道描述python代码的编码规范,现在让我们一起来看看吧!

本文主要介绍描述符的定义,个人的一些理解;什么是数据描述符;什么是非数据描述符;描述符的检测等。希望看完这篇文章后,你对描述符有了更清晰的认识智能仿写软件。知道怎么判断一个对象是不是描述符,知道如果定义一个描述符,知道什么是该用描述符。当然,最大的目的是,通过学习描述符,让你对python这门语言有更多深入的认识。

什么是描述符

官方的定义:描述符是一种具有“捆绑行为”的对象属性。访问(获取、设置和删除)它的属性时,实际是调用特殊的方法(_get_(),_set_(),_delete_())。也就是说,如果一个对象定义了这三种方法的任何一种,它就是一个描述符。
更多的理解:

通常情况下,访问一个对象的搜索链是怎样的?比如a.x,首先,应该是查询 a._dict_['x'],然后是 type(a)._dict_['x'],一直向上知道元类那层止(不包括元类)。如果这个属性是一个描述符呢?那 python 就会“拦截”这个搜索链,取而代之调用描述符方法(_get_)。
三个方法(协议):

_get_(self, instance, owner) —获取属性时调用,返回设置的属性值,通常是 _set_ 中的 value,或者附加的其他组合值。

_set_(self, instance, value) — 设置属性时调用,返回 None.

_delete_(self, instance) — 删除属性时调用,返回 None

其中,instance 是这个描述符属性所在的类的实体,而 owner 是描述符所在的类。

数据描述符(data deor)和非数据描述符(non-data deors)

数据描述符:定义了 _set__get_ 方法的对象
非数据描述符:只定义了 _get_ 方法的对象。通常方法都是非数据描述符。比如后面会谈到的 staticmethod,classmethod 等。
区别:

1、位于搜索链上的顺序。搜索链(或者优先链)的顺序大概是这样的:数据描述符 > 实体属性(存储在实体的 _dict_ 中)>非数据描述符。
这个顺序初看起来挺晦涩。解释如下:
获取一个属性的时候:
首先,看这个属性是不是一个数据描述符,如果是,就直接执行描述符的get,并返回值。
其次,如果这个属性不是数据描述符,那就按常规去从dict里面取。
最后,如果dict里面还没有,但这是一个非数据描述符,则执行非数据描述符的get方法,并返回。
举例如下:

Python
class NoDataDesc(object): def __get__(self, instance, owner): print "nodatadesc.attr" return instance.freq*2 class DataDesc(object): def __get__(self, instance, owner): print "datadesc.attr" return instance.freq*4 def __set__(self, instance, value): print "set:datadesc.attr" instance.doc_freq = instance.freq*value def __delete__(self, instance): print "del datadesc.attr" raise BaseException class Test(object): data_result = DataDesc() nodata_result = DataDesc() def __init__(self,freq,data,nodata): self.freq = freq self.data_result = data self.nodata_result = nodata test = Test(3,-1,-1) print test.nodata_result #print test.data_result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class NoDataDesc ( object ) :
     def __get__ ( self , instance , owner ) :
         print "nodatadesc.attr"
         return instance . freq * 2
 
class DataDesc ( object ) :
     def __get__ ( self , instance , owner ) :
         print "datadesc.attr"
         return instance . freq * 4
     def __set__ ( self , instance , value ) :
         print "set:datadesc.attr"
         instance . doc_freq = instance . freq * value
     def __delete__ ( self , instance ) :
         print "del datadesc.attr"
         raise BaseException
 
class Test ( object ) :
 
     data_result = DataDesc ( )
     nodata_result = DataDesc ( )
     def __init__ ( self , freq , data , nodata ) :
         self . freq = freq
         self . data_result = data
         self . nodata_result = nodata
 
test = Test ( 3 , - 1 , - 1 )
print test . nodata_result
#print test.data_result

注释 print test.data_result 的时候打印的是:

Python
set:datadesc.attr -1(这个值是实体的值,相当于打印test._dict_["nodata_result"]) set:datadesc.attr 是 self.data_result = data 时打印的。
1
2
3
4
5
6
set : datadesc . attr
- 1(这个值是实体的值,相当于打印 test . _dict_ [ "nodata_result" ])
set : datadesc . attr 是
self . data_result = data
时打印的。

注释 print test.nodata_result 的输出:

Python
set:datadesc.attr datadesc.attr 12(这个是描述符 _set_ 中设置的值。相当于 data_result._get_(test,3),返回的是 12)
1
2
3
4
5
set : datadesc . attr
datadesc . attr
12(这个是描述符 _set _ 中设置的值。相当于 data_result . _get_ ( test , 3 ),返回的是 12)
 

谈到这个搜索链的顺序,稍微再引申一下。问一个问题:

如果 Test 这个类还有 _getattr_ , _getattribute_ 呢?

这里就不多介绍 _getattr_,_getattribute_(每一个都可以另外再起一篇文章了)。熟悉的记住一点就行:

getattribute 优先级是最高的,而 getattr 是最低的。

如何检测一个对象是不是描述符

如果把问题换成——一个对象要满足什么条件,它才是描述符呢——那是不是回答就非常简单了?

答:只要定义了( set , get , delete )方法中的任意一种或几种,它就是个描述符。

那么,继续问:怎么判断一个对象定义了这三种方法呢?
立马有人可能就会回答:你是不是傻啊?看一下不就看出来了。。。
问题是,你看不到的时候呢?python 内置的 staticmethodclassmethod 怎么看?

正确的回答应该是:看这个对象的 _dict_

写到这里,我得先停一下,来解释一个问题。不知道读者有没有发现,上面我一直再说“对象”,“对象”,而实际上指的明明是一个类啊?博主是不是搞错了呢?嗯,作为一名入门语言是java(抛开只玩过,没写过软件的C)的程序猿,把类称之为对象,的确让我本人也有点别扭。但是,在 python 中,这样称呼又是妥当的。因为,“一切皆对象”,类,不过也是元类的一种对象而已。
跑了下题,接着说。要看对象的 _dict_ 好办,直接 dir(对象)就行了。现在可以写出检测对象是不是描述符的方法了:

Python
def has_deor_attrs(obj): return set(['__get__', '__set__', '__delete__']).interp(dir(obj)) def is_deor(obj): """obj can be instance of deor or the deor class""" return bool(has_deor_attrs(obj)) def has_data_deor_attrs(obj): return set(['__set__', '__delete__']) &set(dir(obj)) def is_data_deor(obj): return bool(has_data_deor_attrs(obj))
1
2
3
4
5
6
7
8
9
10
11
12
13
def has_deor_attrs ( obj ) :
     return set ( [ '__get__' , '__set__' , '__delete__' ] ) . interp ( dir ( obj ) )
 
def is_deor ( obj ) :
     """obj can be instance of deor or the deor class"""
     return bool ( has_deor_attrs ( obj ) )
 
def has_data_deor_attrs ( obj ) :
     return set ( [ '__set__' , '__delete__' ] ) & set ( dir ( obj ) )
 
def is_data_deor ( obj ) :
     return bool ( has_data_deor_attrs ( obj ) )

测试一下:

Python
print is_deor(classmethod), is_data_deor(classmethod) print is_deor(staticmethod), is_data_deor(staticmethod) print is_data_deor(property) # 输出: (True, False) (True, False) True
1
2
3
4
5
6
7
8
9
10
print is_deor ( classmethod ) , is_data_deor ( classmethod )
print is_deor ( staticmethod ) , is_data_deor ( staticmethod )
print    is_data_deor ( property )
 
# 输出:
 
( True , False )
( True , False )
True

看来,特性(property)是数据描述符

描述符有什么用和好处

1)一般情况下不会用到,建议:先定基本的,以后真有需要再扩展。别贪玩。
2)可以在设置属性时,做些检测等方面的处理
3)缓存?
4)设置属性不能被删除?那定义delete方法,并raise 异常。
5)还可以设置只读属性
6)把一个描述符作为某个对象的属性。这个属性要更改,比如增加判断,或变得更复杂的时候,所有的处理只要在描述符中操作就行了。

老实说,博主也想不出太多描述符使用的场景,举不出什么例子来。希望有人能帮忙补充。不甚感激。

例子

1、一个学校类,学校类又一个学生属性,赋给这个属性的值是一个json格式的字符串。需要json解析。现在是要处理学校很多学生的数据。要求:不能因为某个学生属性有问题而导致其他学生的数据有问题。并且这个学生属性所在这条记录要保存,对于它的属性,置空。

代码如下:

Python
class Student(object): def __init__(self): self.inst = {} def __get__(self, instance, owner): return self.inst[instance] def __set__(self, instance, value): try: self.inst[instance] = json.loads(value) except ValueError,e: print "error" self.inst[instance] = "" def __delete__(self, instance): raise BaseException class School(object): student = Student() def __init__(self,tid,title,student): self.tid = tid self.name = title self.student = student def main(): lst = [] for i in xrange(10): student = '{"aturbo":{"english":"100","math":"100"}}' if i ==1: student = '{"sansan":{"english":"40","scid":"20"}}' if i == 3: #print i student ='{"sansan"}' scl = School(str(i),"fege",student) lst.append(scl) for info in lst: print info.tid,':',info.student if __name__ =="__main__": main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Student ( object ) :
     def __init__ ( self ) :
         self . inst = { }
     def __get__ ( self , instance , owner ) :
         return self . inst [ instance ]
 
     def __set__ ( self , instance , value ) :
         try :
             self . inst [ instance ] = json . loads ( value )
         except ValueError , e :
             print "error"
             self . inst [ instance ] = ""
 
     def __delete__ ( self , instance ) :
         raise BaseException
 
class School ( object ) :
     student = Student ( )
     def __init__ ( self , tid , title , student ) :
         self . tid = tid
         self . name = title
         self . student = student
 
def main ( ) :
     lst = [ ]
     for i in xrange ( 10 ) :
         student = '{"aturbo":{"english":"100","math":"100"}}'
         if i == 1 :
             student = '{"sansan":{"english":"40","scid":"20"}}'
         if i == 3 :
             #print i
             student = '{"sansan"}'
         scl = School ( str ( i ) , "fege" , student )
         lst . append ( scl )
 
     for info in lst :
         print info . tid , ':' , info . student
 
if __name__ == "__main__" :
     main ( )

打印结果:

0 : {u’aturbo’: {u’math’: u’100’, u’english’: u’100’}}
1 : {u’sansan’: {u’scid’: u’20’, u’english’: u’40’}}
2 : {u’aturbo’: {u’math’: u’100’, u’english’: u’100’}}
3 :
4 : {u’aturbo’: {u’math’: u’100’, u’english’: u’100’}}
5 : {u’aturbo’: {u’math’: u’100’, u’english’: u’100’}}
6 : {u’aturbo’: {u’math’: u’100’, u’english’: u’100’}}
7 : {u’aturbo’: {u’math’: u’100’, u’english’: u’100’}}
8 : {u’aturbo’: {u’math’: u’100’, u’english’: u’100’}}
9 : {u’aturbo’: {u’math’: u’100’, u’english’: u’100’}}

注意两点:
1)tid为1这条的取值,tid=3这条的取值
2)这样定义Student这个描述符也可以:

Python
class Student(object): def __get__(self, instance, owner): return instance.value def __set__(self, instance, value): try: instance.value = json.loads(value) except ValueError,e: print "error" instance.value = "" def __delete__(self, instance): raise BaseException
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Student ( object ) :
     def __get__ ( self , instance , owner ) :
         return instance . value
 
     def __set__ ( self , instance , value ) :
         try :
             instance . value = json . loads ( value )
         except ValueError , e :
             print "error"
             instance . value = ""
 
     def __delete__ ( self , instance ) :
         raise BaseException

这样呢:

Python
class Student(object): def __get__(self, instance, owner): return self.value def __set__(self, instance, value): try: self.value = json.loads(value) except ValueError, e: print "error" self.value = ""
1
2
3
4
5
6
7
8
9
10
11
class Student ( object ) :
         def __get__ ( self , instance , owner ) :
             return self . value
 
         def __set__ ( self , instance , value ) :
             try :
                 self . value = json . loads ( value )
             except ValueError , e :
                 print "error"
                 self . value = ""

也正确,但 student 变成类成员,不会是实体成员,打印的结果会全部一样(都是:{u’aturbo’: {u’math’: u’100’, u’english’: u’100’}})

总结
你可能还从没有在实际工作中写过一个描述符,甚至觉得今后也极少有机会会用的。但是,不可避免地,你每天(只要是在写python代码)都或多或少的要和描述符打交道。要非常好的理解描述符并不是一件容易的事,希望这篇这篇文章能够在一定程度上帮到你。相信我,好好理解下描述符会让你对python的认识提高不少。

Python
# coding:utf-8 import numbers """ 如果把问题换成——一个对象要满足什么条件,它才是描述符呢——那是不是回答就非常简单了? 答:只要定义了(_set_,_get_,_delete_)方法中的任意一种或几种,它就是个描述符。 数据描述符(data deor)和非数据描述符(non-data deors) 数据描述符:定义了_set_ 和_get_方法的对象 非数据描述符:只定义了_get_方法的对象。通常方法都是非数据描述符。比如后面会谈到的staticmethod,classmethod等。 描述符有什么用和好处 1)一般情况下不会用到,建议:先定基本的,以后真有需要再扩展。别贪玩。 2)可以在设置属性时,做些检测等方面的处理 3)缓存? 4)设置属性不能被删除?那定义_delete_方法,并raise 异常。 5)还可以设置只读属性 6)把一个描述符作为某个对象的属性。这个属性要更改,比如增加判断,或变得更复杂的时候,所有的处理只要在描述符中操作就行了。 老实说,博主也想不出太多描述符使用的场景,举不出什么例子来。希望有人能帮忙补充。不甚感激。 https://blog.youkuaiyun.com/Allenalex/article/details/54097319 """ class IntField: """属性描述符""" def __set__(self, instance, value): if not isinstance(value, numbers.Integral): raise ValueError("Integral value need") if value < 0: raise ValueError("value must positive") self.value = value def __get__(self, instance, owner): return self.value def __delete__(self, instance): del self.value class NotDataIntField: """非数据描述符""" def __get__(self, instance, owner): return self.value class User: age = IntField() # age = NotDataIntField() if __name__ == '__main__': user = User() user.age = 30 print(getattr(user,'age')) print(user.age) print(user.__dict__) # 30 # 30 # {} """ getattr(user,'age')) 和 user.age 是等价的 如果user是某个类的实例,那么user.age(以及等价的getattr(user,’age’)) 首先调用__getattribute__。如果类定义了__getattr__方法, 那么在__getattribute__抛出 AttributeError 的时候就会调用到__getattr__, 而对于描述符(__get__)的调用,则是发生在__getattribute__内部的。 user = User(), 那么user.age 顺序如下: (1)如果“age”是出现在User或其基类的__dict__中, 且age是data deor, 那么调用其__get__方法, 否则 (2)如果“age”出现在user的__dict__中, 那么直接返回 obj.__dict__[‘age’], 否则 (3)如果“age”出现在User或其基类的__dict__中 (3.1)如果age是non-data deor,那么调用其__get__方法, 否则 (3.2)返回 __dict__[‘age’] (4)如果User有__getattr__方法,调用__getattr__方法,否则 (5)抛出AttributeError """
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# coding:utf-8
import numbers
"""
如果把问题换成——一个对象要满足什么条件,它才是描述符呢——那是不是回答就非常简单了?
答:只要定义了(_set_,_get_,_delete_)方法中的任意一种或几种,它就是个描述符。
 
数据描述符(data deor)和非数据描述符(non-data deors)
数据描述符:定义了_set_ 和_get_方法的对象
非数据描述符:只定义了_get_方法的对象。通常方法都是非数据描述符。比如后面会谈到的staticmethod,classmethod等。
 
 
描述符有什么用和好处
1)一般情况下不会用到,建议:先定基本的,以后真有需要再扩展。别贪玩。
2)可以在设置属性时,做些检测等方面的处理
3)缓存?
4)设置属性不能被删除?那定义_delete_方法,并raise 异常。
5)还可以设置只读属性
6)把一个描述符作为某个对象的属性。这个属性要更改,比如增加判断,或变得更复杂的时候,所有的处理只要在描述符中操作就行了。
老实说,博主也想不出太多描述符使用的场景,举不出什么例子来。希望有人能帮忙补充。不甚感激。
 
https://blog.youkuaiyun.com/Allenalex/article/details/54097319
"""
 
class IntField :
     """属性描述符"""
     def __set__ ( self , instance , value ) :
         if not isinstance ( value , numbers . Integral ) :
             raise ValueError ( "Integral value need" )
         if value < 0 :
             raise ValueError ( "value must positive" )
         self . value = value
 
     def __get__ ( self , instance , owner ) :
         return self . value
 
     def __delete__ ( self , instance ) :
         del self . value
 
class NotDataIntField :
     """非数据描述符"""
     def __get__ ( self , instance , owner ) :
         return self . value
 
 
class User :
     age = IntField ( )
     # age = NotDataIntField()
 
if __name__ == '__main__' :
     user = User ( )
     user . age = 30
     print ( getattr ( user , 'age' ) )
     print ( user . age )
     print ( user . __dict__ )
     # 30
     # 30
     # {}
 
"""
getattr(user,'age')) 和 user.age 是等价的
 
如果user是某个类的实例,那么user.age(以及等价的getattr(user,’age’))
首先调用__getattribute__。如果类定义了__getattr__方法,
那么在__getattribute__抛出 AttributeError 的时候就会调用到__getattr__,
而对于描述符(__get__)的调用,则是发生在__getattribute__内部的。
user = User(), 那么user.age 顺序如下:
 
(1)如果“age”是出现在User或其基类的__dict__中, 且age是data deor, 那么调用其__get__方法, 否则
 
(2)如果“age”出现在user的__dict__中, 那么直接返回 obj.__dict__[‘age’], 否则
 
(3)如果“age”出现在User或其基类的__dict__中
 
(3.1)如果age是non-data deor,那么调用其__get__方法, 否则
 
(3.2)返回 __dict__[‘age’]
 
(4)如果User有__getattr__方法,调用__getattr__方法,否则
 
(5)抛出AttributeError
 
 
"""

建议看看这 https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/

 

 
  • zeropython 微信公众号 5868037 QQ号 5868037@qq.com QQ邮箱
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值