Package: pymagic9
pymagic9This is a Python library based on calling the stack of frames at runtime and analyzing the code object of frames. Basically, it implements some C# features. For example, it contains thenameoffunction andauto-implemented properties. See thedocumentationfor more information.InstallationYou can installpymagic9using pip:pipinstallpymagic9Featuresgetframe: Thesys._getframefunction is used here if it exists in the version of python being used. Otherwise, the_getframepolyfill is used.isemptyfunction: Checks if a function is empty or not.isfunctionincallchain: Determines whether the given function object or code object is present in the call chain.nameof: This function correctly determines the "name" of an object, without being tied to the object itself. It can be used to retrieve the name of variables, functions, classes, modules, and more.PropertyMeta: This metaclass allows you to createauto-implemented properties(like in C#, where you can declare properties without explicitly defining a getter and setter), for which you can use an ellipsis or empty functions to indicate that the Python itself would create the auto-implemented accessor.Usage ofauto-implemented propertiesImport the PropertyMeta metaclass and assign it as a metaclass for the desired class:frompymagic9importPropertyMetaclassPerson(metaclass=PropertyMeta):passCreate properties in this class with empty accessors (using empty function or ellipsis) to indicate that this property will be auto-implemented:frompymagic9importPropertyMetaclassPerson(metaclass=PropertyMeta):"""class Person"""def__init__(self,name):self.name=namename=property(fget=...,)# readonly propertyage=property(fget=...,fset=...,)# ordinary propertyNow for anordinaryproperty we can get and put values into it at any time. But for areadonlyproperty, you can put a value into it only once, at the time of creating an instance of the class:frompymagic9importPropertyMetaclassPerson(metaclass=PropertyMeta):"""class Person"""def__init__(self,name):self.name=name# self.name = "Sam"  # raise AttributeError: 'property' is readonly (reassigning value)name=property(fget=...,)# readonly propertyage=property(fget=...,fset=...,)# ordinary propertyif__name__=="__main__":person=Person("Tom")person.age=24print(person.name+',',person.age)# Tom, 24# person.name = "Sam"  # raise AttributeError: 'property' is readonlyTo delete a property value, use thedeloperator:frompymagic9importPropertyMetaclassPerson(metaclass=PropertyMeta):"""class Person"""def__init__(self,name):self.name=namename=property(fget=...,)# readonly propertyage=property(fget=...,fset=...,)# ordinary propertyif__name__=="__main__":person=Person("Tom")person.age=24print(person.name+',',person.age)# Tom, 24delperson.name# print(person.name)  # raise AttributeError: auto-implemented field does not exist or has already been erasedIf thegetteris specified by an empty accessor (using empty function or ellipsis), and thesetteris not an empty function, thensetterwill also be called. This can be used as a callback when assigning a value to a property:frompymagic9importnameof,PropertyMetadefNotifyPropertyChanged(propertyname,value):"""Notify property changed"""# Do somethingprint(propertyname+',',value)classPerson(metaclass=PropertyMeta):"""class Person"""def__init__(self,name):self.name=namename=property(fget=...,)# readonly propertyage=property(fget=...,fset=...,)# ordinary property@propertydefheight(self):"""Person height in cm"""return@height.setterdefheight(self,value):NotifyPropertyChanged(nameof(self.height),value)if__name__=="__main__":person=Person("Tom")person.age=24print(person.name+',',person.age)# Tom, 24person.height=180# height, 180Similar code forPython 2.7looks like this:frompymagic9importnameof,PropertyMeta__metaclass__=PropertyMetadefNotifyPropertyChanged(propertyname,value):"""Notify property changed"""# Do somethingprint(propertyname+', '+str(value))classPerson:"""class Person"""def__init__(self,name):self.name=namename=property(fget=Ellipsis,)# readonly propertyage=property(fget=Ellipsis,fset=Ellipsis,)# ordinary property@propertydefheight(self):"""Person height in cm"""return@height.setterdefheight(self,value):NotifyPropertyChanged(nameof(self.height),value)if__name__=="__main__":person=Person("Tom")person.age=24print(person.name+', '+str(person.age))# Tom, 24person.height=180# height, 180The detailed operating principle is described in thedocumentation.Compatibilitypymagic9is compatible with the following versions of Python:CPython 2.7CPython 3.6CPython 3.7CPython 3.8CPython 3.9CPython 3.10It is supported on Windows, Ubuntu, and MacOS platforms.DocumentationFor more information and detailed usage examples, please refer to thedocumentation.LicenseThis project is licensed under the Apache License 2.0. See theLICENSEfile for more details.