flask-classful icon indicating copy to clipboard operation
flask-classful copied to clipboard

Why is constructor of FlaskView called per number of methods?

Open kidapu opened this issue 5 years ago • 5 comments

When I run the following code in python 3.6.9, The __init__() method is called 5 times.

from flask import Flask
from flask_classful import FlaskView, route

app = Flask(__name__)

class AppRouting(FlaskView):
	route_base = '/'

	def __init__(self):
		print("--------constructor---------")
		return 

	def test1(self):
		return "test1"

	def test2(self):	
		return "test2"

	def test3(self):
		return "test3"

	def test4(self):
		return "test4"

	def test5(self):
		return "test5"


if __name__ == '__main__':
	AppRouting.register(app)
	app.run()

Cmdline output is below.

$ python test.py 
--------constructor---------
--------constructor---------
--------constructor---------
--------constructor---------
--------constructor---------
 * Serving Flask app "F003-server2" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

Is this right? I think the constructor method is called per number of methods. If possible, I want the constructor to be called only once.

kidapu avatar Oct 28 '19 08:10 kidapu

I'm not sure why. Maybe you can try to create one instance for all make_proxy_method call to see if everything works (at least all unit tests should be passed): https://github.com/teracyhq/flask-classful/blob/develop/flask_classful.py#L257-L260

hoatle avatar Oct 28 '19 10:10 hoatle

@hoatle I have two points to consider.

1)

I edited flask_classful.py linke below, and run with above code.

if init_argument is None:
    print("AAA")
    i = cls()
else:
    print("BBB")
    i = cls(init_argument)

The output is below.

AAA
--------constructor---------
AAA
--------constructor---------
AAA
--------constructor---------
AAA
--------constructor---------
AAA
--------constructor---------
 * Serving Flask app "F003-server2" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

2)

I installed Flask_Classful = 0.14.2. It's not the same with the latest code in GitHub.

kidapu avatar Oct 28 '19 10:10 kidapu

I found one solution for it, when declare the class methods names with prefix of __ then init method is not being called for the method count. ex:

class AppRouting(FlaskView): route_base = '/'

def __init__(self):
	print("--------constructor---------")
	return 

def test1(self):
	return "test1"

def test2(self):	
	return "test2"

in above case init method will be called for 3 times. due to 2 methods declared under the class. now change it like below

class AppRouting(FlaskView): route_base = '/'

def __init__(self):
	print("--------constructor---------")
	return 

def __test1(self):
	return "test1"

def __test2(self):	
	return "test2"

now init method will get called only 1 time. But __test1 method can't be accessed in other class as it is declared as private. Unable to find any other resolution other than this.

dillibabukadati avatar Sep 11 '21 18:09 dillibabukadati

I met the same problem. And my solution is still ugly but needn't rename all the methods' names.

from flask import Flask
from flask_classful import FlaskView, route
from random import choice

quotes = [
    "A noble spirit embiggens the smallest man! ~ Jebediah Springfield",
    "If there is a way to do it better... find it. ~ Thomas Edison",
    "No one knows what he can do till he tries. ~ Publilius Syrus"
]

app = Flask(__name__)

class QuotesView(FlaskView):
    route_base = '/'
    
    @classmethod
    def _initilization(cls):
        print('Enter into init')
        # super().__init__()
        quotes.append("Never fade away. ~ V")
        print('Leave init')

    def index(self):
        return "<br>".join(quotes)

    def _get(self, id):
        id = int(id)
        if id < len(quotes) - 1:
            return quotes[id]
        else:
            return "Not Found", 404
        
    @route('/word_bacon/') #<--- Adding route
    def random(self):
        return choice(quotes)
    
    def add(self,a,b):
        return str(int(a)+int(b))

QuotesView._initilization()
QuotesView.register(app)

if __name__ == '__main__':
    app.run()

The output is like this:

Enter into init
Leave init
 * Serving Flask app "test2" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [15/Dec/2021 23:18:14] "GET / HTTP/1.1" 200 -

Jiaoma avatar Dec 15 '21 15:12 Jiaoma

Any progress on this? Makes it impossible to for example neatly use a getter/setter in the registered class as they'll be called for two different instances of the class.

anembac avatar Feb 05 '24 16:02 anembac