流畅的Python(十九)-动态属性和特性

一、核心要义

在Python中,数据的属性和处理数据的方法,统称属性。方法,只是可调用的属性。除了这两者之外,我们还可以创建特性(property),在不改变类接口的前提下,使用存取方法(即读值方法和设值方法)修改数据属性。

二、代码示例

0、相关知识点

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/13 20:56
# @Author  : Maple
# @File    : 00-相关知识点.py
# @Software: PyCharmclass Animal:def __init__(self,name):self.name = name@propertydef run(self):print('Animal is running')class Computer:def __init__(self,brand,price):self.brand = brandself.price = price@classmethoddef computing(cls):print("I love computing")if __name__ == '__main__':# 1.更新字典的值person= {"name":"Maple","age":19}person.update({"name":"Max","gender":"Maple"})print(person)# 2.类的__dict__中存放着其属性a = Animal('Dog')## 初次查看a的属性print(a.__dict__) # {'name': 'Dog'}## 通过更新__dict__,可以给类增加属性a.__dict__.update({"age":10})## 查看更新后的a包含的属性print(a.__dict__) # {'name': 'Dog', 'age': 10}# 3.以访问属性的方式,调用方法## 没有添加 property装饰器之前,通过如下方式调用run方法#a.run() # Animal is running## 添加property装饰器之后,可以以引用属性的方式调用run方法a.run # Animal is running# 4.类相关的一些内置属性print('******4.类相关的一些内置属性********')print(Animal) #<class '__main__.Animal'>##4-1. 类的名称print(Animal.__name__)##4-2 类的类型:为typeprint(Animal.__class__) #<class 'type'>print(Animal.__class__.__name__)  # type##4-3对比实例的__class__print(a.__class__) #<class '__main__.Animal'>print(Animal) # <class '__main__.Animal'>print(Animal.run) # <property object at 0x00000245AAF264A0>print(a.__class__.run) # <property object at 0x00000245AAF264A0># 5. 通过实例调用类方法com = Computer('Apple', 20000)com.computing() # I love computing# 6.直接通过类调用类方法Computer.computing() # I love computingcom.__class__.computing() # I love computing# 6.从模块的全局作用域中获取对象(包括类),如果获取不到给默认值## 获取Animal的一个实例对象print(globals().get('a', Computer))  # <__main__.Animal object at 0x000001D5FB513DC0>## 获取Animal类print(globals().get('Animal')) # <class '__main__.Animal'>print(globals().get('Cat',Computer)) # <class '__main__.Computer'>cc = globals().get('Cat', Computer)print(issubclass(cc,Computer)) #True

1、使用动态属性访问Json数据(1)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/12 21:17
# @Author  : Maple
# @File    : 01-使用动态属性访问Json数据(1).py
# @Software: PyCharmfrom collections import abc
from osconfeed import loadclass FrozenJSON:def __init__(self,mapping):self.__data = dict(mapping)def __getattr__(self, item):if hasattr(self.__data,item):return self.__data[item]else:return FrozenJSON.build(self.__data[item])@classmethoddef build(cls,obj):if isinstance(obj,abc.Mapping):# 如果是一个键值对类型,就直接返回一个FrozenJSON对象return cls(obj)# 如果是一个列表,就为列表中的每个元素创建一个FrozenJSON对象(其实是将JSON中的对象转换成FrozenJSON对象)elif isinstance(obj,abc.MutableSequence):return [cls(item) for item in obj]# 否则就返回对象本身else:return objif __name__ == '__main__':# 1. 获取原始Json对象:实际已转换为Python中的对象字典osconfeed  = load()print(type(osconfeed)) # <class 'dict'>#2.JSON对象封装成 FrozenJSONprint('**** 2-1.封装osconfeed**********')## 2-1.此时f_json仅有一个属性__data,对应的values是osconfeed.json(转成字典格式)f_json = FrozenJSON(osconfeed)print('f_json:', f_json.__dict__)## 2-2 访问f_json.schedule,因为f_json中并没有schedule属性print('**** 2-2.访问schedule**********')#      因此会调用 FrozenJSON.build(self.__data[item]),会返回一个FrozenJSON实例对象,且该实例属性名依然为__data,对应的value#      则是原json数据中schedule下对应的valuef_json_schedule = f_json.scheduleprint('f_json_schedule:',f_json_schedule.__dict__)# print(f_json.schedule.conference[0].serial) # 115## 2-3 继续访问schedule下的events,由于f_json_schedule中并没有events属性:#      因此会调用  FrozenJSON.build(self.__data[item]),由于events下是一个list,因此该方法也会返回一个FrozenJSON对象列表print('**** 2-3.访问schedule.events**********')FrozenJSON_events_list =  f_json_schedule.eventsfor i,frozen_event in enumerate(FrozenJSON_events_list):# frozen_event仍然没有serial属性,因此会调用FrozenJSON.build(self.__data[item])# 然后 因为self.__data['serial']对应的值既不是Mapping又不是MutableSequence,因此返回值本身:即数字print('**2-4.访问schedule.events下的serial****')result = frozen_event.serialprint('第{}个frozen_event下的serial对应的值是{}'.format(i,result))

