Python: Couldn't dynamically set attributes to a FlaskForm? - python

I want to set attributes dynamically to a FlaskForm like this
form = ModelForm(request.form)
file form.py
class ModelForm(FlaskForm):
def __init__(self, postData):
super(ModelForm, self).__init__()
for p in postData:
setattr(ModelForm, p, StringField(p, validators=[InputRequired()]))
But it only work for the second time running, the first time running, it doesn't work.
I really don't understand how python constructor works.
As this post, it said because
class A is not fully initialized when you do your setattr(A, p, v)
there.
But in other languages, the object have to be created after constructor finished, and it has full class variables, properties declared in the constructor ?
For example, it works and can print a.key. So what's difference there in the flask constructor and this?
class A(object):
def __init__(self):
self.a = 'i am a accessor'
setattr(self, 'key', 'value')
a = A()
print a.a
print a.key

class A is not fully initialized
means, when you create your first instance of your class with form=ModelForm(), you start adding attributes to the class you are currently instancing from. I don't know, how exactly this works internally in Python. But since you say this only works in the second run, I guess the object is first created with all attributes defined for the class, then __init__ is executed. So the new attributes are added to late.
In other words: Your are trying to change the class definition after you already created an instance of it. You need to add all your attributes, before you instantiate.
Now what you need to do is: first define the class without any dynamic fields. Then, after the class definition, you add the loop with your dynamic fields.
ModelForm = FlaskForm
for p in postData:
setattr(ModelForm, p, StringField(p, validators=[InputRequired()]))
Or if you need to add some other stuff in class definition:
class ModelForm(FlaskForm):
def foo(self):
return 'bar'
for p in postData:
setattr(ModelForm, p, StringField(p, validators=[InputRequired()]))
And then, somewhere in your view function, you can use form = ModelForm(request.form) as usual.
Usually you know what fields you need beforehand. The form just answers on what it got from the GET request. So this should be fine.
But maybe you added some more fields with some JS on client side, which the server does not know about (yet). In that case you might try to put the class definition into the local scope of the view function which handles the POST request.

Related

How to properly access and set class variables in a derived class?

Supposed that you have a python class (say B) that is a derived class of some other class (say A) and that class A has both class variables and #classmethods that help you change or view these class variables. I had assumed that a #classmethod in class A that sets a class A class variable using the syntax cls.variable_name = value would work.
This seems to work sometimes but not always which confuses me. Below is an example that does not set the class variables as I would expect. Therefore I cannot tell what cls.something will be accessing and so I have to use A.something which seems that I will be missing the capabilities of cls.something in #classmethods. What does cls.something actually access in class methods and why does the following example not set the test class class variables?
The following example with output hopefully demonstrates what I mean:
class Test():
epf = 'A'
#classmethod
def set_formats(cls, p):
cls.epf = p
#classmethod
def form(cls):
return cls.epf
class Mytest(Test):
pass
Here is the output:
>>>c=Mytest
>>>Test.form()
'A'
>>>c.set_formats(p='a')
>>>Test.epf
'A'
>>>c.form()
'a'
>>>c.epf
'a'
So in this example the classmethods are not changing the class variable as I would expect and instead an instance variable seems to appear. If I do the above without a derived class then it works as expected. Hmm? Clearly missing something here!
Now if I change the c.set_formats(p='a', f='A') to Test.set_formats(p='a', f='A') it does work. Is it because c.set_formats uses the class method with cls being an instance?
Edit: Made the code much smaller and changed conventions as requested.
Is it because c.set_formats uses the class method with cls being an instance?
Yes, you can check via print calls showing the ids of the involved objects.

Set class variable value, the value returned by a class method

