问题
I am looking for a way to dynamically create classes with specific properties accessible via typical instance notation.
DynoOne = createClass('DynoOne',props=['A','B'])
d = DynoOne (database='XYZ')
d.A = d.B + 1
DynoTwo = createClass('DynoTwo',props=['A','C','E'])
q = DynoTwo (database='QRS')
q.A = q.C + 2*q.E
Details of how the "props" are actually acquired and modified would be hidden. This also makes it easier to add access to new props as they become available.
I have experimented with techniques such as the following, to get a feel for how python can dynamically produce basic class attributes:
Class factory to produce simple struct-like classes?
My initial reading on python suggests that class properties are one way to handle introducing getter/setter methods for access.
What's not clear is how to dynamically specify property names in the factory constructor method (whether using decorators or explicit property() call)
E.g., using property() . . .
class DynamicClass( someBase ):
def dynamic_getter(self):
# acquire "stuff"
return stuff
def dynamic_setter(self,stuff):
# store "stuff"
pass
dynamic_property_name = property(fget=dynamic_getter,fset=dynamic_setter)
When the class is declared/constructed, I need to create a set per requested prop. E.g., the DynoOne class would have separate property/setter/getter for 'A' and 'B'.
I suspect that a template-based eval() strategy would work, but I am likely missing some more fundamental and effective technique.
Enlightenment and learning opportunities are appreciated :-)
回答1:
The three-argument for of type
lets you create classes dynamically. So, a sketch:
def dynamic_getter(self):
# acquire "stuff"
return stuff
def dynamic_setter(self,stuff):
# store "stuff"
pass
DynamicClass = type('DynamicClass', (SomeBase,), {"dynamic_property_name":property(fget=dynamic_getter,fset=dynamic_setter)})
Or, more concretely:
In [1]: class SomeBase:
...: def __init__(self):
...: self._foo = 42
...:
...: def dynamic_getter(self):
...: # acquire "stuff"
...: return self._foo
...:
...: def dynamic_setter(self,stuff):
...: # store "stuff"
...: pass
...:
...: DynamicClass = type('DynamicClass', (SomeBase,), {"dynamic_property_name":property(fget=dynamic_getter,fset=dynamic_setter)})
In [2]: instance = DynamicClass()
In [3]: instance.dynamic_property_name
Out[3]: 42
Note: type
is literally a class object like any other, and calling it in it's three-argument form is a constructor for new class object instances, it is the class that creates other class objects, i.e. a metaclass. Indeed, you can think of a class definition statement as syntactic sugar for the above.
A template-based with exec
(if you want to use a complex statement, you'd need exec
, eval
only allows expressions) approach is also viable, if you find that easier to work with. Indeed, that is how collections.namedtuple
works in the standard library.
Note: you seem to be confused about the nature of properties in Python. Instance attribtus are not specified on the class, rather, you'd add a function that initializes those instance attributes (typically __init__
) but you can add instance attributes anywhere, even outside of a method/class.
回答2:
In python, instance variables are stored under a dict which can be used to create dynamic instance variables at the time of object creation of a class.
Let's say, I have a dict {'a':1} in which the key 'a' should be assigned as a variable and 1 as its value.
Under__init__
function, we can do like,
self.__dict__['a'] = 1
We can use a for loop to iterate over the dictionary and do the above to create dynamic variables.
As per @chepner suggestion, we can also use setattr
function to set variables dynamically.
来源:https://stackoverflow.com/questions/57811102/creating-class-properties-dynamically