Gointerface接口声明实现及作用详解
287
2022-08-27
Python从门到精通(二):包装-05-类的属性(补充)
一、属性读取
1.1、getter和setter
这里可以复写两个方法:__getattr__只在调用不存在的属性时才会被调用,__getattribute__无条件被调用,如果同时重写了以上两个方法,则__getattr__永远不会被调用。另外__getattr__对于双下划线开始和结尾、单下划线开始的方法是不能用的。
"""如果自定义这两个方法,则__getattr__只在调用不存在的属性时才会被调用__getattribute__无条件被调用如果同时重写了以上两个方法,则__getattr__永远不会被调用"""class A(object): def __init__(self, name): self.name = namea = A('attribute')print(a.name)#attribute
class A1(object): def __init__(self, name): self.name = name #用这种方法可以实现更友好的程序和属性隐藏, def __getattr__(self, name): print(f'calling __getattr__: {name}')a = A1('attribute')print(a.name)print(a.test)# attribute# calling __getattr__: test# None
class A1(object): def __init__(self, name): self.name = name def __getattr__(self, name): print(f'calling __getattr__: {name}') def __getattribute__(self, item): print("call getattribut")a = A1('attribute')print(a.name)print(a.test)# call getattribut# None //这行是因为不存在属性所以打印出来的,因为覆写了__getattribute__方法# call getattribut# None //这行是因为不存在属性所以打印出来的
1.2、proxy
1.2.1、简单实现
class A(object): def spam(self, x): pass def foo(self): passclass B(object): """ 简单的代理 """ def __init__(self): self._a = A() def spam(self, x): return self._a.spam(x) def foo(self): return self._a.foo() def bar(self): pass
设置一个代理类,这个类只能代理被代理的public方法
# A proxy class that wraps around another object, but exposes its public attributesclass Proxy(object): def __init__(self, obj): self._obj = obj # Delegate attribute lookup to internal obj def __getattr__(self, name): print(f'getattr: {name}') return getattr(self._obj, name) # Delegate attribute assignment def __setattr__(self, name, value): if name.startswith('_'): super().__setattr__(name, value) else: print(f'setattr: {name} {value}') setattr(self._obj, name, value) # Delegate attribute deletion def __delattr__(self, name): if name.startswith('_'): super().__delattr__(name) else: print(f'delattr: {name}') delattr(self._obj, name)class Spam(object): def __init__(self, x): self.x = x def bar(self, y): print(f'Spam.bar: {self.x}, {y}')# Create an instances = Spam(2)# # Create a proxy around itp = Proxy(s)# Access the proxyp.bar(3) #Spam.bar: 2, 3
二、属性创建
2.2、属性的创建
class Person: def __init__(self, first_name): self.first_name = first_name #此处的first_name不带下划线的原因是,当创建属性时会自动调用 @first_name.setter标注的方法,实现检查的目的 # Getter function @property def first_name(self): return self._first_name # Setter function @first_name.setter def first_name(self, value): if not isinstance(value, str): raise TypeError('Expected a string') self._first_name = value # Deleter function (optional) @first_name.deleter def first_name(self): raise AttributeError("Can't delete attribute")per = Person('Guido')# Calls the getterprint(f'first name is: {per.first_name}')# Calls the setter,Err, expected a stringper.first_name = 30# Calls the deleter, Err, raise ErrorExceptiondel per.first_name
2.2、在已有get/set方法的基础上创建property
name = property(get_first_name, set_first_name, del_first_name)
class Person: def __init__(self, first_name): self.set_first_name(first_name) # Getter function def get_first_name(self): return self._first_name # Setter function def set_first_name(self, value): if not isinstance(value, str): raise TypeError('Expected a string') self._first_name = value # Deleter function (optional) def del_first_name(self): raise AttributeError("Can't delete attribute") # Make a property from existing get/set methods name = property(get_first_name, set_first_name, del_first_name)
2.3、动态计算属性
import mathclass Circle: def __init__(self, radius): self.radius = radius @property def area(self): return math.pi * self.radius ** 2 @property def diameter(self): return self.radius * 2 @property def perimeter(self): return 2 * math.pi * self.radiusc = Circle(4.0)print(f'radius is: {c.radius}')# Notice lack of ()print(f'area is: {c.area}')print(f'perimeter is: {c.perimeter}')
2.4、延迟计算
下面这个__get__方法会早于Circle中的具体方法先行运算。
class LazyProperty: def __init__(self, func): self.func = func def __get__(self, instance, cls): if instance is None: return self else: value = self.func(instance) #下面这行可有可无,其中name指要调用的特定方法 setattr(instance, self.func.__name__, value) return valueimport mathclass Circle: def __init__(self, radius): self.radius = radius @LazyProperty def area(self): print('Computing area') return math.pi * self.radius ** 2 @LazyProperty def perimeter(self): print('Computing perimeter') return 2 * math.pi * self.radiuscircle = Circle(6.0)print(f'radius = {circle.radius}')print(f'area = {circle.area}')print(f'perimeter = {circle.perimeter}')
三、类型检查
3.1、通用方法
# Base class. Uses a descriptor to set a valueclass Descriptor: def __init__(self, name=None, **opts): self.name = name for key, value in opts.items(): setattr(self, key, value) def __set__(self, instance, value): instance.__dict__[self.name] = value# Descriptor for enforcing typesclass Typed(Descriptor): expected_type = type(None) def __set__(self, instance, value): if not isinstance(value, self.expected_type): raise TypeError(f'expected {str(self.expected_type)}') super().__set__(instance, value)# Descriptor for enforcing valuesclass Unsigned(Descriptor): def __set__(self, instance, value): if value < 0: raise ValueError('Expected >= 0') super().__set__(instance, value)class Integer(Typed): expected_type = intclass String(Typed): expected_type = strclass SizedString(String): passclass Course: # Specify constraints course_name = SizedString('course_name') total_class = Integer('total_class') score = String('score') def __init__(self, course_name, total_class, score): self.course_name = course_name self.total_class = total_class self.score = scorecourse = Course('python', 30, "hello")course.score = 'hello'
3.2、注解实现
# Class decorator to apply constraintsdef check_attributes(**kwargs): def decorate(cls): for key, value in kwargs.items(): if isinstance(value, Descriptor): value.name = key setattr(cls, key, value) else: setattr(cls, key, value(key)) return cls return decorate# Example@check_attributes(course_name=SizedString(size=8), total_class=String, score=String)class Course: def __init__(self, course_name, total_class, score): self.course_name = course_name self.total_class = total_class self.score = score
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~