(1) osconfeed.json数据

{"schedule": {"conference":[{"serial":115}],"events":[{"serial":4505,"name": "Go to the island","event_type":"escape","venue_serial": 1462,"speakers": [8890,8891]},{"serial":4506,"name": "To be my best","event_type":"study","venue_serial": 1463,"speakers": [8890,8891]}],"speakers": [{"serial":8890,"name": "Jacky","age": 30},{"serial":8891,"name": "Tom","age": 33}],"venues":[{"serial":1462,"name":"F151","category":"Conference Venues"},{"serial":1463,"name":"F152","category":"Super Man Venues"}]}
}

(2) load方法

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/12 21:27
# @Author  : Maple
# @File    : osconfeed.py
# @Software: PyCharm
import jsonJSON = r"D:\01-study\python\fluent_python\19-动态属性和特性\data\osconfeed.json"def load():with open(JSON) as f:# 返回Python对象return json.load(f)if __name__ == '__main__':r = load()print(type(r)) # <class 'dict'>print(r['schedule']['conference'])print(r)

2、使用动态属性访问Json数据(2)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/16 20:30
# @Author  : Maple
# @File    : 01-使用动态属性访问Json数据(2).py
# @Software: PyCharm"""改造FrozenJSON
使用__new__方法构造对象,代替build方法
"""from collections import  abc
from keyword import iskeyword
from osconfeed import loadclass FrozenJSON:def __new__(cls, arg):if isinstance(arg,abc.Mapping):return super().__new__(cls)elif isinstance(arg,abc.MutableSequence):return [cls(item) for item in arg]else:return argdef __init__(self,mapping):self.__data = {}for key,value in mapping.items():if iskeyword(key):key +='_'self.__data[key] = valuedef __getattr__(self, name):# 1-1如果实例中有某个对象,就直接返回属性对应的值# 2-1 比如去访问schedule属性,发现并没有"""""schedule": {"conference":[{"serial":115}],..."""if hasattr(self.__data,name):return self.__data[name]else:# 1-2否则就返回一个FrozenJSON对象# 1-3以下语法会直接去调用FrozenJSON.__new__方法,构建对象实例# 2-2 通过如下方式创建FrozenJSON对象,其中self.__data["schedule"]return FrozenJSON(self.__data[name])if __name__ == '__main__':# 1.初始化osconfeed = load()"""初始化流程分析1.首先走__new__方法,因为初始化参数是一个Mapping,所以会return super().__new__(cls),返回一个FrozenJSON实例化对象2.实例化对象传递到__init__方法,对其进行初始化:手先会生成一个实例属性__data,其value为空{}3.然后对其进行赋值,且其key为`schedule`,value为{'conference'.....}4.最终的结果是f_json有一个__data实例属性,然后其值为 {'schedule': {'conference': [{'serial': 115}],.....}"""f_json = FrozenJSON(osconfeed)print(f_json.__dict__)# 2.访问f_json的schedule属性"""访问schedule属性流程分析1.由于f_json中并没有 schedule 属性(只有__data属性),所以会走__getattr__的else逻辑2.通过FrozenJSON(self.__data[name])构造实例对象(走__new__和__init__逻辑),其中self.__data['schedule']为 {'conference': [{'serial': 115}],...}3.因此返回的f_json_schedule会有一个__data属性.而且其值为 {'conference': [{'serial': 115}],...},具体来说key为conference,value为[{"serial":115}]"""f_json_schedule = f_json.scheduleprint(f_json_schedule)# 3.访问 f_json_schedule 的 conference 属性"""访问schedule下的conference属性分析1.由于 f_json_schedule 中并没有 conference 属性(只有__data属性),所以会走__getattr__的else逻辑2.通过FrozenJSON(self.__data[name])构造实例对象列表(因为self.__data['conference']对应的value为list:[{'serial': 115}]走__new__和__init__逻辑),其中self.__data['conference']为 [{'serial': 115}]3.因此返回的f_json_schedule列表会有一个__data属性.而且其值为 {'serial': 115},具体来说key为 serial,value为115"""f_json_schedule_conference = f_json_schedule.conferenceprint(f_json_schedule_conference)# 4. 访问f_json_schedule_conference属性的serial属性"""访问schedule.conference下的serial属性分析1.由于 f_json_schedule_conference 中并没有 serial 属性(只有__data属性),所以会走__getattr__的else逻辑2.通过FrozenJSON(self.__data[name])返回serial对应的值(因为self.__data['serial']对应的value为115,会直接返回值本身"""result = f_json_schedule_conference[0].serialprint(result) # 115

