首页 文章 精选 留言 我的

精选列表

搜索[监督学习],共10000篇文章
优秀的个人博客,低调大师

python描述符学习

目录 一、对象属性的访问控制 二、描述符基本理解 三、基本使用 四、使用描述符完成property、classmethod、staticmethod自定义实现 1、property的自定义实现 2、classmethod的自定义实现 3、关于实例方法的思考 4、实例方法的自定义实现 5、静态方法的自定义实现 五、总结 一、对象属性的访问控制 看一下这个例子,我们创建一个学生类,提供名字和年龄的属性,然后实例化一个对象,并显示他的信息。 class Student: def __init__(self, name, age): self.name = name self.age = age stu = Student('zlw', 26) print(stu.name) # 名字是'zlw' print(stu.age) # 年龄是26 # 对象的名字和年龄被正常打印,good # 但是,Student类没办法控制用户在实例化时的行为 stu = Student(26, 'zlw') print(stu.name) # 名字是26 print(stu.age) # 年龄是'zlw' 我们可以这样做: class Student: def __init__(self, name, age): # 检测每一次实例化时的参数类型 if not isinstance(name, str): raise TypeError('name必须是str类型') if not isinstance(age, int): raise TypeError('age必须是int类型') self.name = name self.age = age 我们可以在init函数中控制实例化时的输入类型,不过这有2个问题: 1、只能控制实例化时的类型,对于已经实例化完成的对象,可以直接通过stu.name = 23的形式来重新赋值 2、实例化传递的参数越多,那么类型检测的代码也越多,而且类型检测代码和初始化代码写在一起,两者干的事情不一样,逻辑不是一个层面的,都写在init函数里并不合适 我们可以这样写: # 省略了age的处理,方式是一样的 class Student: def __init__(self, name): if not isinstance(name, str): raise TypeError('name属性值类型必须是str类型') self.__name = name @property def name(self): return self.__name @name.setter def name(self, value): if not isinstance(value, str): raise TypeError('name属性值类型必须是str类型') self.__name = value # 这样写就可保证在实例化和已经完成实例化的对象赋值时的类型检查问题了。 # 不过还是有一个问题,就是属性越多,这个类型检查的代码就会不断增加,并且堆积在Student类中 # 我们应该将类型检查的代码单独隔离开,但同时又可以和Student类进行交互 使用python的描述符来处理。 二、描述符基本理解 python的描述符,有几个理解: 1、描述符是一个类 2、描述符的目的是对属性的访问控制 3、描述符将访问控制和业务类分离开,业务类处理业务逻辑,描述符处理属性访问控制 4、描述符是一个特殊类型的类,所谓特殊,就是自定义了__get__、__set__、__delete__方法的类,这种类就叫描述符 5、单独一个描述符没有啥意义,描述符要作用于某一个具体的业务类,为这个业务类提供属性访问控制的功能 6、属性访问可不仅仅是指数据属性的访问,对于函数属性的访问也可以控制。 7、使用类的__setattr__、__getattr__、__delattr__只能全局控制所有属性,而描述符可以有针对的控制部分属性 三、基本使用 class DescName: dic = {} def __init__(self, value_type): self.value_type = value_type def __get__(self, instance, owner): print('get running...') return self.dic.get(instance, None) def __set__(self, instance, value): print('set running...') if not isinstance(value, self.value_type): raise TypeError('名字必须是str类型') self.dic[instance] = value class Student: name = DescName(str) def __init__(self, name, age): self.name = name self.age = age stu1 = Student('小明', 26) print(stu1.name, stu1.age) # 小明,26 stu2 = Student('小红', 25) print(stu2.name, stu2.age) # 小红,25 上方代码中,我定义了一个Student类用于表示一个学生。学生有两个属性name和age,对于age我并没有设置任何的控制,对于name我要求属性值必须是str类型。我们可以定义一个DescName描述符类来单独针对name这个属性提供控制功能。DescName描述符会对name的值进行类型判定,如果是非str类型就会报错。 请注意DesnName的__set__方法中的:self.dic[instance] = value这句代码。 考虑到Student类会实例化出很多不同的学生对象,这些学生对象是共享同一个描述符对象Student.name的,因为这是一个类属性,我们要在DescName描述符中保存不同对象的name值,就需要区分不同的对象,我这里使用字典,将每一个实例作为字典的key来保存对应实例的name值。 不过这里也会有一个问题,就是字典的key必须是可hash对象,如果实例是可变对象比如list,则无法使用这种方法保存属性值,可以考虑转换成一个不可变对象后处理,比如使用字符串表示不同的实例对象。 基本使用的代码中,每个实例对象的属性值实际是保存在共享描述符对象中的。 四、使用描述符完成property、classmethod、staticmethod自定义实现 1、property的自定义实现 # property是一个装饰器,所以底层原理就是把描述符当做一个装饰器并作为类属性存在 class DescName: # 描述符,后续当做装饰器使用,是一个类装饰器,返回的对象是描述符对象 def __init__(self, func): # 首次装饰必须返回一个描述符对象,func是装饰的函数name self.get_func = func self.set_func = None self.delete_func = None # 以上3个属性用于保存用户定义的属性访问逻辑代码 def __get__(self, instance, owner): return self.get_func(instance) # 访问get的时候返回用户定义的函数输出 def setter(self, func): self.set_func = func return self # 提供一个setter用于处理set逻辑,setter是一个函数装饰器 def __set__(self, instance, value): return self.set_func(instance, value) # 访问set的时候调用用户定义函数 def deleter(self, func): # 提供deleter函数装饰器处理delete逻辑 self.delete_func = func return self def __delete__(self, instance): return self.delete_func(instance) # 访问del的时候调用用户定义函数 class Student: # 业务类 def __init__(self, name, age): self.__name = name # 在业务类中隐藏属性 self.age = age @DescName # 和propery是一样的,返回对象就是一个描述符对象,被name引用,且是类属性 def name(self): return self.__name @name.setter # set设置 def name(self, value): if not isinstance(value, str): raise TypeError('必须是str') self.__name = value @name.deleter # 删除设置 def name(self): print('你不能删除名字属性') stu1 = Student('zlw', 26) # 实例化的时候会自动调用描述符的set print(stu1.name, stu1.age) # 打印的时候会调用描述符的get stu1.name = 'wj' print(stu1.name, stu1.age) del stu1.name # 删除的时候调用描述符的delete 2、classmethod的自定义实现 class DescClassMethod: # 描述符,用于作为装饰器,提供类方法功能 def __init__(self, func): self.get_func = func self.cls = None # 保存当前类对象 def __get__(self, instance, owner): # 被装饰的时候,保存当前类对象,返回描述符对象 self.cls = owner return self def __call__(self, *args, **kwargs): # 类方法一般直接运行,也就是描述符对象被运行 return self.get_func(self.cls, *args, **kwargs) # 传入当前类对象,用户就觉得是自动传入 class Student: def __init__(self, name, age): self.name = name self.age = age def learn(self): print(f'{self.name} is learning...') @DescClassMethod # 类方法描述符,让被装饰的函数变成类绑定方法,自动传入类对象 def show_class(cls, school_name): print(f'this is class --> {cls.__name__}') print('输入的参数是:', school_name) stu = Student('zlw', 26) stu.learn() # 实例方法 Student.show_class('北京大学') # 类方法 3、关于实例方法的思考 # 这里是普通的类和一个实例方法定义,不同对象在调用的时候会将自己传入self class Student: def __init__(self, name, age): self.name = name self.age = age def learn(self): print(f'{self.name} is learning...') stu1 = Student('小明', 26) stu2 = Student('小红', 25) stu1.learn() # '小明' is learning... stu2.learn() # '小红' is learning... 通过描述符,我们可以实现一个类似classmethod类方法的功能,这功能可以实现当我们调用类方法的时候,python会自动将类对象传入cls中。那这就引发另一个问题,对于实例方法,我们在通过实例对象调用的时候,也会将实例对象自己传入self中,那这个实现和类方法的实现,是不是一样的思路? 仔细查看描述符的__get__函数可以发现,此函数的参数有instance和owner,这个owner被我们用作cls,那么,instance不就代表实例对象吗?如果我们把istance传入call,不就可以实现类似实例方法的功能了吗?试试看: 4、实例方法的自定义实现 class SelfMethod: # 描述符,用于处理实例方法功能 def __init__(self, func): self.get_func = func self.instance = None # 保存实例对象 def __get__(self, instance, owner): self.instance = instance # 保存实例对象 return self def __call__(self, *args, **kwargs): return self.get_func(self.instance, *args, **kwargs) # 将实例对象传入 class Student: def __init__(self, name, age): self.name = name self.age = age @SelfMethod # 使用描述符作为装饰器,让learn函数变成实例绑定方法 def learn(self): print(f'{self.name} is learning...') stu1 = Student('小明', 26) stu2 = Student('小红', 25) stu1.learn() # '小明' is learning... # 调用的时候,会传入stu1实例 stu2.learn() # '小红' is learning... # 调用的时候,会传入stu2实例 print(stu1.__dict__) print(Student.__dict__) # 类中显示learn是一个描述符对象 以上通过描述符可以自定义类似实例方法的效果,自动传入实例给self。不过这种实现方式和真正的实例方法实现(暂时还不知道如何实现的)还是有些不同: a、自定义实现需要@SelfMethod装饰器,而真正实现是不需要装饰器的,不知道是不是底层做了默认省略的操作 b、Student.__dict__的输出中,自定义的实现表示learn是一个描述符对象,而真正实现的表示是一个function对象 c、打印stu1.learn的时候,自定义实现显示是描述符对象,真正实现表示的是绑定方法对象 嗯。。暂时还没深入研究绑定方法的具体实现,不过可以通过描述符来大概判断出,绑定方法也应该是一个类似封装了实例对象和函数的对象,在被调用的时候也是以func(self, *args, **kw)的方式来调用的。 5、静态方法的自定义实现 class StaticMethod: # 描述符,用于处理静态方法的类装饰器 def __init__(self, func): self.get_func = func def __get__(self, instance, owner): return self def __call__(self, *args, **kwargs): return self.get_func(*args, **kwargs) # 静态方法就是不提供instance和owner参数传入 class Student: def __init__(self, name, age): self.name = name self.age = age @StaticMethod # 描述函数为静态方法 def show(): print('这里是静态方法show') stu1 = Student('小明', 26) stu2 = Student('小红', 25) stu1.show() # 这里是静态方法show stu2.show() # 这里是静态方法show 五、总结 1.描述符可以用于处理类级别的属性的访问控制 2.如果描述符处理的是数据属性,那么核心关注点如下 >1、描述符的__get__,__set__,__delete__函数处理数据读取、删除 >2、处理数据属性的描述符对象,可以保存不同实例对象的属性值,使用字典,key是实例对象自身,不过要注意是否可hash >3、将描述符作为类装饰器对函数进行装饰,可以自定义类似property的get实现效果,不过注意描述符类中要提供setter和deleter用于处理set和del 描述符还可以用于处理函数属性,核心关注点有如下 >1、描述符类作为类装饰器对指定函数进行装饰并返回描述符对象 >2、返回的描述符对象除了处理描述符三大函数之外,还要提供__call__函数以便调用 >3、使用__call__函数的时候,传入的是instance,就类似实例方法,传入的是owner,就类似类方法classmethod,什么都不传入,就类似静态方法staticmethod。 对象属性的解析顺序,比如打印stu.name 0、无条件优先被__getattribute__处理 1、获取对象所属类及MRO列表,自下而上获取name的第一个定义 2、判断此定义的类型 3、如果类型是数据描述符,直接调用数据描述符的__get__,否则下一步 4、如果不是数据描述符,判断是否为:实例属性,即stu.__dict__中是否存在,是的话返回,否则下一步 5、判断类型是否为非数据描述符(也是描述符),如果是,则返回非数据描述符的__get__返回值,否则下一步 6、判断类型是否是普通属性,比如单纯的一个类属性,如果是,则返回此属性值,否则下一步 7、执行__getattr__,期望解析顺序最后给出返回值,没定义就报错

