python中的类属性和实例属性
属性就是属于一个对象的数据或者函数,我们可以通过句点(.)来访问属性,同时 Python 还支持在运作中添加和修改属性。
我们先来看看类里面的普通字段:
class Test(object):
name = 'python' a = Test()
print Test.name # 通过类进行访问
print a.name # 通过实例进行访问
我们发现都是可以访问的。
但是,如果我们试图修改这个属性的话:
class Test(object):
name = 'python' a = Test()
Test.name = 'python good' # 通过类进行修改
print Test.name
print a.name
我们发现两者都修改成功了。
如果通过实例来修改属性的话:
class Test(object):
name = 'python' a = Test()
a.name = 'python good' # 通过实例进行修改
print Test.name
print a.name
我们发现类的属性没有修改,而实例的属性则修改成功了。这究竟是为什么?
其实这里的情况非常类似于局部作用域和全局作用域。
我在函数内访问变量时,会先在函数内部查询有没有这个变量,如果没有,就到外层中找。这里的情况是我在实例中访问一个属性,但是我实例中没有,我就试图去创建我的类中寻找有没有这个属性。找到了,就有,没找到,就抛出异常。而当我试图用实例去修改一个在类中不可变的属性的时候,我实际上并没有修改,而是在我的实例中创建了这个属性。而当我再次访问这个属性的时候,我实例中有,就不用去类中寻找了。
如果用一张图来表示的话:
函数 dir() 就能查看对象的属性:
class Test(object):
name = 'python' a = Test()
a.abc =
print dir(Test)
print dir(a)
它返回一个列表,包含所有能找到的属性的名字,这里我们为实例 a 创建了 abc 属性,这里就能看到了。
有些同学会有疑问,为什么我才写了几个属性,结果却多出一堆我不认识的?
因为我们这里用的是新式类,新式类继承于父类 object ,而这些我们没有写的属性,都是在 object 中定义的。
python3中不管有没有显示的去继承object,默认都会继承的
Python2中如果显示的继承object就是新式类,没有继承object就是经典类
如果我们用经典类的话:
为了方便演示,下面都使用经典类,若没有特殊说明,新旧两式基本是一样的。
其中 __doc__ 是说明文档,在类中的第一个没有赋值的字符串就是说明文档,一般在class的第二行写,没有就为空字符串。
__module__ 表示这个类来自哪个模块,我们在主文件中写的类,其值应该为 ‘__main__’,在其他模块中的类,其值就为模块名。
class Test:
"""文档字符串"""
name = 'scolia' print Test.__doc__
print Test.__module__
文档字符串不一定非要用三引号,只是一般习惯上用三引号表示注释。文档注释也可以使用字符串的形式,实例也可以访问,实际访问的是创建它的类的文档字符串,但是子类并不会继承父类的文档字符串,关于继承的问题以后再讲。
除了这两个特殊的属性之外,还有几个常用的,虽然没有显示出来,但也是可以用的。
__dict__
class Test:
'文档字符串'
name = 'python' a = Test()
a.name = 'good'
print Test.__dict__
print a.__dict__
这个属性就是将对象内的属性和值用字典的方式显示出来。这里可以明显的看出来,实例创建了一个同名的属性。
__class__
class Test:
pass a = Test()
print a.__class__
print Test.__class__
得到的结果是不一样的
a.__class结果是__main__.Test ---它表示创建这个实例的类是哪个,这里显示是 __main__ 模块,也就是主文件中的 Test 这个类创建的。
Test.__class__结果是type ------表示创建类对象的元类是type
但是,这并不意味不能通过实例来修改类中的属性。我们知道对于不可修改类型的‘修改’,其实就是重新赋值。这个也和函数中的局部作用域和全局作用域类似,我在函数内部尝试‘修改’一个不可变类型其实就是创建新的同名变量。但我却可以访问全局某个可修改的对象来修改它。
class Test:
list1 = [] a = Test()
a.list1.append() # 同通过实例修改类中的列表
print Test.list1
print a.list1
我通过实例访问到了一个对象,这个对象是可修改的,所以我可以修改这个对象。这相当于直接操作那个对象。
但是,等号这样的显式赋值行为还是创建新的对象
a.list1 = [123] # 显式的创建一个新对象
这里又有个问题了,我们通常使用 __init__ 来初始化时,会为其添加数据属性,例如 self.name = xxx ,但是却几乎不会为实例添加方法,也就是说实例中的方法,都是在类中找的。这样做其实有好处,因为方法一般是通用的,如果每一个实例都要保存一套方法的话,实在太浪费资源,而把这些方法统一保存到类中,用到的时候来类里找,就节约了许多。
当然,我们也可以任性地为某个实例添加方法,python 支持动态添加属性。
class Test:
pass def method():
print('我是实例方法') a = Test()
b = Test()
a.abc = method # 特意添加一个方法
a.abc()
b.abc() # b 没有这个方法
同样的,我们也可以为类动态添加一个方法:
class Test:
pass def method(self): # self 代表是实例方法,只能由实例调用
print('我是方法') Test.abc = method
a = Test()
a.abc()
当然一般情况下我们很少这样做,因为这样会变得不可控,因为你不知道某个方法在你调用的时候有没有创建。
字段私有化:
我们可以对属性进行私有化,以限制部分访问,现在先说说字段私有化。
一般公有字段我们可以通过实例对象访问,类对象访问,类里面的方法也可以访问。
而私有字段一般仅类里面的方法可以访问了。
私有化的方法非常简单,只需要在变量名前面加上两个下划线即可:
class Test:
__name = 'python' # 私有字段 def a(self):
print Test.__name #内部还需要用类来方问 a = Test()
a.a()
print Test.__name # 在外部使用类来访问是不行的
但是,私有化并不是语法上的强制,而是 python 隐藏了私有字段的访问入口,所以我们可以在新的入口中访问到私有字段:
print Test._Test__name
其格式是: 对象._类__字段名;这里是类的私有字段,所以使用的对象是类对象。
上面的代码使用的是类对象,也可以使用实例对象进行访问 a._Test__name 。
私有化其实就是‘混淆’了相应的属性,这样做还有一个好处,可以保护 __xxx 变量不会与父类中的同名变量冲突。如果父类中有也有一个 __xxx 的变量的话,父类中的变量不会被子类中 __xxx 覆盖。如果是非私有的字段 xxx ,就会被子类中的覆盖掉。所以私有化也是保护关键变量的好选择。
们上面讲的都是类中的字段的私有化,同样的,我们也可以为实例的字段进行私有化
class Test:
def __init__(self):
self.__name = 'python' # 实例的私有字段 def a(self):
print self.__name # 只能有内部方法能访问 a = Test()
a.a()
print a.__name # 试图通过实例访问是访问不到的
同样的,这里也是隐藏了入口,访问格式依然是一样的,只不过这里的对象指的是实例了
print a._Test__nam
总结:公用字段可以通过类对象,实例对象,类里面的方法进行访问。
而私有字段则一般通过类里面的方法进行访问。
一般不建议强制访问私有字段。
python中的类属性和实例属性的更多相关文章
- 理解Python中的类对象、实例对象、属性、方法
class Animal(object): # 类对象 age = 0 # 公有类属性 __like = None # 私有类属性 def __init__(self): # 魔法方法 self.na ...
- Python中的类属性、实例属性与类方法、静态方法
1.什么是类对象,实例对象 类对象:类名 实例对象:类创建的对象 2.类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本,这个和C++.Java中类的静态成员变量有点 ...
- 第8.26节 重写Python类中的__getattribute__方法实现实例属性访问捕获
一. 引言 在<第7.23节 Python使用property函数定义属性简化属性访问的代码实现>和<第7.26节 Python中的@property装饰器定义属性访问方法gette ...
- Python类属性,实例属性
1.Python类数据属性:定义在类里面但在函数外面的变量,它们都是静态的. #一段很简单的代码,但反应了很多 >>> class A(): a=1 #一个类里面有个属性a > ...
- python 类属性和实例属性
class AAA(): aaa = 10 # 情形1 obj1 = AAA() obj2 = AAA() print obj1.aaa, obj2.aaa, AAA.aaa # 情形2 obj1.a ...
- python 类属性 、实例属性,可变数据结构作为类属性需要注意的地方
1.一些经典的python错误不去阅读和不重视,就会把错误的做法带入到实际项目中来,甚至造成难以排查问题. 2.有一个大笨猪,按java写观察者模式,java写得是直接在类名下声明一个实例属性(不加s ...
- 关于Python类属性与实例属性的讨论
标题名字有点长. 之所以想写这个文章是因为碰巧看到网上一篇关于Pyhon中类属性及实例属性区别的帖子.因为我之前也被这个问题困扰过,今天碰巧看到了这篇帖子,发现帖子的作者只是描述了现象,然后对原因的解 ...
- Python的程序结构[0] -> 属性/Property[0] -> 类属性、实例属性和私有属性
类属性.实例属性和私有属性 Python中类的属性主要包括类属性,实例属性和私有属性,下面是对三种属性的简单介绍 类属性 / Class Property 类属性在__init__()之外初始化,在外 ...
- Python类属性与实例属性理解
按理讲,类属性改变,类的实例对象这个属性也应该被改变,但是在python中实际却不是这样 class test(): name = 111 a = test() b = test() a.name = ...
- Python之路-面向对象&继承和多态&类属性和实例属性&类方法和静态方法
一.面向对象 编程方式 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强…” 什么是面 ...
随机推荐
- qmake 提示 Failure to open file:****
执行qmake时报错,如下图所示: 解决方法: 将***.pro文件夹的属主改为当前用户,具体操作为: 1.切换登录用户为:root 2.#chown -R ies:ies /usr/appsoft ...
- php导入csv文件
<?php /** * Created by PhpStorm. * User: hanks * Date: 2017/4/30 * Time: 13:24 */ include 'header ...
- PDO数据库操作类
<?php include 'common_config.php'; /** * Class Mysql * PDO数据库操作类 */ class Mysql { protected stati ...
- js脚本中try与cache捕获异常处理
<script type="text/javascript"> function add_reason(elm){ try{ var pp=$('.pp').val() ...
- html的基本标记符号
文本标记:<h1><h2><h3><h4><h5><h6>: 段落标记:<p>: 空格: : 换行: ...
- angular自动化测试--protractor
前戏 面向模型编程: 测试驱动开发: 先保障交互逻辑,再调整细节.---by 雪狼. 为什么要自动化测试? 1,提高产出质量. 2,减少重构时的痛.反正我最近重构多了,痛苦经历多了. 3,便于新人接手 ...
- MyBatis源码解析【1】准备工作
终于迎来了这一天,我觉得现在的我在经历了长时间的学习和开发之后有了一定的经验,所以准备开始学习源码. 今天我将做好充足的准备,在接下来的一个月中,努力的爬过这座大山.(可能不用一个月,但是我觉得需要仔 ...
- Unity3D-Shader-复古电影荧幕特效
[旧博客转移 - 2015年12月6日 18:12] 今天用Shader做了一个复古荧幕效果,老电视机放映的感觉,写篇文章记录一下 原始图片: 没错,这就是电影<泰坦尼克号> ...
- jsp注册页面的省份联动(网上copy别人的,然后自己弄了一下才知道怎么用)
首先写一个js里面是所有的省份一些七七八八的东西,直接复制黏贴过去就好了. var addressInit = function(_cmbProvince, _cmbCity, _cmbArea, d ...
- POJ 3279 枚举(思维)
Fliptile Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10931 Accepted: 4029 Descrip ...