3、使用shelve模块访问Json

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/13 21:05
# @Author  : Maple
# @File    : 03-使用shelve模块访问Json.py
# @Software: PyCharm"""
schedule2.py: traversing OSCON schedule data>>> import shelve>>> db = shelve.open(DB_NAME)>>> if CONFERENCE not in db: load_db(db)# BEGIN SCHEDULE2_DEMO>>> DbRecord.set_db(db)  # <1>>>> event = DbRecord.fetch('event.33950')  # <2>>>> event  # <3><Event 'There *Will* Be Bugs'>>>> event.venue  # <4><DbRecord serial='venue.1449'>>>> event.venue.name  # <5>'Portland 251'>>> for spkr in event.speakers:  # <6>...     print('{0.serial}: {0.name}'.format(spkr))...speaker.3471: Anna Martelli Ravenscroftspeaker.5199: Alex Martelli# END SCHEDULE2_DEMO>>> db.close()"""# BEGIN SCHEDULE2_RECORD
import warnings
import inspect  # <1>import osconfeed
import shelveDB_NAME = 'data/schedule2_db'  # <2>
CONFERENCE = 'conference.115'class Record:def __init__(self, **kwargs):self.__dict__.update(kwargs)def __eq__(self, other):  # <3>if isinstance(other, Record):return self.__dict__ == other.__dict__else:return NotImplemented
# END SCHEDULE2_RECORD# BEGIN SCHEDULE2_DBRECORD
class MissingDatabaseError(RuntimeError):"""Raised when a database is required but was not set."""  # <1>class DbRecord(Record):  # <2>__db = None  # <3>@staticmethod  # <4>def set_db(db):DbRecord.__db = db  # <5>@staticmethod  # <6>def get_db():return DbRecord.__db@classmethod  # <7>def fetch(cls, ident):db = cls.get_db()try:return db[ident]  # <8>except TypeError:if db is None:  # <9>msg = "database not set; call '{}.set_db(my_db)'"raise MissingDatabaseError(msg.format(cls.__name__))else:  # <10>raisedef __repr__(self):# 如果DbRecord有serial属性,则返回对应serial对象的value值if hasattr(self, 'serial'):  # <11># cls_name = 'DbRecord'cls_name = self.__class__.__name__return '<{} serial={!r}>'.format(cls_name, self.serial)else:return super().__repr__()  # <12>
# END SCHEDULE2_DBRECORD# BEGIN SCHEDULE2_EVENT
class Event(DbRecord):  # <1>@propertydef venue(self):# 注意venue_serial是event数据中的一个key,里面记录了venue的serial idkey = 'venue.{}'.format(self.venue_serial)# self.__class__获得是Event类,然后通过类调用类方法fetch(继承自DbRecord)# 为何不直接用self.fetch(key),因为如果Event中如果有一个属性名为fetch,那么self.fetch就直接获取`fetch`属性对应的值了# 而不是调用类的fetch方法: 返回db[key]return self.__class__.fetch(key)  # <2>@propertydef speakers(self):if not hasattr(self, '_speaker_objs'):  # <3># event中有一个speaker属性,里面记录了该event对应的speakers id列表spkr_serials = self.__dict__['speakers']  # <4>fetch = self.__class__.fetch  # <5># 返回db[speaker.xx]对应的值,并存放在_speaker_objs属性中self._speaker_objs = [fetch('speaker.{}'.format(key))for key in spkr_serials]  # <6>return self._speaker_objs  # <7>def __repr__(self):# 如果记录中name属性,则使用如何格式化方式展示数据if hasattr(self, 'name'):  # <8>cls_name = self.__class__.__name__return '<{} {!r}>'.format(cls_name, self.name)else:return super().__repr__()  # <9>
# END SCHEDULE2_EVENT# BEGIN SCHEDULE2_LOAD
def load_db(db):raw_data = osconfeed.load()warnings.warn('loading ' + DB_NAME)for collection, rec_list in raw_data['schedule'].items():record_type = collection[:-1]  # <1># 比如event变成Event,speakers变成Speakerscls_name = record_type.capitalize()  # <2># 从模块的全局作用域中获取cls_name名字对应的对象(也有可能是类,比如Event);如果找不到对象,使用DbRecordcls = globals().get(cls_name, DbRecord)  # <3>#  如果获取的对象是类 并且是DbRecord类的子类if inspect.isclass(cls) and issubclass(cls, DbRecord):  # <4>factory = cls  # <5>else:factory = DbRecord  # <6># rec_list的Sample data:""""events":[{"serial":4505,"name": "Go to the island","event_type":"escape"},{"serial":4506,"name": "To be my best","event_type":"study"}],"""for record in rec_list:  # <7># record的Sample data:"""{"serial":4505,"name": "Go to the island","event_type":"escape"},"""# Key = Event.4505key = '{}.{}'.format(record_type, record['serial'])# record的serial属性值被替换"""{"serial":Event.4505,"name": "Go to the island","event_type":"escape"},"""record['serial'] = key# 将新的record放到db中,具体的数据类型取决于 factory,而factory又取决于全局作用域中定义的类(本例中定义了Event类)## 1.首先raw_data['Schedule']中有四个Key,其经过转换后(掐尾,以及首字母大写)分别变成:Conference,Event,Speaker,Venus## 2.由于本文件中只定义了上面4个key中的一个类Event,因此只有对应的Event数据以Event类型数据存放,其它都是以DbRecord##   类型存放db[key] = factory(**record)  # <8>
# END SCHEDULE2_LOADif __name__ == '__main__':#1. factory(**record)数据类型的验证cls1 = globals().get('Event', DbRecord)print(cls1) # <class '__main__.Event'>## Speaker, Conference 和 Venus 类都未定义,所以factory都指向DbRecordcls2 = globals().get('Speaker', DbRecord)print(cls2) # <class '__main__.DbRecord'>cls3 = globals().get('Conference', DbRecord)print(cls3) # <class '__main__.DbRecord'>cls4 = globals().get('Venus', DbRecord)print(cls4) # <class '__main__.DbRecord'># 2.创建db:会在指定目录自动创建db = shelve.open(DB_NAME)# 3.将osconfeed.json数据加载到db中if CONFERENCE not in db:load_db(db)print(db)for key,value in db.items():print('Key:',key,' value:',value)"""打印结果如下:# 说明conference.115对应的value为何是<DbRecord...>,首先是Event类中__repr__方法的定义,由于conferenc.115没有名字为name的属性因此会去调用DbRecord中的__repr__方法,而其返回的是:'<{} serial={!r}>'.format(cls_name, self.serial)Key: conference.115  value: <DbRecord serial='conference.115'># event.4505对应的value,由于Event类中__repr__方法的定义,由于event.4505有名字为name的属性因此直接返回:  return '<{} {!r}>'.format(cls_name, self.name)Key: event.4505  value: <Event 'Go to the island'>Key: event.4506  value: <Event 'To be my best'># 同conferenceKey: speaker.8890  value: <DbRecord serial='speaker.8890'>Key: speaker.8891  value: <DbRecord serial='speaker.8891'>Key: venu.1462  value: <DbRecord serial='venu.1462'>"""# 4.将db赋值给 DbRecordDbRecord.set_db(db)# 5.获取db中key = event.4505对应的valueevent = DbRecord.fetch('event.4505')# 由于Event类中定义了__repr__方法,打印event是会调用该方法# return '<{} {!r}>'.format(cls_name, self.name)# 其中cls_name是类名,self.name是name关键字对应的Valueprint(event) # <Event 'Go to the island'>## 观察该event中的属性print(event.__dict__)# {'serial': 'event.4505', 'name': 'Go to the island', 'event_type': 'escape', 'venus_serial': 1462, 'speakers': [8890, 8891]}# 6.打印该event的中venue:由于给Event类中venue方法添加了property属性,所以能够像属性一样访问该方法print(event.venue)  # <DbRecord serial='venue.1462'>print(event.venue.name) # F151#7.打印speakersfor spkr in event.speakers:"""speaker.8890:Jackyspeaker.8891:Tom"""print('{0.serial}:{0.name}'.format(spkr))

