My code dynamically generates properties and the classes to contain them. The code creates immutably-typed properties such that assignments to them are automatically converted to the correct type, rather than be rejected.
The problem is that, for property c.p the getter (t=c.p) and setter (c.p=t) are not being invoked. Code can explicitly invoke the getter with t=w.p.__get__(0) . Code can explicitly invoke the setter with c.p.__set__(3,0) . However, that ruins the convenience of having properties in the first place.
Symptoms:
for property p in class c:
t=c.p does not invoke the getter. Instead the assignment causes t to then refer to the property object itself, rather than the property's value.
t=c.p.__get__() fails with TypeError: expected at least 1 argument, got 0
t=c.p.__get__(None) fails with TypeError: get(None, None) is invalid
t=c.p.__get__(0) invokes the getter. t gets the value returned by the getter. The value of the parameter does not matter, as long as it is not None.
c.p=3 does not invoke the setter. Instead, c.p is now an integer with value 3.
After reconstructing the property:
c.p.__set__(3) fails with TypeError: expected 2 arguments, got 1
c.p.__set__(3,0) fails with TypeError: fImmutablyTypedPropertiesContainer..cImmutablyTypedPropertiesContainer.addProperty..psetter() takes from 0 to 1 positional arguments but 2 were given
Altering the setter's signature to accept a optional second parameter then allows c.p.__set__(3,0) or even c.p.__set__(3,None) to work.
c.p.__set__(3,0) # now works
What must be done to get the property's typical usage to invoke the getter and setter as intended?
code:
#!/bin/python3.13 # immutably typed properties (the type survives setting a new value) import numpy as np def fImmutablyTypedPropertiesContainer(): # Purpose: Create a Class to be a container to which staticly typed properties can be added, then can get and set. # Each property's type is immutable, although its value may change. An np.longdouble stays an np.longdouble. # Each call creates and returns a new class, NOT an instance. No instances are created. # That way multiple invocations of this function each get their own container and namespace. # The static typing survives a set to a new value, even if conversion & coercion at assignment time is required. # Different properties within the container need not all be of the same type. # # Usage: # bucket= fImmutablyTypedPropertiesContainer() # create a container # bucket.addProperty('i',75.6,ptype=np.int64) # add a property i with value stored in _i[0] set to 75 # bucket.addProperty('x',144,ptype=np.longdouble) # add a property x with value stored in _x[0] set to 144.0 # bucket.i # get i's value # bucket.x = 44 # set x's value to 44.0 # # import numpy as np # assume already imported # create the class class cImmutablyTypedPropertiesContainer(object): pass # no instances @classmethod def addProperty(cls,name,value=np.longdouble(2.71828182845),ptype=np.longdouble) : #cls is the class, not an instance. # name is a string, such as "i" setattr(cls, "_"+name, np.ndarray((1,),dtype=ptype) ) # create an array containing a single item as an attribute called _name # elements of a numpy array have a static type, with conversion & coercion at assignment time getattr(cls, "_"+name)[0]=value # this SETs the initial value of the only element of the _name array, including automatic type conversion. print("adding property named: ", name ," to class: ", cls," at", id(cls), ". with parm value:", value, " in ", "_"+name, "with value ",getattr(cls, "_"+name)," \n" ) #MUST NOT BE @classmethod. Causes TypeError: 'classmethod' object is not callable def pgetter(a1):#*args,**kwargs): # arguments are unused t=pgetter.fromwhattoget[0] # set externally print("invoked the getter for name= ",name, pgetter.fromwhattoget, "; value= ",t, ". a1=",a1) # elements of a numpy array have a static type, with conversion & coercion at assignment time return t pgetter.fromwhattoget=getattr(cls, "_"+name) #MUST NOT BE @classmethod. Causes TypeError: 'classmethod' object is not callable def psetter(newvalue=3.14159, dummyparm=0): #must allow for two parameters print("invoked a setter for name ",name, psetter.intowhattoset, " = ",newvalue) # elements of a numpy array have a static type, with conversion & coercion at assignment time psetter.intowhattoset[0]=newvalue # this SETs a value of the first element of the _name array, including automatic type conversion. return psetter.intowhattoset[0] # getattr(cls, "_"+name)[0] # also returns the value, but the __get__ function does not pass it back. psetter.intowhattoset=getattr(cls, "_"+name) print("fromwhat to get and into what toset = ",pgetter.fromwhattoget, psetter.intowhattoset) setattr(cls,name, property( fget=pgetter, fset=psetter) ) return return cImmutablyTypedPropertiesContainer # return the class itself, not an instance v=fImmutablyTypedPropertiesContainer() # v is a unique class itself, rather than an instance. v.addProperty('i',1024,ptype=np.int64) w=fImmutablyTypedPropertiesContainer() # w is a unique class itself, rather than an instance. w.addProperty('i',75.6,ptype=np.int64) print("added property named: w.i", w.i, w.i.__get__(0), type(w.i)," to class: ",w," with parm value: 75.6, ", "but actual value: ", w.i ) print("\n getting:") t=w.i tg=w.i.__get__ tv=w.i.__get__(10) # must have a parameter, even though the getter does not use it. Cannot be None. print("t=w.i= ",t,", getter:", tg, ", value:", tv) print("\n setting:") ts=w.i.__set__ w.i.__set__(314,None) #must have two parameters, even though the setter does not use the second. tv=w.i.__get__(w.i) print("t=w.i= ",t,", setter:", ts,", value:", tv) tvr=w.i.__set__(342,0) #must have two parameters, even though the setter does not use the second. tv=w.i.__get__(w.i) print("t=w.i= ",t,", setter:", ts,", value:", tv, tvr) # tvr is None. __set__ does not return a value. t=w.i print("t=w.i= ",t,", w.i=",w.i,", with type=",type(w.i)) print("\n") print("w.i= ",w.i.__get__(0), type(w.i), w.i,w, type(w), id(w)) print("v.i= ",v.i.__get__(0), type(v.i), v.i,v, type(v), id(v)) w.i=3 t=w.i print("t=w.i= ",t,", w.i=",w.i,", with type=",type(w.i)) print("\n") print("w.i= ",w.i.__get__(0), type(w.i), w.i,w, type(w), id(w)) quit() references:
- How to add property to a class dynamically? # see the top answer
- https://stackoverflow.com/users/saves/1496279
- https://www.dropbox.com/scl/fi/vahot6oi1ddt3epasyyie/dynamic_properties_simple.py?rlkey=q8rqcpufdf4lva2y0ahmih798&e=1&dl=0
- https://www.programiz.com/python-programming/property
- https://docs.python.org/2/howto/descriptor.html#properti
- https://realpython.com/python-property/
- Python: Dynamically add properties to class instance, properties return function value with inputs
- Dynamically adding @property in python
- https://github.com/Infinidat/munch
- https://docs.python.org/3/tutorial/classes.html
- https://discuss.python.org/t/dynamic-generation-of-methods-for-a-class-from-a-list-of-names/14566
- https://discuss.python.org/t/dynamic-generation-of-methods-for-a-class-from-a-list-of-names/14566/2
- https://www.geeksforgeeks.org/classmethod-in-python/
- https://www.programiz.com/python-programming/methods/built-in/classmethod
- https://mgarod.medium.com/dynamically-add-a-method-to-a-class-in-python-c49204b85bd6
- https://tush.ar/post/descriptors/
- Setter ignored when property is assigned to variable (Python 3.4)
- @property setter not called in python 3
- Python property being ignored, acting like an attribute
- creating class properties dynamically
- pythonic way to declare multiple class instance properties as numbers?
- Dynamic python properties
- Is there a way to type hint a class property created without the property decorator?
sharebutton. "top answer" is meaningless because order is dynamic.fImmutablyTypedPropertiesContainerALWAYS returns the SAME class. Your comment that each returned value is a new, unique class is incorrect. Your variables 'v' and 'w' both refer to the same object, which is a class (not an instance). You never instantiate an instance, so what you are doing here is manipulating values in the dictionarycImmutablyTypedPropertiesContainer.__dict__. That's why t.c doesn't invoke the getter - the getter is invoked to assigned a value to the__dict__of an instance.fImmutablyTypedPropertiesContainerdoes return a class with a different ID. The fundamental problem was that a property's getters and setters are only called when the getting and setting are through an instance.z=classx.propertyyresults inzreferring to a property objectz=instancewofclassx.propertyyresults inzgetting the value returned by the property's getter.