2022年 11月 3日

python委托模式详细解释(__getattr__)以及字段,属性,方法的涉及总结

委托:如果我们要把方法当做参数来传递的话,就要用到委托。简单来说,委托的类型可以是赋值一个方法的引用. 可以把一个方法赋值过来,通过这个委托变量调用这个方法 python函数是能作为参数输入函数的,这个相当于c里面的委托,将一个函数封装到一个委托对象里

首先我们看这个函数

__getattr__

getattr(object, name[, default])

  • object — 对象。
  • name — 字符串,对象属性。
  • default — 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。

该函数属于反射操作,用于获取 object 中名为 name 的属性(name 是以字符串表示的属性名), getattr(x, ‘foobar’) 等效于 x.foobar。如果 object 中含有 name 属性,则返回该属性;如果 object 没有 name 属性,则返回 default(如果提供),否则抛出 AttributeError 异常。

对于字段属性,会直接返回值;对于方法属性,会返回其引用(通过引用可调用方法属性)。

  1. #字段包括普通字段和静态字段
  2. class Province:
  3. # 静态字段
  4. country = '中国'
  5. def __init__(self, name):
  6. # 普通字段
  7. self.name = name
  8. # 直接访问普通字段
  9. obj = Province('河北省')
  10. print obj.name
  11. # 直接访问静态字段
  12. Province.country

 

  1. class ObjectDict(dict):
  2. def __init__(self, *args, **kwargs):
  3. super(ObjectDict, self).__init__(*args, **kwargs)
  4. def __getattr__(self, name):
  5. value = self[name]
  6. if isinstance(value, dict):
  7. value = ObjectDict(value)
  8. return value
  9. if __name__ == '__main__':
  10. od = ObjectDict(asf={'a': 1}, d=True)
  11. print od.asf
  12. print od.asf.a
  13. print od.d
  14. >>>{'a':1}
  15. >>>1
  16. >>>True

 

  1. #方法包括普通方法、静态方法和类方法
  2. 三种方法在内存中都归属于类,区别在于调用方式不同。
  3. 普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
  4. 类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
  5. 静态方法:由类调用;无默认参数;
  6. class Foo:
  7. def __init__(self, name):
  8. self.name = name
  9. def ord_func(self):
  10. """ 定义普通方法,至少有一个self参数 """
  11. # print self.name
  12. print '普通方法'
  13. @classmethod
  14. def class_func(cls):
  15. """ 定义类方法,至少有一个cls参数 """
  16. print '类方法'
  17. @staticmethod
  18. def static_func():
  19. """ 定义静态方法 ,无默认参数"""
  20. print '静态方法'
  21. # 调用普通方法
  22. f = Foo()
  23. f.ord_func()
  24. # 调用类方法
  25. Foo.class_func()
  26. # 调用静态方法
  27. Foo.static_func()
  28. 相同点:对于所有的方法而言,均属于类(非对象)中,所以,在内存中也只保存一份。
  29. 不同点:方法调用者不同、调用方法时自动传入的参数不同。

 

  1. #属性(普通方法的变种)
  2. class Foo:
  3. def func(self):
  4. pass
  5. # 定义属性
  6. @property
  7. def prop(self):
  8. pass
  9. # ############### 调用 ###############
  10. foo_obj = Foo()
  11. foo_obj.func()#这叫调用方法
  12. foo_obj.prop #调用属性
  13. -------------------------
  14. 由属性的定义和调用要注意一下几点:
  15. 定义时,在普通方法的基础上添加 @property 装饰器;
  16. 定义时,属性仅有一个self参数
  17. 调用时,无需括号
  18. 方法:foo_obj.func()
  19. 属性:foo_obj.prop
  20. ----------------------------------
  21. 属性的定义有两种方式:
  22. 装饰器 即:在方法上应用装饰器
  23. 静态字段 即:在类中定义值为property对象的静态字段
  24. 经典类具有一种@property装饰器
  25. 新式类(Object) 具有三种@property装饰器
  26. class Goods(object):
  27. @property
  28. def price(self):
  29. print '@property'
  30. @price.setter
  31. def price(self, value):
  32. print '@price.setter'
  33. @price.deleter
  34. def price(self):
  35. print '@price.deleter'
  36. # ############### 调用 ###############
  37. obj = Goods()
  38. obj.price
  39. # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
  40. obj.price = 123
  41. # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数
  42. del obj.price
  43. # 自动执行 @price.deleter 修饰的 price 方法

 

  1. class Wrapper:
  2. def __init__(self, obj):
  3. self.wrapper = obj
  4. print self.wrapper
  5. print type(self.wrapper)
  6. print"-"*100
  7. def __getattr__(self, item):
  8. print("trace:", item)
  9. return getattr(self.wrapper, item)
  10. if __name__ == '__main__':
  11. x = Wrapper([1, 2, 3, 4])
  12. x.append(35)
  13. x.remove(2)
  14. print(x.wrapper) # [1,3,4,35]

 在__init__(self,obj)方法中传入一个被委托对象。 通过重写__getattr__(self,item)方法,拦截外部对象的属性调用 在__getattr__(self,item)中,将拦截到的属性,让被委托对象去使用。 python 中的属性概念,和Java中的属性概念是不同的。Java中的属性,就是指类中定义的成员变量,绝对不包含方法。而在python中,任何能以obj.xx形式调用的东西,全部可以称为属性。无论是方法,还是变量,还是对象。 所以上述代码中调用x.append(N),实际上是让x的属性wrapper去调用append(N)方法。