4、使用特性验证属性(1)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/16 8:27
# @Author  : Maple
# @File    : 04-使用特性验证属性(1).py
# @Software: PyCharmclass LineItem:"""需要对类的属性weight做一些限制(使用装饰器的方式实现-比较新的一种方式)>> 其值必须大0>> 可以通过特性的方式实现"""def __init__(self,description,weight,price):self.description = descriptionself.weight = weightself.price = price@propertydef weight(self):# weight属性的值真正存放于__weight中return self.__weight@weight.setterdef weight(self,value):# weight的值必须大于0if value > 0:self.__weight = valueelse:raise ValueError('weight must be > 0')def subtotal(self):return self.weight * self.priceif __name__ == '__main__':# 1.查看LineItem类的属性item = LineItem('Bread',20,100)## 注意观察,item的属性有一个是_LineItem__weight,表明weight属性值真正存放于__weight属性中print(item.__dict__) # {'description': 'Bread', '_LineItem__weight': 20, 'price': 100}# 2. 特性验证:weight是否能设置小于0的值# 以下代码会报错item2 = LineItem('Bread', -10, 100) # ValueError: weight must be > 0

5、使用特性验证属性(2)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/16 8:38
# @Author  : Maple
# @File    : 05-使用特性验证属性(2).py
# @Software: PyCharmclass LineItem:"""需要对类的属性weight做一些限制(使用经典方式实现-手动配置和装载property属性)>> 其值必须大0>> 可以通过特性的方式实现"""def __init__(self,description,weight,price):self.description = descriptionself.weight = weightself.price = pricedef subtotal(self):return self.weight * self.price# 方法名以get开头只是一种约定俗成def get_weight(self):return self.__weight# 方法名以set开头只是一种约定俗成def set_weitht(self,value):if value > 0:self.__weight = valueelse:raise ValueError('weight must be > 0')# 手动为weight添加特性# property 构造方法的完整签名: property(gfet_None,fset=None,fdel=None,doc= None)# 本案例构造了一个特性weight(注意与属性weight同名,此时就涉及到特性与属性优先级的问题,留待下节分解),且为该特性添加了#  get_weight和set_weitht方法,这样当通过obj.weight方式访问属性或者赋值时,就会分别走这两个函数的逻辑weight = property(get_weight,set_weitht)if __name__ == '__main__':# 1. 特性验证:weight是否能设置小于0的值# 以下代码会报错try:item1 = LineItem('Bread', -10, 100)  # ValueError: weight must be > 0except ValueError as e:print(e)# 2.特性验证: 是否能够将weight的值修改为复数item2 = LineItem('Milk', 10, 200)print(item2.weight) # 10# 2-1 修改weight的值为另外一个大于0的值item2.weight = 20print(item2.weight) # 20# 2-2 试图修改weight的值为复数,会报错item2.weight = -20 # ValueError: weight must be > 0

