流畅的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)
相关文章:
流畅的Python(十九)-动态属性和特性
一、核心要义 在Python中,数据的属性和处理数据的方法,统称属性。方法,只是可调用的属性。除了这两者之外,我们还可以创建特性(property),在不改变类接口的前提下,使用存取方法(即读值方法和设值方法)修改数据属性。 二、代码示例 0、相关知识点 #!/usr/bin/env…...
确保云原生部署中的网络安全
数字环境正在以惊人的速度发展,组织正在迅速采用云原生部署和现代化使用微服务和容器构建的应用程序(通常运行在 Kubernetes 等平台上),以推动增长。 无论我们谈论可扩展性、效率还是灵活性,对于努力提供无与伦比的用…...
【分布式websocket 】前端vuex管理客户端消息crud!使用localStorage来存储【第19期】
前言 聊天系统客户端是要存储消息的,因为所有所有的历史消息都从服务器拉的话一方面服务器压力大,另一方面也耗费用户流量。所以客户端存储消息是势在必行的。如何存储呢上一篇文章也写了,大概就是浏览器的话是localStorage或者IndexedDB。然…...
venv uvicorn python 虚拟服务器外网无法访问
python -m venv .venv source ./.venv/bin/activate pip install -r requirements.txt ./run.sh source ./.venv/bin/activate uvicorn main:app --reload 虚拟web服务器外网访问控制台启动命令用以下代码启动 uvicorn main:app --host 0.0.0.0 --port 8501 --reload 启动到后…...
一款博客网站源码
一款博客网站源码 源码软件库 为大家内置了主题 清爽又强大真正的永久可用的一条源码,该版本为整合版本,内置了Joe主题,搭建后直接启用即可~ 安装环境要求: PHP 7.2 以上 MySQL, PostgreSQL, SQLite 任意一种数据库支持ÿ…...
Mr-Robot1靶场练习靶场推荐小白入门练习靶场渗透靶场bp爆破wordpress
下载链接: Mr-Robot: 1 ~ VulnHub 安装: 打开vxbox,菜单栏----管理----导入虚拟电脑 选择下载完的ova文件,并修改想要保存的位置(也可以保持默认位置) 导入完成后可以根据自己的情况去配置网络链接方式 完成…...
数据仓库的设计开发应用(三)
目录 五、数据仓库的实施(一)数据仓库的创建(二)数据抽取转换加载 六、数据仓库系统的开发(一)开发任务(二)开发方法(三)系统测试 七、数据仓库系统的应用&am…...
【04】WebAPI
WebAPI 和标准库不同,WebAPI 是浏览器提供的一套 API,用于操作浏览器窗口和界面 WebAPI 中包含两个部分: BOM:Browser Object Model,浏览器模型,提供和浏览器相关的操作DOM:Document Object Model,文档模型,提供和页面相关的操作BOM BOM 提供了一系列的对象和函数,…...
数据预处理在数据挖掘中的重要性
数据挖掘作为从大量数据中提取有用信息和知识的过程,其结果的准确性和可靠性直接受到数据质量的影响。因此,数据预处理在数据挖掘中扮演着至关重要的角色。让我们探讨数据质量对数据挖掘结果的影响,并介绍常见的数据预处理方法以及它们如何提…...
Java并发编程—JUC线程池架构
Java并发编程(JUC,Java Utilities Concurrency)中的线程池架构是Java提供的一种用于管理和复用线程的机制。线程池的主要目标是减少线程创建和销毁的开销,提高系统的响应速度,并通过合理的线程管理和资源分配ÿ…...
Android input输入子系统
一.Android input输入子系统简介 Input系统是Android系统中负责处理用户输入操作的核心组件,它负责从各种输入设备(如屏幕、键盘、鼠标等)获取原始的输入事件(如按键、触摸、滑动等),并将其转换为Android应…...
如何在webapp中于动发布一个应用
目录 第一步:在webapp文件夹内自定义文件夹第二步:生成一个文本,并把后缀改为 .html第三步:进入bin文件夹打开服务第四步:打开方式选择java第六步:输入你想输出的东西第七步:双击运行即可 第一步…...
部署一个本地的ChatGPT(Ollama)
一 下载Ollama Ollama下载地址:https://ollama.com/download 下载完后 二 安装运行 双击下载好的OllamaSetup.exe开发 安装Ollama: 安装完成后,多了一个Ollama的菜单如下图 : Ollama安装好默认是配置开机运行,如果没有运行可以在…...
Vue 3中的reactive:响应式状态的全面管理
🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…...
【网络】详解HTTPS及探究加密过程
目录 一、什么是HTTPS1、加密解密是什么2、为什么要加密3、常见的加密方式1、对称加密2、非对称加密 二、探究HTTPS如何实现加密1、方案一----只使用对称加密2、方案二----只使用非对称加密3、方案三----双方都使用非对称加密4、方案四----非对称加密 对称加密5、中间人攻击6、…...
【C语言】字符与字符串---从入门到入土级详解
🦄个人主页:修修修也 🎏所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 目录 一.字符类型和字符数组(串)简介 1.ASCII 2.定义,初始化,使用 1>字符的定义及初始化 2>字符串的定义及初始化 二.…...
Github Copilot 工具,无需账号,一键激活
① 无需账号,100%认证成功!0风险,可联网可更新,,支持copilot版本升级,支持chat ② 支持windows、mac、linux系统等设备 ③一号通用,支持所有IDE(AppCode,CLion,DataGrip,GoLand,IntelliJ IDEA …...
node: -max-old-space-size=xxx is not allowed in NODE_OPTIONS
问题描述 在启动node项目时,出现了OOM参照网上的处理方案,设置了环境变量: export NODE_OPTIONS"–max-old-space-size8192"当再次通过npm run docs:dev运行node项目的时候出现了如下错误: node: -max-old-space-siz…...
k8s编排系统
Kubernetes(简称K8s)是一个开源的容器编排系统,由Google基于其内部的Borg项目开发,并于2014年正式对外发布。目前,Kubernetes已成为云原生计算基金会(Cloud Native Computing Foundation, CNCF)…...
samba服务器的配置
需求:在Linux上搭建一个文件共享服务,创建不同的账号给予不同的权限,在windows可以直接访问该共享目录 介绍 Samba 是一个强大的工具,使得不同操作系统之间可以无缝地共享文件和资源,促进了跨平台环境下的协作和通信…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...
Matlab实现任意伪彩色图像可视化显示
Matlab实现任意伪彩色图像可视化显示 1、灰度原始图像2、RGB彩色原始图像 在科研研究中,如何展示好看的实验结果图像非常重要!!! 1、灰度原始图像 灰度图像每个像素点只有一个数值,代表该点的亮度(或…...
