python属性_深入理解python对象及属性

类属性和实例属性

首先来看看类属性和类实例的属性在python中如何存储,通过__dir__方法来查看对象的属性

>>> class Test(object):

pass

>>> test = Test(http://www.my516.com)

# 查看类属性

>>> dir(Test)

['__class__','__delattr__','__dict__','__doc__','__format__',

'__getattribute__', '__hash__', '__init__', '__module__',

'__new__', '__reduce__', '__reduce_ex__', '__repr__',

'__setattr__', '__sizeof__', '__str__', '__subclasshook__',

'__weakref__']

# 查看实例属性

>>> dir(test)

['__class__', '__delattr__', '__dict__', '__doc__', '__format__',

'__getattribute__', '__hash__', '__init__', '__module__',

'__new__', '__reduce__', '__reduce_ex__', '__repr__',

'__setattr__', '__sizeof__', '__str__', '__subclasshook__',

'__weakref__']

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

我们主要看一个属性__dict__,因为 __dict__保存的对象的属性,看下面一个例子

>>> class Spring(object):

... season = "the spring of class"

...

# 查看Spring类保存的属性

>>> Spring.__dict__

dict_proxy({'__dict__': ,

'season': 'the spring of class',

'__module__': '__main__',

'__weakref__': ,

'__doc__': None})

# 通过两种方法访问类属性

>>> Spring.__dict__['season']

'the spring of class'

>>> Spring.season

'the spring of class'

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

发现__dict__有个’season’键,这就是这个类的属性,其值就是类属性的数据.

接来看,看看它的实例属性

>>> s = Spring()

# 实例属性的__dict__是空的

>>> s.__dict__

{}

# 其实是指向的类属性

>>> s.season

'the spring of class'

# 建立实例属性

>>> s.season = "the spring of instance"

# 这样,实例属性里面就不空了。这时候建立的实例属性和类属性重名,并且把它覆盖了

>>> s.__dict__

{'season': 'the spring of instance'}

>>> s.__dict__['season']

'the spring of instance'

>>> s.season

'the spring of instance'

# 类属性没有受到实例属性的影响

>>> Spring.__dict__['season']

'the spring of class'

>>> Spring.__dict__

dict_proxy({'__dict__': , 'season': 'the spring of class', '__module__': '__main__', '__weakref__': , '__doc__': None})

# 如果将实例属性删除,又会调用类属性

>>> del s.season

>>> s.__dict__

{}

>>> s.season

'the spring of class'

# 自定义实例属性,对类属性没有影响

>>> s.lang = "python"

>>> s.__dict__

{'lang': 'python'}

>>> s.__dict__['lang']

'python'

# 修改类属性

>>> Spring.flower = "peach"

>>> Spring.__dict__

dict_proxy({'__module__': '__main__',

'flower': 'peach',

'season': 'the spring of class',

'__dict__': , '__weakref__': , '__doc__': None})

>>> Spring.__dict__['flower']

'peach'

# 实例中的__dict__并没有变化

>>> s.__dict__

{'lang': 'python'}

# 实例中找不到flower属性,调用类属性

>>> s.flower

'peach'

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

下面看看类中包含方法,__dict__如何发生变化

# 定义类

>>> class Spring(object):

... def tree(self, x):

... self.x = x

... return self.x

...

# 方法tree在__dict__里面

>>> Spring.__dict__

dict_proxy({'__dict__': ,

'__weakref__': ,

'__module__': '__main__',

'tree': ,

'__doc__': None})

>>> Spring.__dict__['tree']

# 建立实例,但是__dict__中没有方法

>>> t = Spring()

>>> t.__dict__

{}

# 执行方法

>>> t.tree("xiangzhangshu")

'xiangzhangshu'

# 实例方法(t.tree('xiangzhangshu'))的第一个参数(self,但没有写出来)绑定实例 t,透过 self.x 来设定值,即给 t.__dict__添加属性值。

>>> t.__dict__

{'x': 'xiangzhangshu'}

# 如果没有将x 赋值给 self 的属性,而是直接 return,结果发生了变化

>>> class Spring(object):

... def tree(self, x):

... return x

>>> s = Spring()

>>> s.tree("liushu")

'liushu'

>>> s.__dict__

{}

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

需要理解python中的一个观点,一切都是对象,不管是类还是实例,都可以看成是对象,符合object.attribute ,都会有自己的属性

使用__slots__优化内存使用

默认情况下,python在各个实例中为名为__dict__的字典里存储实例属性,而字典会消耗大量内存(字典要使用底层散列表提升访问速度), 通过__slots__类属性,在元组中存储实例属性,不用字典,从而节省大量内存

# 在类中定义__slots__属性就是说这个类中所有实例的属性都在这儿了,如果几百万个实例同时活动,能节省大量内存

>>> class Spring(object):

... __slots__ = ("tree", "flower")

...

# 仔细看看 dir() 的结果,还有__dict__属性吗?没有了,的确没有了。也就是说__slots__把__dict__挤出去了,它进入了类的属性。

>>> dir(Spring)

['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'flower', 'tree']

>>> Spring.__slots__

('tree', 'flower')

# 实例化

>>> t = Spring()

>>> t.__slots__

('tree', 'flower')

# 通过类赋予属性值

>>> Spring.tree = "liushu"

# tree这个属性是只读的, 实例不能修改

>>> t.tree = "guangyulan"

Traceback (most recent call last):

File "", line 1, in

AttributeError: 'Spring' object attribute 'tree' is read-only

>>> t.tree

'liushu'

# 对于用类属性赋值的属性,只能用来修改

>>> Spring.tree = "guangyulan"

>>> t.tree

'guangyulan'

# 对于没有用类属性赋值的属性,可以通过实例来修改

>>> t.flower = "haitanghua"

>>> t.flower

'haitanghua'

# 实例属性的值并没有传回到类属性,你也可以理解为新建立了一个同名的实例属性

>>> Spring.flower

# 如果再给类属性赋值

>>> Spring.flower = "ziteng"

>>> t.flower

'ziteng'

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

如果使用的当,__slots__可以显著节省内存,按需要注意一下问题

在类中定义__slots__之后,实例不能再有__slots__所列名称之外的其他属性

每个子类都要定义__slots__熟悉,因为解释器会忽略继承__slots__属性

如果不把__werkref__加入__slots__,实例不能作为弱引用的目标

属性的魔术方法

来看几个魔术方法

__setattr__(self,name,value):如果要给 name 赋值,就调用这个方法。

__getattr__(self,name):如果 name 被访问,同时它不存在的时候,此方法被调用。

__getattribute__(self,name):当 name被访问时自动被调用(注意:这个仅能用于新式类),无论 name 是否存在,都要被调用。

__delattr__(self,name):如果要删除 name,这个方法就被调用。

>>> class A(object):

... def __getattr__(self, name):

... print "You use getattr"

... def __setattr__(self, name, value):

... print "You use setattr"

... self.__dict__[name] = value

# a.x,按照本节开头的例子,是要报错的。但是,由于在这里使用了__getattr__(self, name) 方法,当发现 x 不存在于对象的__dict__中的时候,就调用了__getattr__,即所谓“拦截成员”。

>>> a = A()

>>> a.x

You use getattr

# 给对象的属性赋值时候,调用了__setattr__(self, name, value)方法,这个方法中有一句 self.__dict__[name] = value,通过这个语句,就将属性和数据保存到了对象的__dict__中

>>> a.x = 7

You use setattr

# 测试__getattribute__(self,name)

>>> class B(object):

... def __getattribute__(self, name):

... print "you are useing getattribute"

... return object.__getattribute__(self, name)

# 返回的内容用的是 return object.__getattribute__(self, name),而没有使用 return self.__dict__[name]。因为如果用这样的方式,就是访问 self.__dict__,只要访问这个属性,就要调用`getattribute``,这样就导致了无限递归

# 访问不存在的成员,可以看到,已经被__getattribute__拦截了,虽然最后还是要报错的。

>>> b = B()

>>> b.y

you are useing getattribute

Traceback (most recent call last):

File "", line 1, in

File "", line 4, in __getattribute__

AttributeError: 'B' object has no attribute 'y'

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

Property函数

porperty可以作为装饰器使用把方法标记为特性

class Vector(object):

def __init__(self, x, y):

# 使用两个前导下划线,把属性标记为私有

self.__x = float(x)

self.__y = float(y)

# porperty装饰器把读值方法标记为特性

@property

def x(self):

return self.__x

@property

def y(self):

return self.__y

vector = Vector(3,4)

print(vector.x, vector.y)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

使用property可以将函数封装为属性

class Rectangle(object):

"""

the width and length of Rectangle

"""

def __init__(self):

self.width = 0

self.length = 0

def setSize(self, size):

self.width, self.length = size

def getSize(self):

return self.width, self.length

if __name__ == "__main__":

r = Rectangle()

r.width = 3

r.length = 4

print r.getSize() # (3,4)

r.setSize( (30, 40) )

print r.width # 30

print r.length # 40

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

这段代码可以正常运行,但是属性的调用方式可以改进,如下:

class Rectangle(object):

"""

the width and length of Rectangle

"""

def __init__(self):

self.width = 0

self.length = 0

def setSize(self, size):

self.width, self.length = size

def getSize(self):

return self.width, self.length

# 使用property方法将函数封装为属性,更优雅

size = property(getSize, setSize)

if __name__ == "__main__":

r = Rectangle()

r.width = 3

r.length = 4

print r.size # (30, 40)

r.size = 30, 40

print r.width # 30

print r.length # 40

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

使用魔术方法实现:

class NewRectangle(object):

def __init__(self):

self.width = 0

self.length = 0

def __setattr__(self, name, value):

if name == 'size':

self.width, self, length = value

else:

self.__dict__[name] = value

def __getattr__(self, name):

if name == 'size':

return self.width, self.length

else:

raise AttrubuteErrir

if __name__ == "__main__":

r = Rectangle()

r.width = 3

r.length = 4

print r.size # (30, 40)

r.size = 30, 40

print r.width # 30

print r.length # 40

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

属性的获取顺序

最后我们来看看熟悉的获得顺序:通过实例获取其属性,如果在__dict__中有相应的属性,就直接返回其结果;如果没有,会到类属性中找。

看下面一个例子:

class A(object):

author = "qiwsir"

def __getattr__(self, name):

if name != "author":

return "from starter to master."

if __name__ == "__main__":

a = A()

print a.author # qiwsir

print a.lang # from starter to master.

1

2

3

4

5

6

7

8

9

10

当 a = A() 后,并没有为实例建立任何属性,或者说实例的__dict__是空的。但是如果要查看 a.author,因为实例的属性中没有,所以就去类属性中找,发现果然有,于是返回其值 “qiwsir”。但是,在找 a.lang的时候,不仅实例属性中没有,类属性中也没有,于是就调用了__getattr__()方法。在上面的类中,有这个方法,如果没有__getattr__()方法呢?如果没有定义这个方法,就会引发 AttributeError,这在前面已经看到了。

---------------------

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/434178.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 类型转换_java中的基本数据类型的转换

本文参考了如下两篇文章:Java中,经常可以遇到类型转换的场景,从变量的定义到复制、数值变量的计算到方法的参数传递、基类与派生类间的造型等,随处可见类型转换的身影。Java中的类型转换在Java编码中具有重要的作用。首先,来了解下…

Activity的四种加载模式(转载)

在多Activity开发中,有可能是自己应用之间的Activity跳转,或者夹带其他应用的可复用Activity。可能会希望跳转到原来某个Activity实例,而不是产生大量重复的Activity。这需要为Activity配置特定的加载模式,而不是使用默认的加载模…

cubieboard 将linux debian 系统灌入Nand中的操作记录

下载地址:http://guillaumeplayground.net:81/share/debian_wheezy_armhf_v1_mele.img.gz 首先在WIN系统下使用Win32diskimager将debian_wheezy_armhf_v1_mele.img刷到TF卡中,然后把TF卡放入CB的TF卡槽,加电启动。 因为Debian已经自带了SS…

centos 安装tomcat_简单介绍Linux配置mysql,tomcat,Nginx 开机自启动的几个方式

概述一般我们打算把一些服务,例如 mysql,tomcat,Nginx设置开机自启动的话一般是有三四种方式来实现,下面以mysql,tomcat,Nginx做例子来演示。一、使用定时任务 cron 命令创建定时任务来运行 .sh 脚本。在sh…

java 永久代_Java新生代、老生代和永久代详解

前言: 还是面试经常被q,小结一下image.pngJVM中的堆一般分为三部分,新生代、老年代和永久代。1 新生代主要是用来存放新生的对象。一般占据堆空间的1/3,由于频繁创建对象,所以新生代会频繁触发MinorGC进行垃圾回收。新生代分为Ede…

java算法:冒泡排序

java算法:冒泡排序 冒泡排序:不断遍历文件,交换倒序的相邻元素,直到文件排好顺序。冒泡排序的主要优点是容易实现,冒泡排序通常会比选择排序、插入排序慢。 如,对EXAMPLE 字母进行排序: E X…

python3发布时间_Python3优雅操作-时间处理与定时任务

无论哪种编程语言,时间肯定都是非常重要的部分,今天来看一下python如何来处理时间和python定时任务 注意:本篇所讲是python3版本的实现,在python2版本中的实现略有不同 1.计算明天和昨天的日期 #! /usr/bin/env python #codingutf…

Cubieboard安装Debian在Nand中

本教程所附带系统为Server版,不带显示,所以插显示器是不会有任何画面出现的。另外所提供系统为 http://linux-sunxi.org 所推荐(linux-sunxi.org的权威毋庸置疑),非CB官方提供,但CB官方并未提供相关CB所用Server版,而且…

strlwr,strupr函数

函数原型&#xff1a;extern char *strlwr(char *str) extern char *strupr(char *s) 参数说明&#xff1a;str为要转换的字符串。 所在库名&#xff1a;#include <string.h> 函数功能&#xff1a;将字符串str中的大(小)写字母转换成为小(大)写字母&#xff…

为Cubieboard打造完美Debian系统

作为Cubieboard的用户&#xff0c;最头疼的问题就是没有一个比较好的系统&#xff0c;本文将帮你解决这个问题。 首先需要感谢网站http://guillaumeplayground.net/的作者制作了这个系统。不过由于是定制给mele的&#xff0c;所以在Cubieboard上运行需要做一些优化调整。 系统…

python中的类怎样理解_理解Python数据类:Dataclass fields 的概述(下)

原标题 Understanding Python Dataclasses?—?Part 2 &#xff0c;作者为 Shikhar Chauhan 。这是 Python 最新的 Dataclasses 系列的第二部分内容。在第一部分里&#xff0c;我介绍了 dataclasses 的一般用法。这篇主要介绍另一个特征&#xff1a;dataclasses.field。我们已…

java 图形处理库_java中处理图片的类库

拷贝一下代码&#xff0c;以后备用&#xff1a;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.PrintWriter;import java.util.ArrayList;import java.util.List;import javax.servlet.ServletException;import javax.servle…

Hibernate @OneToMany等注解设置查询过滤条件等

如实体PdOrg对象中有users对象&#xff0c;数据库user表有字段DEL_FLAG(0&#xff1a;删除&#xff1b;1&#xff1a;未删除)&#xff1a; private List<User> users new ArrayList<User>(); 生成get、set方法&#xff1a; OneToMany(fetchFetchType.LAZY, mappedB…

西部数码域名解析到阿里云_西部数码云主机好吗 稳定性如何

随着云计算技术的不断发展&#xff0c;我国云计算市场的经济效益也在日渐扩大&#xff0c;各个云服务商之间的竞争异常激烈。在这种环境下&#xff0c;备受人们关注的云服务企业主要呈现两大类&#xff0c;一是互联网巨头背景的阿里云、腾讯云等&#xff1b;二是以西部数码为代…

ffmpeg yasm not found, use --disable-yasm for a crippled build

yasm是汇编编译器&#xff0c;因为ffmpeg中为了提高效率用到了汇编指令&#xff0c;比如MMX和SSE。解决这个问题方面有两个&#xff1a;1、在网上下载一个yasm.exe并安装在mingw/bin下面&#xff0c;编译代码时你注意看&#xff0c;会发现asm后缀的文件用的编译器是yasm&#x…

java native 接口_Java本地接口--Java Native Interface (JNI)

一、方法介绍java native方法是指本地方法&#xff0c;当在方法中调用一些不是由java语言写的代码或者在方法中用java语言直接操纵计算机硬件时要声明为native方法。java中&#xff0c;通过JNI(Java Native Interface,java本地接口)来实现本地化。Native方法一般用于两种情况&a…

【转】android程序连接网络出现android.os.NetworkOnMainThreadExceptionat

错误&#xff1a; android.os.NetworkOnMainThreadException at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099) ...... 原因&#xff1a;是涉及到url操作的时候&#xff0c;访问网络不能在主程序中运行 解决&#xff1a;参考【http://geeksu…

mysql8.0.22安装步骤图解_MySQL server 5.5的安装 步骤图解

作者&#xff1a;极客小俊 一个专注于web技术的80后我不用拼过聪明人&#xff0c;我只需要拼过那些懒人 我就一定会超越大部分人!知乎极客小俊&#xff0c;官方首发原创文章还有人用老版本的mysql 5.5吗&#xff1f;&#xff1f; 如果有的话 并且不会安装的小白看下面的步骤图吧…

win7下ffmpeg编译动态链接库整理

1.写在ffmpeg编译前 关于ffmpeg的编译过程google一搜&#xff0c;一大堆&#xff0c;ffmpeg编译真的有那么难么&#xff1f;在我编译成功后回头来看&#xff0c;网上的资料过多&#xff0c;反而使自己走了很多的弯路。即便有些楼主亲自测试后编译成功了&#xff0c;由于受机器…

inputstream java_Java实现inputstream流的复制

获取到一个inputstream后&#xff0c;可能要多次利用它进行read的操作。由于流读过一次就不能再读了&#xff0c;而InputStream对象本身不能复制&#xff0c;而且它也没有实现Cloneable接口&#xff0c;所以得想点办法。实现思路&#xff1a;1、先把InputStream转化成ByteArray…