admin管理员组

文章数量:1242847

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
  • .py?rlkey=q8rqcpufdf4lva2y0ahmih798&e=1&dl=0
  • .html#properti
  • /
  • Python: Dynamically add properties to class instance, properties return function value with inputs
  • Dynamically adding @property in python
  • .html
  • /
  • /
  • 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?

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/users/saves/1496279
  • https://www.dropbox/scl/fi/vahot6oi1ddt3epasyyie/dynamic_properties_simple.py?rlkey=q8rqcpufdf4lva2y0ahmih798&e=1&dl=0
  • https://www.programiz/python-programming/property
  • https://docs.python./2/howto/descriptor.html#properti
  • https://realpython/python-property/
  • Python: Dynamically add properties to class instance, properties return function value with inputs
  • Dynamically adding @property in python
  • https://github/Infinidat/munch
  • https://docs.python./3/tutorial/classes.html
  • https://discuss.python./t/dynamic-generation-of-methods-for-a-class-from-a-list-of-names/14566
  • https://discuss.python./t/dynamic-generation-of-methods-for-a-class-from-a-list-of-names/14566/2
  • https://www.geeksfeeks./classmethod-in-python/
  • https://www.programiz/python-programming/methods/built-in/classmethod
  • https://mgarod.medium/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?
Share Improve this question edited Feb 17 at 20:12 JRiggles 6,8102 gold badges15 silver badges34 bronze badges asked Feb 17 at 19:33 user15972user15972 1184 bronze badges 5
  • 1 Please try to pare this down to a more readable minimal reproducible example, and if you're going to include links, include them as links rather than code. – JRiggles Commented Feb 17 at 20:09
  • 1 Also, are you 100% sure your question isn't answered (in whole or in part) by any of your 20+ references? – JRiggles Commented Feb 17 at 20:15
  • The second link fails for me. I don't think you can view other users' saved questions. And if you want to refer to a specific answer, link directly to it by using the share button. "top answer" is meaningless because order is dynamic. – Barmar Commented Feb 17 at 21:21
  • Your function fImmutablyTypedPropertiesContainer ALWAYS 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 dictionary cImmutablyTypedPropertiesContainer.__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. – Paul Cornelius Commented Feb 17 at 23:35
  • @Paul Cornelius: Each call to fImmutablyTypedPropertiesContainer does 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.propertyy results in z referring to a property object z=instancewofclassx.propertyy results in z getting the value returned by the property's getter. – user15972 Commented 2 days ago
Add a comment  | 

1 Answer 1

Reset to default 0

The answer is that a property's getter and setter are invoked only from an instance.

The example that demonstrates this is within https://stackoverflow/a/7118013/1496279 .

> print Bar.x
> # < property object at 0x04D37270> 
> print Bar () .x
> # 0

The ( ) creates an instance.

本文标签: Dynamically created Python properties not invoking getters and gettersStack Overflow