I'm trying to create a class which maps to a mongoDB collection.
My code looks like this:
class Collection:
_collection = get_collection() # This seems not working
#classmethod
def get_collection(cls):
collection_name = cls.Meta.collection_name if cls.Meta.collection_name \
else cls.__name__.lower()
collection = get_collection_by_name(collection_name) # Pseudo code, please ignore
return collection
class Meta:
collection_name = 'my_collection'
I came across a situation where I need to assign the class variable _collection with the return value of get_collection.
I also tried _collection = Collection.get_collection() which also seems not to be working
As a work-around, I subclassed Collection and set value of _collection in the child class.
Would like to know any simple solution for this.
Thanks in advance
As DeepSpace mentions, here:
class Collection:
_collection = get_collection() # This seems not working
#classmethod
def get_collection(cls):
# code that depends on `cls`
the get_collection method is not yet defined when you call it. But moving this line after the method definition won't work either, since the method depends on the Collection class (passed as cls to the method), which itself won't be defined before the end of the class Collection: statement's body.
The solution here is to wait until the class is defined to set this attribute. Since it looks like a base class meant to be subclassed, the better solution would be to use a metaclass:
class CollectionType(type):
def __init__(cls, name, bases, attrs):
super(CollectionType, cls).__init__(name, bases, attrs)
cls._collection = cls.get_collection()
# py3
class Collection(metaclass=CollectionType):
# your code here
# py2.7
class Collection(object):
__metaclass__ = CollectionType
# your code here
Note however that if Collection actually inherit from a another class already having a custom metaclass (ie Django Model class or equivalent) you will need to make CollectionType a subclass of this metaclass instead of a subclass of type.
There are some design/syntax errors in your code.
When the line _collection = get_collection() executes, get_collection is not yet defined. As a matter of fact, the whole Collection class is not yet defined.
get_collection_by_name is not defined anywhere.
EDIT OP updated the question so the below points may not be relevant anymore
collection = get_collection(collection_name) should be collection = cls.get_collection(collection_name)
Sometimes you are passing a parameter to get_collection and sometimes you don't, however get_collection's signature never accepts a parameter.
Calling get_collection will lead to an infinite recursion.
You have to take a step back and reconsider the design of your class.

How to update an already-declared class during runtime

How can I 'update' a class that has already been declared? My particular scenario is allowing a user to enter code (via a module name) during runtime to update the class when the program determines that the existing class is insufficient. So let's say I have module ClassA containing
class ClassA:
def __init__(self, field1):
self.field1 = field1
partway through runtime I notice some cases where I'd like to use ClassA if only I could add another field. I alert the user to this and give them the option. What can I prompt them to input? Is it possible for them to give me a filename redeclaring the class? If not, how else would I be able to do this? And if the user does this, what happens to existing instances of the class? I assume they are seamlessly updated if this is done correctly?
You can dynamically add or replace methods of a class by assigning functions as unbound methods. For example:
class Foo(object):
pass
f = Foo()
def m(self, x):
self.x = x
Foo.method = m
f.method(123)
print(f.x)
This prints 123. Even though method wasn't added until after f was created, it is still callable from f.

Classes in python, how to set an attributes

