Advantages of Reflection
Its core essence is actually string-based event-driven, via theString formTo manipulate an object's properties or methods
A concept is presented as a way to understand what its advantages are so that we can know why we should use reflection.
Scene construction
Development of 1 website, consisting of two files, one for the specific execution of operationsOne is the entry file.
Requirements: need to be set in the entry file to allow the user to enter the url, according to the user to enter the url to perform the corresponding operation
# def login(): print("It's a landing page!") def logout(): print("It's an exit page!") def home(): print("This is the main website page!")
# import commons def run(): inp = input("Please enter the url of the page you want to visit: ").strip() if inp == 'login': () elif inp == 'logout': () elif inp == 'index': () else: print('404') if __name__ == '__main__': run()
(of a computer) runrun
After the method, the results are as follows:
Please enter the url of the page you want to visit: login
This is a landing page!
Q: The above uses if judgment to execute the specified function based on each url request, if theThere are 100 operations in it, and it would be inappropriate to use if judgments anymore Answer: Using the python reflection mechanism, the
The contents of the document remain unchanged and the document is modified to read as follows
import commons def run(): inp = input("Please enter the url of the page you want to visit: ").strip() if hasattr(commons, inp): getattr(commons, inp)() else: print("404") if __name__ == '__main__': run()
Using these lines of code, it is possible to cope withCalls to any number of page functions in the file!
Built-in Functions in Reflection
getattr
def getattr(object, name, default=None): # known special case of getattr """ getattr(object, name[, default]) -> value Get a named attribute from an object; getattr(x, 'y') is equivalent to . When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case. """ pass
getattr()
The first argument to the function needs to be an object, and in the example above, I imported the customizedcommons
module, commons is an object; the second argument specifies the name of a method in the preceding object.
getattr(x, 'y')
Equivalent to executing the. If the second parameter is a method that does not exist in the previous object, the function will throw an exception and exit. So at this point, for the sake of program robustness, we need to determine whether the method exists in the object first, so we use the
hasattr()
function (math.)
hasattr
def hasattr(*args, **kwargs): # real signature unknown """ Return whether the object has an attribute with the given name. This is done by calling getattr(obj, name) and catching AttributeError. """ pass
hasattr()
The function returns whether the object has a property with the specified name, which simply means that it checks whether a method with the same name as the second parameter can be found in the object with the first parameter. The explanation of the source code also says that the implementation of the function is actually a call to thegetattr()
function, except that it catches the exception. So with this function, we can go ahead and determine if the object has this method in it, and if it does, we can use thegetattr()
to get the method.
setattr
def setattr(x, y, v): # real signature unknown; restored from __doc__ """ Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to `` = v'' """ pass
setattr()
function is used to reassign a method in the specified object (assigning the new function body/method body to the specified object name) takes effect only in the memory of this program run.setattr(x, 'y', v)
equivalence = v
delattr
def delattr(x, y): # real signature unknown; restored from __doc__ """ Deletes the named attribute from the given object. delattr(x, 'y') is equivalent to ``del '' """ pass
Deletes the specified method in the specified object. Special note: the method is only deleted in the memory of the running program, and does not affect the contents of the file.
__import__ module reflection
Continuing with the example of the website above, now a backend file can no longer meet my needs, this time I need to divide the backend file according to the function, now I have added a newThis user class file also needs to be imported to the home page for calling.
However, for the website example above, I've written it to death to only be able to specify thecommons
module's methods are called arbitrarily, and there is now a newuser
module, so at this point I have to use if judgment again?
A: No, use the functions that come with Python__import__
Since the import of modules also requires the use of Python reflection features, the module name has to be added to the url as well, so now the url request becomes something likecommons/visit
forms
# def add_user(): print('Add User') def del_user(): print('Delete user')
# def login(): print("It's a landing page!") def logout(): print("It's an exit page!") def home(): print("This is the main website page!")
# def run(): inp = input("Please enter the url of the page you want to visit: ").strip() # modules for the imported modules, func for the methods inside the imported modules. modules, func = ('/') obj_module = __import__(modules) if hasattr(obj_module, func): getattr(obj_module, func)() else: print("404") if __name__ == '__main__': run()
final executionrun
function with the following results:
Please enter the url of the page you want to visit: user/add_user
Add User
Please enter the url of the page you want to visit: user/del_user
Delete User
We can appreciate it now.__import__
What it does now is to import strings as modules.
But what if the structure of my site becomes the following
|- |- |- |- lib |- __init__.py |-
Now I want to be invisit
Calls in the pagelib
take overconnectdb
Is it ok to call the methods in the module, or in the same way as before?
# def conn(): print("Connected to mysql.")
# def run(): inp = input("Please enter the url of the page you want to visit: ").strip() # modules for the imported modules, func for the methods inside the imported modules. modules, func = ('/') obj_module = __import__('lib.' + modules) if hasattr(obj_module, func): getattr(obj_module, func)() else: print("404") if __name__ == '__main__': run()
(of a computer) runrun
command with the following results:
Please enter the url of the page you want to access: connectdb/conn
404
The result shows that it can't be found, and in order to test calling modules under lib, I ditched support for all sibling directory modules, so we need to look at the__import__
source code (computing)
def __import__(name, globals=None, locals=None, fromlist=(), level=0): # real signature unknown; restored from __doc__ """ __import__(name, globals=None, locals=None, fromlist=(), level=0) -> module Import a module. Because this function is meant for use by the Python interpreter and not for general use, it is better to use importlib.import_module() to programmatically import a module. The globals argument is only used to determine the context; they are not modified. The locals argument is unused. The fromlist should be a list of names to emulate ``from name import ...'', or an empty list to emulate ``import name''. When importing a module from a package, note that __import__('', ...) returns package A when fromlist is empty, but its submodule B when fromlist is not empty. The level argument is used to determine whether to perform absolute or relative imports: 0 is absolute, while a positive number is the number of parent directories to search relative to the current module. """ pass
__import__
function has afromlist
parameter, the source code explains that if a module is imported in a package, this parameter if empty, then return this package object, if this parameter is not empty, then return the module object specified below the package, so we are above the return of the package object, so it will return 404 results, now modify the following:
# def run(): inp = input("Please enter the url of the page you want to visit: ").strip() # modules for the imported modules, func for the methods inside the imported modules. modules, func = ('/') # Only added fromlist=True obj_module = __import__('lib.' + modules, fromlist=True) if hasattr(obj_module, func): getattr(obj_module, func)() else: print("404") if __name__ == '__main__': run()
Run the run method with the following results:
Please enter the url of the page you want to access: connectdb/conn
Connected mysql
It worked, but I wrote it to death.lib prefix
It's the equivalent of abandoning thecommons
cap (a poem)user
two imported functions, so the above code is not perfect, the demand is complex, or need to do a little judgment on the request url
def getf(module, func): """ Withdrawal of the public portion """ if hasattr(module, func): func = getattr(module, func) func() else: print('404') def run(): inp = input("Please enter the url of the page you want to visit: ").strip() if len(('/')) == 2: # modules for the imported modules, func for the methods inside the imported modules. modules, func = ('/') obj_module = __import__(modules) getf(obj_module, func) elif len(("/")) == 3: p, module, func = ('/') obj_module = __import__(p + '.' + module, fromlist=True) getf(obj_module, func) if __name__ == '__main__': run()
Run the run function with the following results:
Please enter the url of the page you want to access: lib/connectdb/conn
Connected mysql
Please enter the url of the page you want to visit: user/add_user
Add User
Of course you can continue to optimize the code, now only judged with 1 slash and 2 slashes, if the directory level more it, this is not considered for the time being, this time is to understand python's reflection mechanism
The above is python reflection mechanism built-in functions and scene construction details, more information about python reflection mechanism built-in functions please pay attention to my other related articles!