Describes how to use the Hook technique in Python development and the pythonhook technique.

Source: Internet
Author: User

Describes how to use the Hook technique in Python development and the pythonhook technique.

What is a Hook is to add some hooks to an existing method so that some additional processing is performed before or after the method is executed, so what is the function of the Hook technique and why we need to use it? In fact, if a project has sufficient considerations in designing the architecture and the module abstraction is reasonable enough, at the beginning of the design, we reserved enough interfaces for future extensions, so we can skip the Hook technique. However, at the beginning of the project design, it is often impossible for the architects to think far-reaching enough, which makes Shenzhen face the pain of restructuring in the future expansion. At this time, the Hook technique seems to be able to bring us a piece of cake, add hooks to the old architecture to meet new expansion requirements.

Next, let's take a look at the Hook processing. We will introduce them one by one based on the level of the Hook object.

Hook a class

That is to say, we need to monitor the creation and other operations of the class, and then perform the operations we want before or after this.

1. Create a Hook class

You can add the _ metaclass _ attribute to a class when writing it.

class Foo(Bar): __metaclass__ = something…

The process of creating a class in Python is as follows:

Is the _ metaclass _ attribute in Foo? If yes, Python creates a class named Foo through _ metaclass _ in the memory. If Python does not find _ metaclass __, it will continue to search for the _ metaclass _ attribute in Bar (parent class) and try the same operations as the previous one. If Python cannot find _ metaclass __in any parent class, it searches for _ metaclass __at the module level and tries the same operation. If _ metaclass __is still not found, Python will use the built-in type to create this class object.

Therefore, the value of the _ metaclass _ attribute must be something that can create a class, that is, a class that inherits the type.

For example:

Copy codeThe Code is as follows:
Class Singleton (type): def _ init _ (cls, name, bases, dict): super (Singleton, cls ). _ init _ (name, bases, dict) cls. _ instance = None def _ call _ (cls, * args, ** kw): if cls. _ instance is None: cls. _ instance = super (Singleton, cls ). _ call _ (* args, ** kw) return cls. _ instanceclass MyClass (object): _ metaclass _ = Singleton

Singleton is an object that can create classes because it inherits the type

For this reason, we can monitor the creation process of MyClass In the Singleton class.

2. Hook instance attributes

Here we need to operate on the properties of _ getattribute _ and _ getattr __

Object. _ getattribute _ (self, name): This method is accessed first regardless of whether the access exists or does not exist.

Object. _ getattr _ (self, name): Access this method when the _ getattribute _ method does not exist or an AttributeError error occurs.

Copy codeThe Code is as follows:
Class C (object): a = 'abc' def _ getattribute _ (self, * args, ** kwargs): print (_ getattribute _ () is called) return object. _ getattribute _ (self, * args, ** kwargs) def _ getattr _ (self, name): print (_ getattr _ () is called) return namec = C () print c. a _ getattribute _ () is calledabcprint c. aa _ getattribute _ () is called _ getattr _ () is calledaa

We can see that when accessing an existing attribute a, __getattribute _ is called. when accessing the undefined attribute aa, _ getattribute _ is called first, and _ getattr _ is called.

3. Hook attributes

The python descriptor is an object attribute of "binding behavior". In the descriptor protocol, it can override the access to the attribute through methods. These methods include _ get _ (), _ set _ (), and _ delete __(). If any of these methods is defined in an object, this object is a descriptor.

Copy codeThe Code is as follows:
Class Desc (object): def _ get _ (self, instance, owner): print (_ get __...) def _ set _ (self, instance, value): print ('_ set __... ') class TestDesc (object): x = Desc () t = TestDesc () t. x _ get __...

-Self: Desc instance object, which is actually the property of TestDesc x

-Instance: instance Object of TestDesc, which is actually t

-Owner: who owns these things. Of course, it is the class TestDesc. It is the highest ruler, and others are included in or generated by it.

To make descriptors work properly, they must be defined at the class level. Otherwise, Python cannot automatically call the _ get _ and _ set _ methods for you.

According to the previous descriptions of class methods, will the TestDesc _ getattribute _ method be referenced when t. x is referenced? The answer is yes. In fact, the actual search order in python is as follows:

1) _ getattribute _ (), call unconditionally

2) Data Descriptor (defined by _ set _ or _ delete _): from 1) trigger call (if the _ getattribute _ () method is reloaded manually, the descriptor may not be called)

3) instance object dictionary

4) Class dictionary

5) non-data Descriptor (only the _ get _ descriptor is defined)

6) Dictionary of the parent class

7) _ getattr _ () method

4. Hook classes with Modifiers

Copy codeThe Code is as follows:
Def singleton (cls, * args, ** kw): instances = {} def _ singleton (): if cls not in instances: instances [cls] = cls (* args, ** kw) return instances [cls] return _ singleton @ singletonclass MyClass (object): a = 1 def _ init _ (self, x = 0): self. x = x