6、类属性,实例属性和特性的优先级

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/16 8:50
# @Author  : Maple
# @File    : 06-类属性,实例属性和特性的优先级.py
# @Software: PyCharm"""
1. 实例属性会遮盖类属性
2. 实例属性不会遮盖类特性"""class Person:# 类属性data = "I am a Person"# 特性@propertydef prop(self):return 'the prop value'if __name__ == '__main__':# 1. 实例属性会遮盖类属性print('*****1. 实例属性会遮盖类属性************')p = Person()## 1-1 返回实例属性:为空,因为未定义实例属性print(vars(p))## 1-2 访问类属性print(p.data) # I am a Person## 1-3 添加实例属性p.data = 'Maple'# 此时实例会有一个data实例属性print(vars(p)) # {'data': 'Maple'}## 1-4 再次通过实例访问data属性# 此时访问到的是实例属性,而不是类属性print(p.data) # Maple## 1-5 类属性data的值并未发生print(Person.data) # I am a Person# 2. 实例属性不会遮盖类特性print('*****2. 实例属性不会遮盖类特性*************')## 2-1 通过类访问类特性prop,返回特性对象print(Person.prop) # <property object at 0x0000015D9E39A180>## 2-2 通过实例对象访问特性prop,返回 return的值print(p.prop) # the prop value## 2-3 尝试直接设置prop实例属性,会失败try:p.prop = 'foo'except Exception as e:print(e) # can't set attribute## 2-4 直接通过self.__dict__方法添加属性p.__dict__['prop'] = 'foo'# 此时实例对象p中会新增prop实例属性print(vars(p)) #{'data': 'Maple', 'prop': 'foo'}## 2-5 但是此时通过实例访问prop,仍然访问的特性(而非实例属性)print(p.prop) # the prop value## 2-6 覆盖prop特性## 此时pro还是特性print(Person.__dict__) ## {...'prop': <property object at 0x000001AC48F8A180>,...}## 覆盖prop特性,此时prop变成类属性Person.prop = 'bar'print(Person.__dict__)# {...,'prop': 'bar'...}## 2-7 由于实例属性会遮盖类属性# 此时访问到的就是 实例属性print(p.prop) # foo# 3 为类新增一个data`特性`,此时特性会遮盖`实例属性`Person.data =property(lambda self: "I am Person prop data")# 3-1 此时再访问data就是,访问读取特性的值print(p.data) # I am Person prop data## 3-2 删除特性,再次访问就是访问实例属性del Person.dataprint(p.data) # Maple

7、定义特性工厂

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/16 9:22
# @Author  : Maple
# @File    : 07-定义特性工厂.py
# @Software: PyCharmdef quantity(storage_name):def qty_getter(instance):return instance.__dict__[storage_name]def qty_setter(instance,value):if value > 0:instance.__dict__[storage_name] = valueelse:raise ValueError('Value must be > 0')return property(qty_getter,qty_setter)class LineItem:# 以下是两个特性weight = quantity('weight')price = quantity('price')def __init__(self,description,weight,price):self.description = description# 以下是两个与特性同名的两个属性self.weight = weightself.price = pricedef subtotal(self):return self.weight * self.priceif __name__ == '__main__':# 1.查看类的属性,可以发现weight和price是两个特性print(LineItem.__dict__) ## {...'weight': <property object at 0x000001BAB116A130>, 'price': <property object at 0x000001BAB1176680>...}computer = LineItem('Computer',20,10000)# 2. 实例有两个同名的属性:weight和priceprint(computer.__dict__) # {'description': 'Computer', 'weight': 20, 'price': 10000}# 3.特性的工作流程## (1) 通过实例访问weight,由于特性优先级大于实例属性,所以实际上会走特性的qty_getter方法## (2) 所以返回computer.__dict['weight'],即实例属性中存放的值print(computer.weight) # 20## (1) 通过实例修改weight,由于特性优先级大于实例属性,所以实际上会走特性的qty_setter方法## (2) 先判断新值是否大于0,如果满足条件,则执行:computer.__dict['weight'] = value,即给实例属性赋予新值computer.weight = 30print(computer.weight) # 30## (1) 通过实例修改weight,由于特性优先级大于实例属性,所以实际上会走特性的qty_setter方法## (2) 先判断新值是否小于0,如果小于0,则会抛出ValueErrorcomputer.weight = -30 # ValueError: Value must be > 0

8、删除属性

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/3/16 10:12
# @Author  : Maple
# @File    : 08-删除属性.py
# @Software: PyCharm"""
不常用,仅作展示
"""class BlackKnight:def __init__(self):self.members = ['am arm','another arm','a leg','another leg']self.phrase = ["'Tis but a scrath'","It's just a fresh wound","I'm invincible!","All right,we'll call it a draw:"]@propertydef member(self):print('next member is:')return self.members[0]@member.deleterdef member(self):text = 'BLACK KNIGHT (loses {}) \n -- {}'print(text.format(self.members.pop(0),self.phrase.pop(0)))if __name__ == '__main__':knight = BlackKnight()# next member is:# am armprint(knight.member)# BLACK KNIGHT (loses am arm)#  -- 'Tis but a scrath'del knight.member# next member is:# another armprint(knight.member)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/750742.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务技术栈之rabbitMQ高级(二)

我们该如何确保MQ消息的可靠性&#xff1f; 如果真的发送失败&#xff0c;有没有其它的兜底方案&#xff1f; 这些问题&#xff0c;在这一次的学习中都会找到答案。 生产者的可靠性 首先&#xff0c;我们一起分析一下消息丢失的可能性有哪些。 消息从发送者发送消息&#…

StarRocks实战——云览科技存算分离实践

目录 背景 一、平台现状&痛点 1.1 使用组件多&#xff0c;维护成本高 1.2 链路冗长&#xff0c;数据时效性难以保证 1.3 服务稳定性不足 二、StarRocks 存算分离调研 2.1 性能对比 2.2 易用性 2.3 存储成本 三、StarRocks 存算分离实践 3.1 查询优化 3.1.1 物化…

Linux网络编程: 以太网帧Frame/ARP/RARP详解

一、TCP/IP五层模型 物理层&#xff08;Physical Layer&#xff09;&#xff1a;物理层是最底层&#xff0c;负责传输比特流&#xff08;bitstream&#xff09;以及物理介质的传输方式。它定义了如何在物理媒介上传输原始的比特流&#xff0c;例如通过电缆、光纤或无线传输等。…

【论文阅读】Diffused Heads: Diffusion Models Beat GANs on Talking-Face Generation

Diffused Heads: 扩散模型在说话人脸生成方面击败GANs paper&#xff1a;[2301.03396] Diffused Heads: Diffusion Models Beat GANs on Talking-Face Generation (arxiv.org) code&#xff1a;MStypulkowski/diffused-heads: Official repository for Diffused Heads: Diffu…

R:简易的Circos图

library(grid) library(circlize) library(RColorBrewer) library(ComplexHeatmap) setwd("C:/Users/fordata/Downloads/Circos") # 创建颜色调色板 coul <- colorRampPalette(brewer.pal(9, "Set3"))(12) # 读取基因组数据 genome <- read.table(ci…

贪心算法(两个实例)

例一&#xff1a;调度问题 问题&#xff1a;由n项任务&#xff0c;每项任务的加工时间已知&#xff0c;从零时刻开始陆续加入一台机器上去加工&#xff0c;每个任务完成的时间是从0时刻到任务加工截至的时间。 求总完成时间&#xff08;所有任务完成时间最短计划方案&#xf…

情感分析技术调研:传统方法到深度学习的全景观

目录 基于规则的方法 字典 基于机器学习的方法 贝叶斯分类 支持向量机 基于深度学习的方法 Transformer系列&#xff0c;Bert家族--以Albert举例 自监督学习 迁移学习和领域适应 对抗训练 前言 本文讨论的是截止到本文发出时间&#xff08;2024年&#xff09;为止&am…

PostMan测试文件上传

后端代码 package com.example.backend.controller;import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.StrUtil; import com.example.backend.common.Result; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; import org…

Educational Codeforces Round 163 (Rated for Div. 2)题解

A. Special Characters&#xff08;Problem - A - Codeforces&#xff09; 题目大意&#xff1a;给定一个正整数n&#xff0c;需要输出一个字符串s&#xff0c;s中需要有n个满足要求的字符&#xff0c;对于字符的要求&#xff1a;对于该字符&#xff0c;它的左右有且仅有一个字…

React Router 参数使用详解

React Router 参数使用详解 React Router 是 React 中用于处理路由的常用库&#xff0c;它提供了丰富的功能来管理应用程序的导航和路由状态。在 React Router 中&#xff0c;我们经常需要使用不同类型的参数来处理路由信息&#xff0c;包括 params 参数、search 参数和 state…

数据血缘实现原理

市面上其实针对数据血缘的产品有很多,像阿里DataWorks的数据地图、字节的DataLeap以及非常火的开源产品Apache Atlas都是非常好用工具产品。但是本质上是想通过这篇文章,让小伙伴们在使用这些产品的时候多去思考这些产品背后的实现原理。 1、前言 大数据时代,数据的来源极…

Python Web开发记录 Day9:Django part3 用户管理

名人说&#xff1a;莫道桑榆晚&#xff0c;为霞尚满天。——刘禹锡&#xff08;刘梦得&#xff0c;诗豪&#xff09; 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 1、数据库准备2、用户列表3、新建用户4、编辑用…

科研学习|论文解读——美国政治经济中的权力:网络分析(JASIST, 2019)

论文原题目 Power in the U.S. political economy: A network analysis 摘要 美国政治经济的许多特征产生于大型政治和经济机构之间的互动&#xff0c;然而我们对它们的互动性质和这些机构之间的权力分配知之甚少。在本文中&#xff0c;对总部设在美国的组织的网络进行了详细的…

突破编程_C++_面试(STL 编程 map 与 multimap)

面试题 1 &#xff1a;解释一下 std::map 和 std::multimap 之间的主要区别是什么&#xff1f; std::map 和 std::multimap 都是 C 标准模板库&#xff08;STL&#xff09;中的关联容器&#xff0c;它们提供了键值对的存储和快速查找功能。然而&#xff0c;它们之间存在着一些…

学习shell脚本

文章目录 什么是shell脚本为什么要学习shell脚本第一个脚本编写与执行 简单的shell脚本练习简单案例脚本的执行方式差异(source、sh script、./script) 如何使用shell脚本的判断式利用test命令的测试功能利用判断符号[ ]shell脚本的默认变量($0、$1...) shell脚本的条件判断式利…

C语言每日一题—判断是否为魔方矩阵

魔方矩阵 在魔方阵中&#xff0c;所有的行、列和对角线都拥有相同的和。例如&#xff1a;17 24 1 8 15 23 5 7 14 16 4 9 24 6 13 20 22 和 3 5 710 12 19 21 3 8 1 611 18 25 2 9 写一个程序读入一个二维整型数组并…

【Unity知识点详解】Button点击事件拓展,单击、双击、长按实现

Button拓展 今天来聊一下关于Button的事件拓展&#xff0c;这里只是拿Button来举例&#xff0c;Unity中其他的UI组件如Toggle、Slider等都也适用。 我们知道在Button中我们可以通过onClick的方式来添加点击事件&#xff0c;但在游戏开发过程中我们往往对Button有着更多的功能需…

2.3 物理层设备

2.3 物理层设备 &#xff08;一&#xff09;中继器 产生原因 由于存在损耗&#xff0c;在线路上传输的信号功率会逐渐衰减&#xff0c;衰减到一定程度时将造成信号失真&#xff0c;因此会导致接收错误。 中继器的功能 对信号进行再生和还原&#xff0c;对衰减的信号进行放大…

VMware Worksation 问题

几个晚上在虚拟机装了好多东西&#xff0c;配置mysql&#xff0c;配置docker、Git工具等等&#xff0c;可能废寝忘食导致太困强制关了虚拟机&#xff0c;结果第二天晚上回来发现打不开&#xff0c;心态直接崩了。 问题&#xff1a; 疯狂百度告知要删除后缀为.lck的文件夹及文件…

网络爬虫丨基于scrapy+mysql爬取博客信息

文章目录 写在前面实验描述实验框架实验需求 实验内容1.安装依赖库2.创建Scrapy项目3.配置系统设置4.配置管道文件5.连接数据库6.分析要爬取的内容7.编写爬虫文件 运行结果写在后面 写在前面 本期内容&#xff1a;基于scrapymysql爬取博客信息并保存到数据库中 实验需求 ana…