Python反射与自省学习
1.反射自省的概念
自省:自省就是能够获得自身的结构和方法,给开发者可以灵活的调用,给定一个对象,返回该对象的所有属性和函数列表,或给定对象和该对象的函数或者属性的名字,返回对象的函数或者属性实例。
反射就是通过字字符串的形式来操作对象或者模块的成员,一种基于字符串的事件驱动。
2.类与属性
类是对象的定义,而实例是真正的实物,它存放了类中所定义的对象的具体信息
类是现实世界的抽象的实体以编程形式出现,实例是这些对象的具体化
类属性:属性就是一个对象的数据或者函数元素
class MyNewClass: #所有的类需要至少一个继承,object是所有类的父类
'define my new class for test' #类的文档,不能被子类继承,可以使用__doc__调出
version = '1.0' #类的数据属性
def __init__(self): #类似构造器,创建一个新对象时调用,self代表实例对象本身,调用方法时,解释器传给方法
print('create a object')
def in_class(self): #方法,必须绑定到实例才能调用
print('in class ')
#申明与定义类同时进行
myclass = MyNewClass() #实例化
create a object
MyNewClass.version #访问类数据属性
'1.0'
myclass.version #访问实例属性
'1.0'
MyNewClass.in_class() #通过类不能调用方法
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-5c59b2c4c0c8> in <module>()
----> 1 MyNewClass.in_class() #通过类不能调用方法
TypeError: in_class() missing 1 required positional argument: 'self'
myclass.in_class() #通过实例进行方法调用
in class
class MySubClass(MyNewClass):
'This is my second Class for test' #文档不能被子类继承
version = '2.0'
def __init__(self, num): #重写__init__方法
self.num = num
print('create a sub class ')
def num_is(self): #为子类增加方法
print('The num is %d' % self.num)
my_sub_class = MySubClass(123) #子类实例化
create a sub class
my_sub_class.num_is() #子类方法调用
The num is 123
my_sub_class.in_class() #访问父类方法
in class
my_sub_class.version #子类数据属性
'2.0'
dir()方法,没有参数,返回当前本地作用域中的名称列表。使用参数,尝试返回该对象的有效属性列表
dir(MyNewClass) #通过dir()可以查看类的属性
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'in_class',
'version']
object.__dict__
用于存储对象(可写)属性的字典或其他映射对象,不是所有的对象都有__dict__
属性。例如,如果你在一个类中添加了 __slots__
属性,那么这个类的实例将不会拥有 __dict__
属性,但是 dir() 仍然可以找到并列出它的实例所有有效属性
MyNewClass.__dict__ #类的属性
mappingproxy({'__dict__': <attribute '__dict__' of 'MyNewClass' objects>,
'__doc__': 'define my new class for test',
'__init__': <function __main__.MyNewClass.__init__>,
'__module__': '__main__',
'__weakref__': <attribute '__weakref__' of 'MyNewClass' objects>,
'in_class': <function __main__.MyNewClass.in_class>,
'version': '1.0'})
MyNewClass.__name__ #类名
'MyNewClass'
MyNewClass.__doc__ #查看文档
'define my new class for test'
MySubClass.__doc__
'This is my second Class for test'
MySubClass.__bases__ #查看类的父类的元组
(__main__.MyNewClass,)
MyNewClass.__bases__
(object,)
MyNewClass.__module__ #类定义所在的模块
'__main__'
MyNewClass.__class__
type
2.实例与实例属性
如果说类是一种很数据结构定义类型,那么实例就是申明了这种类型的变量
__init__()
构造器是最早可以设置实例属性的地方
class MyClass (object):
pass
mc = MyClass()
mc
<__main__.MyClass at 0x7fd26c503198>
如果定义了构造器,它不应返回任何对象,因为实例对象是自动在实例化调用后返回的。
__init__()
就不应该返回任何对象,否则,就可能出现冲突,因为只能返回实例。
class MyClass(object):
def __init__(self):
print('Initialized')
return 1
mc = MyClass()
File "<ipython-input-29-8544d6773fc1>", line 4
return 1
^
SyntaxError: 'return' outside function
实例属性
class C:
pass
c = C()
c.foo = 'foo foo'
c.bar = 'bar bar'
dir(C) #类属性
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__']
dir(c) #实例属性
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'bar',
'foo']
c.__dict__
{'bar': 'bar bar', 'foo': 'foo foo'}
class T:
pass
t = T()
t.__dict__
{}
t.__class__
__main__.T
类属性和实例属性:类属性仅是与类相关的数据值,这些值可以像静态成员那样被引用,即使在多次实例化中调用类,他们的值都保持不变
class T(object):
version = 1.0
t = T() #实例化
T.version #访问类属性
1.0
t.version #访问实例属性
1.0
t.version = 2.0 #改变实例属性(实际上时床架了新的实例属性),而非类属性
t.version
2.0
T.version #类属性没有改变
1.0
del t.version #删除实例属性, 给一个与类属性同名的实例属性赋值,我们会有效的“隐藏”类属性,删除又重现
t.version
1.0
T.version = 3.0 #更新类属性
t.version #实例访问,其值已经改变
3.0
但是在类属性可以改变的情况下,类属性可以通过实例改变
class Foo(object):
x = {2003: 'poe2'}
foo = Foo()
foo.x
{2003: 'poe2'}
foo.x[2004] = 'valid path' #通过实例改变
foo.x
{2003: 'poe2', 2004: 'valid path'}
Foo.x #类属性已经改变
{2003: 'poe2', 2004: 'valid path'}
3.绑定和方法调用
方法仅仅是类内部定义的函数,这意味着方法时类属性而不是实例属性
任何方法定义的第一个参数都是变量self,它表示调用此方法的实例对象
非绑定方法:需要调用一个还没有任何实例的类中的一个方法
class Person(object):
def __init__(self, name):
self.name = name
def get_name(self):
return('The name is %s' % self.name)
Person.get_name
<function __main__.Person.get_name>
Person.get_name() #方法未绑定
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-66-257ab8eff3fa> in <module>()
----> 1 Person.get_name() #方法未绑定
TypeError: get_name() missing 1 required positional argument: 'self'
Person.get_name(Person('zhang')) #未绑定的方法必须使用一个Person实例作为第一个参数来调用
'The name is zhang'
p = Person('python') #实例化绑定方法,使用实例调用,调用的实例被作为第一个参数被隐含的传递过去
print(p)
<__main__.Person object at 0x7fd26c505ac8>
4.内建函数
hasattr、getattr、setattr、delattr:对象是否有、取得、设置、删除某个属性
class TestAttr(object):
def __init__(self):
self.foo = 100
ta = TestAttr()
hasattr(ta, 'foo') #判断是否具有'foo'属性
True
getattr(ta, 'foo') #取得foo的值
100
getattr(ta, 'bar') #取得bar的值,但是对象没有该值,抛出异常
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-80-f6c57b29833a> in <module>()
----> 1 getattr(ta, 'bar') #取得bar的值,但是对象没有该值,抛出异常
AttributeError: 'TestAttr' object has no attribute 'bar'
setattr(ta, 'bar', 100000) #设置某个值
getattr(ta, 'bar')
100000
setattr(ta, 'my attr', 'Python Class Attr Function')
dir(ta)
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'bar',
'foo',
'my attr']
delattr(ta, 'bar') #删除某个值
delattr(ta, 'foo')
ta.__dict__
{'my attr': 'Python Class Attr Function'}