We use the singleton method to modify MyClass to a singleton mode, and we also monitor the process of MyClass instances in the singleton method.

Hook Methods

1. Hook methods with Modifiers

1) modify the method without Parameters

Copy codeThe Code is as follows:
Def something (func): def wrap (): print start func () print end return wrap @ somethingdef func (): pass

2) modify the method with Parameters

Copy codeThe Code is as follows:
Def something (func): defwrap (* args, ** kargv): print startfunc (* args, ** kargv) print end return wrap @ somethingdef func (a, B): pass

3) Use a modifier with parameters to modify the method.

Copy codeThe Code is as follows:
Def something (a, B): def new_func (func): def wrap (* args, ** kargv): print a func (* args, ** kargv) print breturn wrap return new_func @ something (1, 2) def func (a, B): pass

Other hooks

1. built-in Hook Methods

Copy codeThe Code is as follows:
# Hookopen method real_open = _ builtins __. open _ builtin __. open = my_open # Hookimport method real_importer = _ import ____ builtins __. _ import _ = my_importer

The above operations make my_open Replace the python built-in open method, so we can use our own my_open method to monitor subsequent calls to the open method.

2. Monkey Patch

Copy codeThe Code is as follows:
From SomeOtherProduct. SomeModule import SomeClassdef speak (self): return "ookookeeeeeeeee! "SomeClass. speak = speak

In fact, this is the Hook technique used in all languages. We often use third-party packages and want to make some extensions on them, but do not want to use them when changing the original code.

More

The above mentioned modifier operations, so we have some tips to understand when using modifiers.

1. Use functools

Prevent function signature changes after modifier is used

Copy codeThe Code is as follows: from functools import wrapsdef my_dec (func): @ wraps (func) def wrapped (): print % siscalled % func. _ name _ return func () return wrapped @ my_decdef foo (): pass
After such processing, the signature of the foo method is consistent with that before modification. Otherwise, the signature will become the signature of the my_dec method.

2. Use the decorator module as the Modifier

Copy codeThe Code is as follows:
From decorator import decorator @ decoratordef wrap (f, * args, ** kw): print start f (* args, ** kw) print end # in this way, the wrap method becomes a decorator @ wrapdef func (): print func

3. Use classes as modifiers

Copy codeThe Code is as follows: class test (object): def _ init _ (self, func): self. _ func = func def _ call _ (self): print start self. _ func () print end @ testdef func (): print funcfunc () startfuncend

In practice, a class is rarely used as the modifier, but in fact, as long as a class implements the _ call _ method, it can be used as a modifier, in addition, because the class is more operable than the method, the class modifier can also implement richer features.

The following is an example for further understanding.

#-*-Coding: UTF-8-*-# import pythoncom import pyHook def onMouseEvent (event): # Listen to mouse event print "MessageName:", event. messageName print "Message:", event. message print "Time:", event. time print "Window:", event. window print "WindowName:", event. windowName print "Position:", event. position print "Wheel:", event. wheel print "Injected:", event. injected print "---" # Return True to pass the event to another handler # Note: if False is returned here, the mouse event is intercepted. # That is to say, your mouse seems to be frozen. It seems that you have lost the response. return Truedef onKeyboardEvent (event): # Listen to the keyboard event print "MessageName :", event. messageName print "Message:", event. message print "Time:", event. time print "Window:", event. window print "WindowName:", event. windowName print "Ascii:", event. ascii, chr (event. ascii) print "Key:", event. key print "KeyID:", event. keyID print "ScanCode:", event. scanCode print "Extended:", event. extended print "Injected:", event. injected print "Alt", event. alt print "Transition", event. transition print "---" # return True def main (): # create a "Hook" management object hm = pyHook. hookManager () # Listen to all Keyboard Events hm. keyDown = onKeyboardEvent # Set the keyboard "hook" hm. hookKeyboard () # Listen to all mouse events hm. mouseAll = onMouseEvent # Set the mouse "Hook" hm. hookMouse () # enters the loop. If you do not close it manually, the program will remain in the listening status pythoncom. pumpMessages () if _ name _ = "_ main _": main ()
Export test.pyto test.exe # Get py2exe from http://www.py2exe.org/from distutils. core import setupimport py2exesetup (console = ['test. py ']) # Run python setup in cmd. py py2exe, which has exe and required dll under the dist directory
# Hide the console and let it flash through import ctypes whnd = ctypes. windll. kernel32.GetConsoleWindow () if whnd! = 0: ctypes. windll. user32.ShowWindow (whnd, 0) ctypes. windll. kernel32.CloseHandle (whnd)

Let me talk about it first. The content we are talking about today is hard knowledge, which may not be available in the general development process. However, understanding this knowledge is very helpful for improving programming capabilities, it also helps you better understand the Python mechanism. We also hope that you can support the customer's home.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.