When I write class in python, most of the time, I am eager to set variables I use, as properties of the object. Is there any rule or general guidelines about which variables should be used as class/instance attribute and which should not?
for example:
class simple(object):
def __init(self):
a=2
b=3
return a*b
class simple(object):
def __init(self):
self.a=2
self.b=3
return a*b
While I completely understand the attributes should be a property of the object. This is simple to understand when the class declaration is simple but as the program goes longer and longer and there are many places where the data exchange between various modules should be done, I get confused on where I should use a/b or self.a/self.b. Is there any guidelines for this?
Where you use self.a you are creating a property, so this can be accessed from outside the class and persists beyond that function. These should be used for storing data about the object.
Where you use a it is a local variable, and only lasts while in the scope of that function, so should be used where you are only using it within the function (as in this case).
Note that __init is misleading, as it looks like __init__ - but isn't the constructor. If you intended them to be the constructor, then it makes no sense to return a value (as the new object is what is returned).
class Person(object):
def __init__(self, name):
# Introduce all instance variables on __init__
self.name = name
self.another = None
def get_name(self):
# get_name has access to the `instance` variable 'name'
return self.name
So if you want a variable to be available on more than one method, make
it an instance variable.
Notice my comment on introducing all instance vars on __init__.
Although the example below is valid python don't do it.
class Person(object):
def __init__(self):
self.a = 0
def foo(self):
self.b = 1 # Whoa, introduced new instance variable
Instead initialize all your instance variables on __init__ and set
them to None if no other value is appropriate for them.
I try to imagine what I want the API of my class to look like prior to implementing it. I think to myself, If I didn't write this class, would I want to read the documentation about what this particular variable does? If reading that documentation would simply waste my time, then it should probably be a local variable.
Occasionally, you need to preserve some information, but you wouldn't necessarily want that to be part of the API, which is when you use the convention of appending an underscore. e.g. self._some_data_that_is_not_part_of_the_api.
The self parameter refers to the object itself. So if you need to use on of the class attributes outside of the class you would it call it as the name of class instance and the attribute name. I don't think there is any guideline on when to use self, it all depends on your need. When you are building a class you should try to think about what you will use the variables you creating for. If you know for sure that you will need that specific attribute in the program you are importing your class, then add self.

Is there a way to modify a class in a class method in Python?

I wanted to do something like setattr to a class in class method in Python, but the class doesn't exist so I basically get:
NameError: global name 'ClassName' is not defined
Is there a way for a class method to modify the class? Something like this but that actually works:
class ClassName(object):
def HocusPocus(name):
setattr(ClassName, name, name)
HocusPocus("blah")
HocusPocus("bleh")
Class methods get the class passed as the first argument:
class Bla(object):
#classmethod
def cm(cls,value):
cls.storedValue = value
Bla.cm("Hello")
print Bla.storedValue # prints "Hello"
Edit: I think I understand your problem now. If I get it correctly, all you want to do is this:
class Bla(object):
storedValue = "Hello again"
print Bla.storedValue # prints "Hello again"
Class creation in Python (pretty much) simply means:
Create a fresh namespace.
Run the code that you find inside the class body using this namespace
Put everything that's left in the namespace into the class as class attributes.
Since storedValue is in the namespace after step 2, it's turned into a class attribute in step 3.
Another way you could do this would be to use a class decorator, though these are only available from Python 2.6 onwards IIRC.
Something like this:
def addattributes(cls):
cls.foobar = 10
return cls
#addattributes
class MyClass(object):
pass
print MyClass.foobar
This kind of this most useful when you want to "decorate" a number of classes with some specific functionality / properties. In your case, if you only want to do this once, you might just want to use class methods as previously shown.
While many good suggestions have been advanced, the closest one can get to the originally requested code, that is:
class ClassName(object):
def HocusPocus(name):
setattr(ClassName, name, property(fget=..., fset=...))
HocusPocus("blah")
HocusPocus("bleh")
is this:
class ClassName(object):
def HocusPocus(name):
return property(fget=..., fset=...)
blah = HocusPocus("blah")
bleh = HocusPocus("bleh")
I'm assuming the mysterious ... redacted parts need access to name too (otherwise it's not necessary to pass it as an argument).
The point is that, within the class body, HocusPocus is still just a function (since the class object doesn't exist yet until the class body finishes executing, the body is essentially like a function body that's running in its local dict [without the namespace optimizations typically performed by the Python compiler on locals of a real function, but that only makes the semantics simpler!]) and in particular it can be called within that body, can return a value, that value can be assigned (to a local variable of the class body, which will become a class attribute at the end of the body's execution), etc.
If you don't want ClassName.HocusPocus hanging around later, when you're done executing it within the class body just add a del statement (e.g. as the last statement in the class body):
del HocusPocus

Categories