优秀的个人博客,低调大师

SDWebImage学习笔记之NSMapTable

NSDictionary/NSMutableArray浅析 我们在使用NSDictionary/NSMutableArray时,通常会使用NSString对象作为key,因为key必须遵循NSCopying协议,见NSMutableArray中的方法: - (void)setObject:(ObjectType)anObject forKey:(KeyType <NSCopying>)aKey; 在NSDictionary/NSMutableArray对象中,aKey对象被copy一份后存入,anObject对象则被强引用。来看一段代码: NSMutableDictionary *aDictionary = [[NSMutableDictionary alloc] initWithCapacity:0]; { NSString *aKey = @"akey"; NSObject *aObject = [[NSObject alloc] init]; [aDictionary setObject:aObject forKey:aKey]; } NSLog(@"dictionary: %@", aDictionary); 打印日志: dictionary: { akey = "<NSObject: 0x60400001d3b0>"; } 本来作用于结束后,aKey变量指向的NSString对象(简称aKey对象)和aObject变量指向的NSObject对象(简称aObject对象)应该被自动释放,但是aDictionary变量指向的NSMutableDictionary对象(简称aDictionary对象)持有一份aObject对象的强引用,所以打印日志时,aDictionary对象不为空。 现在有一个Teacher类表示班主任信息,包含姓名name属性和年龄age属性,另有一个Student类表示学生信息,也包含姓名name属性和年龄age属性。那么一个班包含一个班主任(Teacher对象)和n个学生(Student数组),为了统计一个班的信息,需要把班主任和学生的信息及对应关系保存下来。 // Teacher.h @interface Teacher : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger age; @end // Teacher.m @implementation Teacher @end // Student.h @interface Student : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger age; @end // Student.m @implementation Student @end // ViewController.m { NSMutableDictionary *aDictionary = [[NSMutableDictionary alloc] initWithCapacity:0]; Teacher *teacher = [[Teacher alloc] init]; teacher.name = @"teacher"; teacher.age = 30; NSMutableArray *aArray = [[NSMutableArray alloc] initWithCapacity:0]; for (int i = 0; i < 3; i++) { Student *student = [[Student alloc] init]; student.name = [NSString stringWithFormat:@"student%d", i]; student.age = i; [aArray addObject:student]; } [aDictionary setObject:aArray forKey:teacher.name]; NSLog(@"%@", aDictionary); } 打印日志: dictionary:{ teacher = ( "<Student: 0x60000003aa00>", "<Student: 0x60000003a9c0>", "<Student: 0x60000003aa80>" ); } 这里将班主任的姓名作为key,这样会损失其他信息。如果想要将teacher对象作为key,则需要让Teacher类遵循NSCopying协议,而且NSDictionary/NSMutable使用hash表来实现key和value之间的映射和存储,所以作为key值的类型必须重写++- (NSUInteger)hash++和++- (BOOL)isEqual:(id)object++两个方法,其中hash方法计算该对象的hash值,hash值决定该对象在hash表中存储的位置,isEqual方法通过hash值来定位对象在hash表中的位置。具体代码如下: // Teacher.h @interface Teacher : NSObject<NSCopying> @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger age; @end // Teacher.m @implementation Teacher - (id)copyWithZone:(NSZone *)zone { Teacher *teacher = [[Teacher allocWithZone:zone] init]; teacher.name = self.name; teacher.age = self.age; return teacher; } - (BOOL)isEqual:(id)object { // 比较hash值是否相等 return [self hash] == [object hash]; } - (NSUInteger)hash { // 调用父类的hash方法,也可以自定义 return [super hash]; } 打印日志: dictionary:{ "<Teacher: 0x600000027940>" = ( "<Student: 0x60c00022fa20>", "<Student: 0x60c00022fa00>", "<Student: 0x60c00022f960>" ); } NSMapTable浅析 NSMapTable继承自NSObject,自iOS6.0开始使用,NSMapTable是可变的。 NS_CLASS_AVAILABLE(10_5, 6_0) @interface NSMapTable<KeyType, ObjectType> : NSObject <NSCopying, NSCoding, NSFastEnumeration> NSMapTable有两个指定初始化方法和一个便捷初始化方法: // 指定初始化方法 - (instancetype)initWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER; - (instancetype)initWithKeyPointerFunctions:(NSPointerFunctions *)keyFunctions valuePointerFunctions:(NSPointerFunctions *)valueFunctions capacity:(NSUInteger)initialCapacity NS_DESIGNATED_INITIALIZER; // 便捷初始化方法 + (NSMapTable<KeyType, ObjectType> *)mapTableWithKeyOptions:(NSPointerFunctionsOptions)keyOptions valueOptions:(NSPointerFunctionsOptions)valueOptions; 初始化方法方法中有两个参数keyOptions和valueOptions,都是NSPointerFunctionsOptions类型,NSPointerFunctionsOptions是一个枚举类型, typedef NS_OPTIONS(NSUInteger, NSPointerFunctionsOptions) { // Memory options are mutually exclusive // default is strong NSPointerFunctionsStrongMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (0UL << 0), // use strong write-barrier to backing store; use GC memory on copyIn #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || TARGET_OS_WIN32 NSPointerFunctionsZeroingWeakMemory NS_ENUM_DEPRECATED_MAC(10_5, 10_8) = (1UL << 0), // deprecated; uses GC weak read and write barriers, and dangling pointer behavior otherwise #endif NSPointerFunctionsOpaqueMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (2UL << 0), NSPointerFunctionsMallocMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (3UL << 0), // free() will be called on removal, calloc on copyIn NSPointerFunctionsMachVirtualMemory API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (4UL << 0), NSPointerFunctionsWeakMemory API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0)) = (5UL << 0), // uses weak read and write barriers appropriate for ARC // Personalities are mutually exclusive // default is object. As a special case, 'strong' memory used for Objects will do retain/release under non-GC NSPointerFunctionsObjectPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (0UL << 8), // use -hash and -isEqual, object description NSPointerFunctionsOpaquePersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (1UL << 8), // use shifted pointer hash and direct equality NSPointerFunctionsObjectPointerPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (2UL << 8), // use shifted pointer hash and direct equality, object description NSPointerFunctionsCStringPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (3UL << 8), // use a string hash and strcmp, description assumes UTF-8 contents; recommended for UTF-8 (or ASCII, which is a subset) only cstrings NSPointerFunctionsStructPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (4UL << 8), // use a memory hash and memcmp (using size function you must set) NSPointerFunctionsIntegerPersonality API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (5UL << 8), // use unshifted value as hash & equality NSPointerFunctionsCopyIn API_AVAILABLE(macos(10.5), ios(6.0), watchos(2.0), tvos(9.0)) = (1UL << 16), // the memory acquire function will be asked to allocate and copy items on input }; 常用的枚举值及对应的含义如下: NSPointerFunctionsStrongMemory: 强引用存储对象 NSPointerFunctionsWeakMemory: 弱引用存储对象 NSPointerFunctionsCopyIn:copy存储对象 就是说,如果NSMapTable的初始化方法为: NSMapTable *aMapTable = [[NSMapTable alloc] initWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:NSPointerFunctionsStrongMemory capacity:0]; 或 NSMapTable *aMapTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsCopyIn valueOptions:NSPointerFunctionsStrongMemory]; 那么就等同于NSMutableDictionay的初始化方法: NSMutableDictionary *aDictionary = [[NSMutableDictionary alloc] initWithCapacity:0]; 或 NSMutableDictionary *aDictionary = [NSMutableDictionary dictionary]; 若初始方法修改为 NSMapTable *aMapTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsWeakMemory valueOptions:NSPointerFunctionsStrongMemory]; 即对key值进行弱引用,就可以不用让Teacher类遵循NSCopying协议和重新跟hash有关的两个方法,代码如下: // Teacher.h @interface Teacher : NSObject @property (nonatomic, copy) NSString *name; @property (nonatomic, assign) NSInteger age; @end // Teacher.m @implementation Teacher @end // ViewController.m Teacher *teacher = [[Teacher alloc] init]; teacher.name = @"teacher"; teacher.age = 30;NSMutableArray *aArray = [[NSMutableArray alloc] initWithCapacity:0]; for (int i = 0; i < 3; i++) { Student *student = [[Student alloc] init]; student.name = [NSString stringWithFormat:@"student%d", i]; student.age = i; [aArray addObject:student]; } NSMapTable *aMapTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsWeakMemory valueOptions:NSPointerFunctionsStrongMemory]; [aMapTable setObject:aArray forKey:teacher]; NSLog(@"%@", aMapTable); 打印日志: NSMapTable { [10] <Teacher: 0x604000038a40> -> ( "<Student: 0x60400003c640>", "<Student: 0x60400003c660>", "<Student: 0x60400003c620>" ) } 这样的方法可以快速的将NSObject对象作为key存入到“字典”中。 由于NSDictionary/NSMutableArray会强引用value,使得value的引用计数+1,加入不希望怎么做,可以用NSMapTable来实现。 NSMapTable *aMapTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory]; { NSObject *keyObject = [[NSObject alloc] init]; NSObject *valueObject = [[NSObject alloc] init]; [aMapTable setObject:valueObject forKey:keyObject]; NSLog(@"NSMapTable:%@", aMapTable); } NSLog(@"NSMapTable:%@", aMapTable); 打印日志: NSMapTable:NSMapTable { [6] <NSObject: 0x60c00000c690> -> <NSObject: 0x60c00000c730> } NSMapTable:NSMapTable { } 第一个NSLog打印出了key-value值,等到object对象指向的NSObject对象超出作用域,释放该对象,由于aMapTable弱引用object对象,aMapTable的中的key-value值会被安全的删除,第二个NSLog打印出的值为空。 NSMapTable与NSDictionary/NSMutableDictionary对比 NSDcitionary有一个可变类型NSMutableDictionary,NSMapTable没有可变类型,它本身就是可变的; NSDcitionary/NSMutableDictionary中对于key和value的内存管理方法唯一,即对key进行copy,对value进行强引用,而NSMapTable没有限制; NSDcitionary中对key值进行copy,不可改变,通常用字符串作为key值,只是key->object的映射,而NSMapTable的key是可变的对象,既可以实现key->object的映射,又可以实现object->object的映射。 遗留的问题 笔者才疏学浅,对NSMapTable与NSDictionary的内部结构了解不是很深,不清楚key-value是通过怎么样的方式绑定起来的,假如看到这篇文章的朋友有所了解,希望可以指点一二。

优秀的个人博客,低调大师

Go——小白学习之map

map的使用,key值唯一,打印出是无序的,注意坐标(key)与数组坐标不一样 定义: m3 := map[int]string{1: "mile", 2: "go"} m3[1] = "litter" m3[3] = "gogogo" //超出范围,错误 fmt.Println("m3=", m3) 遍历: 第一个运行结果的前提是 value OK:=m[1] range的使用,有两个返回值,在数组中也可以用到,一个是id,一个是value,id为下标,value为其对应的值,如果只想要其中一个值,可以使用 “_”

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册