python判断对象属性
⑴ python 如何查看object有哪些属性值
dir([obj]):
调用这个方法将返回包含obj大多数属性名的列表(会有一些特殊的属性不包含在内)。obj的默认值是当前的模块对象。
hasattr(obj, attr):
这个方法用于检查obj是否有一个名为attr的值的属性,返回一个布尔值。
getattr(obj, attr):
调用这个方法将返回obj中名为attr值的属性的值,例如如果attr为’bar’,则返回obj.bar。
setattr(obj, attr, val):
调用这个方法将给obj的名为attr的值的属性赋值为val。例如如果attr为’bar’,则相当于obj.bar = val。
⑵ python如何判断self.属性是否存在
一般来说,在Python中,类实例属性的访问规则算是比较直观的。
但是,仍然存在一些不是很直观的地方,特别是对C++和Java程序员来说,更是如此。
在这里,我们需要明白以下几个地方:
1.Python是一门动态语言,任何实体都可以动态地添加或删除属性。
2.一个类定义了一个作用域。
3.类实例也引入了一个作用域,这与相应类定义的作用域不同。
4.在类实例中查找属性的时候,首先在实例自己的作用域中查找,如果没有找到,则再在类定义的作用域中查找。
5.在对类实例属性进行赋值的时候,实际上会在类实例定义的作用域中添加一个属性(如果还不存在的话),并不会影响到相应类中定义的同名属性。
下面看一个例子,加深对上述几点的理解:
复制代码
代码如下:
class A:
cls_i = 0
cls_j
= {}
def __init__(self):
self.instance_i =
0
self.instance_j =
{}
在这里,我们先定义类A的一个实例a,然后再看看类A的作用域和实例a的作用域中分别有什么:
复制代码
代码如下:
>>> a = A()
>>>
a.__dict__
{'instance_j': {}, 'instance_i': 0}
>>>
A.__dict__
{'__init__': , '__mole__': '__main__', 'cls_i': 0, 'cls_j': {},
'__doc__': None}
我们看到,a的作用域中有instance_i和instance_j,A的作用域中有cls_i和cls_j。
我们再来看看名字查找是如何发生的:
复制代码
代码如下:
>>> a.cls_i
0
>>>
a.instance_i
0
在查找cls_i的时候,实例a的作用域中是没有它的,却在A的作用域中找到了它;在查找instance_i的时候,直接可在a的作用域中找到它。
如果我们企图通过实例a来修改cls_i的值,那会怎样呢:
复制代码
代码如下:
>>> a.cls_i = 1
>>>
a.__dict__
{'instance_j': {}, 'cls_i': 1, 'instance_i': 0}
>>>
A.__dict__
{'__init__': , '__mole__': '__main__', 'cls_i': 0, 'cls_j': {},
'__doc__': None}
我们可以看到,a的作用域中多了一个cls_i属性,其值为1;同时,我们也注意到A作用域中的cls_i属性的值仍然为0;在这里,我们其实是增加了一个实例属性,并没有修改到类属性。
如果我们通过实例a操纵cls_j中的数据(注意不是cls_j本身),又会怎么样呢:
复制代码
代码如下:
>>> a.cls_j['a'] =
'a'
>>> a.__dict__
{'instance_j': {}, 'cls_i': 1, 'instance_i':
0}
>>> A.__dict__
{'__init__': , '__mole__': '__main__',
'cls_i': 0, 'cls_j': {'a': 'a'}, '__doc__': None}
我们可以看到a的作用域没有发生什么变化,但是A的作用域发生了一些变化,cls_j中的数据发生了变化。
实例的作用域发生变化,并不会影响到该类的其它实例,但是类的作用域发生变化,则会影响到该类的所有实例,包括在这之前创建的实例:
复制代码
代码如下:
>>> A.cls_k = 0
⑶ python一个对象的属性可以有多少
导读:很多朋友问到关于python一个对象的属性可以有多少的相关问题,本文首席CTO笔记就来为大家做个详细解答,供大家参考,希望对大家有所帮助!一起来看看吧!
Python查看对象属性的几种方式:__dict__,dir(),vars(),locals()为了方便用户查看类中包含哪些属性,Python类提供了__dict__属性。需要注意的一点是,该属性可以用类名或者类的实例对象来调用,用类名直接调用__dict__,会输出该由类中所有类属性组成的字典;而使用类的实例对象调用__dict__,会输出由类中所有实例属性组成的字典。
先来看一下Python类的__dict__属性和类实例对象的__dict__属性,例子如下:
从以上的测试结果中可以得出以下结论:
看几个小例子:
如果没传入参数,就打印当前调用位置的属性和属性值,类似于下面的locals()。
locals()返回调用者当前局部名称空间的字典。在一个函数内部,局部名称空间代表在函数执行时候定义的所有名字,locals()函数返回的就是包含这些名称的字典。
Python对象众所周知,Python是一门面向对象的语言,在Python无论是数值、字符串、函数亦或是类型、类,都是对象。
对象是在堆上分配的结构,我们定义的所有变量、函数等,都存储于堆内存,而变量名、函数名则是一个存储于栈中、指向堆中具体结构的引用。
要想深入学习Python,首先需要知道Python对象的定义。
我们通常说的Python都是指CPython,底层由C语言实现,源码地址:cpython[GitHub]
Python对象的定义位于Include/object.h,是一个名为PyObject的结构体:
Python中的所有对象都继承自PyObejct,PyObject包含一个用于垃圾回收的双向链表,一个引用计数变量ob_refcnt和一个类型对象指针ob_type
从PyObejct的注释中,我们可以看到这样一句:每个指向可变大小Python对象的指针也可以转换为PyVarObject*(可变大小的Python对象会在下文中解释)。PyVarObejct就是在PyObject的基础上多了一个ob_size字段,用于存储元素个数:
在PyObject结构中,还有一个类型对象指针ob_type,用于表示Python对象是什么类型,定义Python对象类型的是一个PyTypeObject接口体
实际定义是位于Include/cpython/object.h的_typeobject:
在这个类型对象中,不仅包含了对象的类型,还包含了如分配内存大小、对象标准操作等信息,主要分为:
以Python中的int类型为例,int类型对象的定义如下:
从PyObject的定义中我们知道,每个对象的ob_type都要指向一个具体的类型对象,比如一个数值型对象100,它的ob_type会指向int类型对象PyLong_Type。
PyTypeObject结构体第一行是一个PyObject_VAR_HEAD宏,查看宏定义可知PyTypeObject是一个变长对象
也就是说,归根结底类型对象也是一个对象,也有ob_type属性,那PyLong_Type的ob_type是什么呢?
回到PyLong_Type的定义,第一行PyVarObject_HEAD_INIT(PyType_Type,0),查看对应的宏定义
由以上关系可以知道,PyVarObject_HEAD_INIT(PyType_Type,0)={{_PyObject_EXTRA_INIT1,PyType_Type}0},将其代入PyObject_VAR_HEAD,得到一个变长对象:
这样看就很明确了,PyLong_Type的类型就是PyType_Typ,同理可知,Python类型对象的类型就是PyType_Type,而PyType_Type对象的类型是它本身
从上述内容中,我们知道了对象和对象类型的定义,那么根据定义,对象可以有以下两种分类
Python对象定义有PyObject和PyVarObject,因此,根据对象大小是否可变的区别,Python对象可以划分为可变对象(变长对象)和不可变对象(定长对象)
原本的对象a大小并没有改变,只是s引用的对象改变了。这里的对象a、对象b就是定长对象
可以看到,变量l仍然指向对象a,只是对象a的内容发生了改变,数据量变大了。这里的对象a就是变长对象
由于存在以上特性,所以使用这两种对象还会带来一种区别:
声明s2=s,修改s的值:s='newstring',s2的值不会一起改变,因为只是s指向了一个新的对象,s2指向的旧对象的值并没有发生改变
声明l2=l,修改l的值:l.append(6),此时l2的值会一起改变,因为l和l2指向的是同一个对象,而该对象的内容被l修改了
此外,对于字符串对象,Python还有一套内存复用机制,如果两个字符串变量值相同,那它们将共用同一个对象:
对于数值型对象,Python会默认创建0~28以内的整数对象,也就是0~256之间的数值对象是共用的:
按照Python数据类型,对象可分为以下几类:
Python创建对象有两种方式,泛型API和和类型相关的API
这类API通常以PyObject_xxx的形式命名,可以应用在任意Python对象上,如:
使用PyObjecg_New创建一个数值型对象:
这类API通常只能作用于一种类型的对象上,如:
使用PyLong_FromLong创建一个数值型对象:
在我们使用Python声明变量的时候,并不需要为变量指派类型,在给变量赋值的时候,可以赋值任意类型数据,如:
从Python对象的定义我们已经可以知晓造成这个特点的原因了,Python创建对象时,会分配内存进行初始化,然后Python内部通过PyObject*变量来维护这个对象,所以在Python内部各函数直接传递的都是一种泛型指针PyObject*,这个指针所指向的对象类型是不固定的,只能通过所指对象的ob_type属性动态进行判断,而Python正是通过ob_type实现了多态机制
Python在管理维护对象时,通过引用计数来判断内存中的对象是否需要被销毁,Python中所有事物都是对象,所有对象都有引用计数ob_refcnt。
当一个对象的引用计数减少到0之后,Python将会释放该对象所占用的内存和系统资源。
但这并不意味着最终一定会释放内存空间,因为频繁申请释放内存会大大降低Python的执行效率,因此Python中采用了内存对象池的技术,是的对象释放的空间会还给内存池,而不是直接释放,后续需要申请空间时,优先从内存对象池中获取。
python类中的方法属性分别什么意思很抽象没办法回答
属性:就是类对象的属性,存储某个值这个值的代号可以称为类的属性
方法:把每一项类中所有的功能封装起来称为方法,一般方法里的内容就是方法的执行过程。
举例:比如类表示的是People也就是人
?????人的类中会有一些属性这些属性大概是身高、体重、姓名等等
?????那么方法比如是跑、吃、等等
?
Class?People():
????def?__init__(self,?name):
????????self.name?=?name
????????self.height?=?0
????
????#?比如说跑了一次之后?身高就增长了1个单位
????def?run():
????????print?"开始奔跑"
????????self.height?+=?1
????????print?"奔跑结束"
上面的例子run就是方法;name和height就是属性
run的方法执行过程就是跑完之后height就加1
不知道这样讲你能明白吗
python类的属性有哪几种?如何访问它们?属性的访问机制
一般情况下,属性访问的默认行为是从对象的字典中获取,并当获取不到时会沿着一定的查找链进行查找。例如?a.x?的查找链就是,从?a.__dict__['x']?,然后是?type(a).__dict__['x']?,再通过?type(a)?的基类开始查找。
若查找链都获取不到属性,则抛出?AttributeError?异常。
一、__getattr__?方法
这个方法是当对象的属性不存在是调用。如果通过正常的机制能找到对象属性的话,不会调用?__getattr__?方法。
class?A:
a?=?1
def?__getattr__(self,?item):
print('__getattr__?call')
return?item
t?=?A()
print(t.a)
print(t.b)
#?output
1
__getattr__?call
b
二、__getattribute__?方法
这个方法会被无条件调用。不管属性存不存在。如果类中还定义了?__getattr__?,则不会调用?__getattr__()方法,除非在?__getattribute__?方法中显示调用__getattr__()?或者抛出了?AttributeError?。
class?A:
a?=?1
def?__getattribute__(self,?item):
print('__getattribute__?call')
raise?AttributeError
def?__getattr__(self,?item):
print('__getattr__?call')
return?item
t?=?A()
print(t.a)
print(t.b)
所以一般情况下,为了保留?__getattr__?的作用,__getattribute__()?方法中一般返回父类的同名方法:
def?__getattribute__(self,?item):
return?object.__getattribute__(self,?item)
使用基类的方法来获取属性能避免在方法中出现无限递归的情况。
三、__get__?方法
这个方法比较简单说明,它与前面的关系不大。
如果一个类中定义了?__get__(),?__set__()?或?__delete__()?中的任何方法。则这个类的对象称为描述符。
class?Descri(object):
def?__get__(self,?obj,?type=None):
print("call?get")
def?__set__(self,?obj,?value):
print("call?set")
class?A(object):
x?=?Descri()
a?=?A()
a.__dict__['x']?=?1??#?不会调用?__get__
a.x??????????????????#?调用?__get__
如果查找的属性是在描述符对象中,则这个描述符会覆盖上文说的属性访问机制,体现在查找链的不同,而这个行文也会因为调用的不同而稍有不一样:
如果调用是对象实例(题目中的调用方式),a.x?则转换为调用:。type(a).__dict__['x'].__get__(a,type(a))
如果调用的是类属性,?A.x?则转换为:A.__dict__['x'].__get__(None,A)
其他情况见文末参考资料的文档
四、__getitem__?方法
这个调用也属于无条件调用,这点与?__getattribute__?一致。区别在于?__getitem__?让类实例允许?[]?运算,可以这样理解:
__getattribute__适用于所有.运算符;
__getitem__适用于所有?[]?运算符。
class?A(object):
????a?=?1
????def?__getitem__(self,?item):
????????print('__getitem__?call')
????????return?item
t?=?A()
print(t['a'])
print(t['b'])
如果仅仅想要对象能够通过?[]?获取对象属性可以简单的:
def?__getitem(self,?item):
????return?object.__getattribute__(self,?item)
总结
当这几个方法同时出现可能就会扰乱你了。我在网上看到一份示例还不错,稍微改了下:
class?C(object):
????a?=?'abc'
????def?__getattribute__(self,?*args,?**kwargs):
????????print("__getattribute__()?is?called")
????????return?object.__getattribute__(self,?*args,?**kwargs)
????#????????return?"haha"
????def?__getattr__(self,?name):
????????print("__getattr__()?is?called?")
????????return?name?+?"?from?getattr"
????def?__get__(self,?instance,?owner):
????????print("__get__()?is?called",?instance,?owner)
????????return?self
????def?__getitem__(self,?item):
????????print('__getitem__?call')
????????return?object.__getattribute__(self,?item)
????def?foo(self,?x):
????????print(x)
class?C2(object):
????d?=?C()
if?__name__?==?'__main__':
????c?=?C()
????c2?=?C2()
????print(c.a)
????print(c.zzzzzzzz)
????c2.d
????print(c2.d.a)
????print(c['a'])
可以结合输出慢慢理解,这里还没涉及继承关系呢。总之,每个以?__get?为前缀的方法都是获取对象内部数据的钩子,名称不一样,用途也存在较大的差异,只有在实践中理解它们,才能真正掌握它们的用法。
结语:以上就是首席CTO笔记为大家整理的关于python一个对象的属性可以有多少的全部内容了,感谢您花时间阅读本站内容,希望对您有所帮助,更多关于python一个对象的属性可以有多少的相关内容别忘了在本站进行查找喔。