Drupal Module Hooks
Drupal is a Content Management System. Drupal is also deeply, deeply weird. While systems like Magento often confuse people, the MVC structure that most people are used to is still there, it’s just more abstract. Web MVC systems are systems designed to, first and foremost, help programmers manage the complexity of their code.
Drupal is something else. It’s a system designed, first and foremost, to help website developers get their content on a website. Drupal contains several programming systems, and is built around object oriented concepts implemented without classes. In fact, architecturally Drupal can be thought of as a container that holds multiple systems, and all these systems interact to get a piece of content on a website.
Drupal has just undergone a major version release. With that revision comes refinements to the system, as well as a renewed interest in the platform from outside the community. Over the next few months I’m hoping to explore and write about Drupal from the point of view of a PHP programmer. Not just using the systems, but understanding how they’re implemented and in turn, uncovering their full potential/power. The specifics will be for the just released Version 7, but I imagine many of the concepts will be applicable to older versions as well.
We’ll be starting with Drupal’s module system, which is the glue that binds all the other sub-systems together.
Setup
Before we start, we’ll need to write some wrote voodoo setup code. This code may seem weird an unintuitive at first. The explanations for what you’re doing may not make sense. Follow the instructions, persevere, and at the end of this article come back and things should make more sense.
We’re going to setup two empty Drupal modules which we’ll use later. We’ll also being copying the default Drupal index.php
so we can run some code in isolation to show you how Drupal modules work.
We’ll start with creating a module.
Create the following folder (directory paths are relative to the Drupal site root)
mkdir sites/all/modules/modulea
and then create two empty text files (we’re using the *nix “touch” command for this)
touch sites/all/modules/modulea/modulea.info
touch sites/all/modules/modulea/modulea.module
Finally, add the following contents to the modulea.info
file.
; File: sites/all/modules/modulea/modulea.info (don't include this line)
name = Module A
description = First Example Module
package = Alanstormdotcom
version = VERSION
core = 7.x
files[] = modulea.module
That’s enough to create a simple module. Drupal will use the module’s folder name (in our case, modulea
), as the module’s internal, programatic identifier. The .info
file is a configuration file (ini style) that contains information about the module. Its presence and contents is what tells Drupal the module exists.
The modulea.module
file will eventually contain the PHP code for our module. If you’re using a search tool like ack you’ll want to add the .module
extension to list of valid extensions for PHP files (while you’re there, add .inc
as well). Depending on your editor you may need to make similar tweaks to get syntax highlighting working in these files.
We’re placing the module in the sites/all/modules
folder. This is where third party modules (also called contrib modules) that we want made available to all sites should go. Drupal offers feature that allows you to enable modules on a per-site (hostname) basis. By placing the module in all
, its functionality will be available to everyone.
To ensure we’ve installed our module correctly, Navigate to
Modules
while logged into Drupal as an Admin user. There’s a lot of Drupal functionality that’s only available via the GUI Admin, or by knowing which database bit to flip. This is one of things that seems weird to outsiders. Drupal isn’t a system meant to help you program, its a system meant to help you manage your content in a website, which means you’ll always prefer a browser GUI. If you don’t, then you’re (obviously!) a core Drupal developer who knows their business and doesn’t need an extra layer between you and the Core code.
I’m not exactly advocating for this view of the world, but if you’re going to become involved in the Drupal community you need to accept that’s where they’re coming from.
Enough moaning! Back to work! If you click on the Module admin menu item, you’ll see a list of all the Modules installed in the system. Below the Core modules group, you should see a new module group named Alanstormdotcom (this name is derived from the modula.info
file).
You may need to clear your Drupal cache for this module to show up. Drupal, like most modern systems, implements internal caching to speed up certain tasks. You can do so by navigating to
Configuration -> Development -> Performance
and clicking the Clear all caches button.
Over the years this “Use the GUI or known the system” approach has left some developers wanting, and a robust community of tools has grown up around the Drupal. You may want to look into some of the alternative modules and tools for quickly clearing/disabling the Drupal cache. I’ve only been using it for a bit, but I’m a big fan of drush, a command line too for performing common system tasks.
Finally, I’m new enough to the system that I’m not sure where/when clearing the cache is or isn’t required. If something you’re trying isn’t working, it never hurts to clear out your cache and try again.
Enabling the Module
Just because a module is installed doesn’t mean its enabled. Drupal will only load code from modules that are enabled. This allows you to install third party code, but quickly turn it around off if the need arrises. If it isn’t, check the checkbox and then click Save Configuration. Your new, behavior-less, “Module A” is now a part of the system! Let’s do the same for a second Module, Module B
Create the following folder (from the Drupal site root)
mkdir sites/all/modules/moduleb
and then create the following files
touch sites/all/modules/moduleb/moduleb.info
touch sites/all/modules/moduleb/moduleb.module
And then add the following contents to the .info
file.
#File: sites/all/modules/modulea/moduleb.info (don't include this line. That goes for all the #File lines in this tutorial. We won't tell you again.)
name = Module B
description = Second Example Module
package = Alanstormdotcom
version = VERSION
core = 7.x
files[] = moduleb.module
That’s Module A and Module B in place! For our last bit of voodoo setup, copy your index.php
file.
cp index.php working.php
and then edit working.php
so it contains the following
1
2
3
4
5
6
|
define( 'DRUPAL_ROOT' , getcwd ()); require_once DRUPAL_ROOT . '/includes/bootstrap.inc' ; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); echo '<p>Done</p>' ; ###menu_execute_active_handler(); |
and load your working.php
file in a browser.
http://drupal.example.com/working.php
You should see the word “Done” displayed on a white background. What we’ve done here is commented out the code that would normally display a Drupal page, and but kept in the code that bootstraps the Drupal system. We’ll cover this in greater detail later.
With that out of the way, we’re ready to begin!
What a Module Is
As I’m fond of pointing out, there’s no word in software development more hijacked that the word module. As you’d expect, Drupal has it’s own take on modules that’s different than other systems you may have worked with.
Drupal’s module system implements a Hook system. This system resembles class based observer/listener patterns you may be familiar with, but no classes or objects are used. Instead, the system is implemented entirely with PHP’s variable function features. This may seem weird if you’re just coming into PHP development, but remember Drupal’s history.
Drupal is over a decade old, its first versions surfacing in the open source community sometime around 2001. PHP was a popular language at the time, but PHP 4 was the new version. Objects based on classes were not references, which means traditional OOP patterns weren’t readily availability. Even once PHP 5 broke onto the scene, it’s class/object system was noticeably slower that solutions implemented using only functions. Code performance speed approaches deity like status in the Drupal community, so rather than play with the cards PHP dealt them, Drupal developers chose to implement their own system. Also, it’s more fun to roll your own!
This sort of decision is one of the many things that programmers like to argue about. My suggestion to you is accept that Drupal made the decision, and learn to use the systems they’ve provided. If you can’t do that, and you’re bent out of shape about it, pick another system. If you can’t pick another system and hate the one you’re being forced to you, meditate on why you’re working where you are.
So, what are Hooks? The way I’ve come to understand them is that hooks allow you to distribute a single function call over multiple include files. Let’s pretend we’re writing a PHP function to do something
1
2
3
4
5
6
7
8
9
10
11
12
|
function do_something( $thing ) { //code here to do something awesome //insert some database information //mark a flag //chat up a potential spouse //sing a song return $something } ... somewhere else in our program ... do_something(); |
Once we’ve written that function and deployed the code, we can’t easily change it. That is, it’s easy enough to edit the file, but other coders may have become reliant on how that function works. It’s very hard for a programmer to communicate, purely through code and comments, everything a function is supposed to do. Even if you have a team with perfect communication, there’s the problem of unintended side effects a function may have. A tenant of systems programming is never change existing code, even if you think you understand everything it does.
Here’s the problem we’re trying to solve. When “something” happens, we want to take additional actions. Requirements change, new functionality is needed. These are the standard conditions on the ground for a developer. So how do we not change code that we don’t own (Drupal core), but still take those additional actions?
That’s the problem Hooks solve. When you want to do something, instead of calling a function, you invoke a hook.
1
2
3
4
5
|
//old way, calling do_something function //do_something(); //new way: invoking do_something hook module_invoke_all( 'do_something' ); |
When a hook is invoked, Drupal will
Get a list of all installed and enabled modules
Ask each module “Have you implemented the do_something hook”?
If so, then Drupal calls the function in those modules that implement the hook
This way, as a core developer, you can achieve what you want while still letting other programers “hook into” what you’re doing.
What does this look like?
Makes sense in the abstract, but what does that look like in real code? Let’s take a look. We’re going to
- Write code that invokes a hook named
helloworld
- Write code that implements the
helloworld
hook in Module A - Write code that implements the
helloworld
hook in Module B
Let’s get started.
In the setup section we created an alternate index.php
file named example.php
. Change the contents of this file so they match the following
1
2
3
4
5
6
|
define( 'DRUPAL_ROOT' , getcwd ()); require_once DRUPAL_ROOT . '/includes/bootstrap.inc' ; drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); module_invoke_all( 'helloworld' ); echo '<p>Done</p>' ; ###menu_execute_active_handler(); |
We’ve commented out the menu_execute_active_handler
function call. This is the call that would actually render out a Drupal
page. For the purposes of this tutorial, we don’t want that to happen.
This is why we’ve commented it out.
We’ve left in the call to the drupal_bootstrap
function.
This loads up the Drupal system and includes all the code necessary
for Drupal to run. We need this loaded in, because its the bootstrapping
that loads in the module system code.
In-between those two standard function calls we’ve added two lines
1
2
|
module_invoke_all( 'helloworld' ); echo '<p>Done</p>' ; |
The echo is a sanity thing to ensure that PHP is executing down to the bottom of the file. If you load your page and don’t see Done
,
then you know there was an error previously. Strictly speaking this
isn’t needed, but I’ve worked on enough PHP systems to know you’re never
sure where/when error reporting is done.
The module_invoke_all
function call is the interesting bit. This function isn’t the only
way to invoke a hook, but it’s the most obvious way to do so. With the
code above, we’ve handled our first requirement, invoking a Hook. The
Hook’s name is helloworld
.
Load working.php
in a browser, and … only the word Done shows up. While we’ve invoked a hook, there’s no Drupal modules that implement that hook. Therefore, nothing extra happens. Let’s take care of that.
Implementing a Hook
Earlier in this article, we created two modules. Module A, and Module
B. Make sure these modules are enabled before continuing.
Next, open up Module A’s .module file, and enter the following
1
2
3
4
5
6
|
#File: sites/all/modules/modulea/modulea.module <?php function modulea_helloworld() { echo "<p>Our friends at " . __FUNCTION__ . " want to say Hello World</p>" ; } |
Remember, despite the .module
extension this is just another PHP file. Clear your Drupal cache and reload working.php
. You should see the text
Our friends at modulea_helloworld want to say Hello World
That’s it! You’ve now implemented your first hook. To implement a hook in a module, all that’s required is
Create a function in your module’s
.module
fileThe function’s name should start with the name of your module, and then an underscore (
modulea_
)The function’s name should continue with the name of the hook to implement (
helloworld
)Implement whatever code you want in your new function
Let’s do the same in Module B. Open up Module b’s .module
file, and enter the following
1
2
3
4
5
6
|
#File: sites/all/modules/moduleb/moduleb.module <?php function moduleb_helloworld() { echo "<p>Our friends at " . __FUNCTION__ . " want to say Hello World</p>" ; } |
We’re editing moduleb.module
, and have created a function name by combining moduleb
(our module name) and helloworld
(our Hook name). Reload working.php
, and you’ll see two messages
Our friends at modulea_helloworld want to say, Hello World
Our friends at moduleb_helloworld want to say, Hello World
And that’s it. While this example is trivially simple, the possibilities and power of this sort of distributed function calling is what helps make Drupal such a powerful and customizable system.
Hook Return Values
Hopping back up to working.php
, let’s change our invocation slightly
1
2
|
$results = module_invoke_all( 'helloworld' ); var_dump( $results ); |
Instead of just calling module_invoke_all
, we’re calling it and assigning its results a variable. If you reload working.php
, you’ll get something like
Our friends at modulea_helloworld want to say, Hello World
Our friends at moduleb_helloworld want to say, Hello World
array
empty
Our call to module_invoke_all
returned an empty array. Let’s change our two hook implementations slightly.
1
2
3
4
5
6
7
8
9
10
11
12
|
#File: sites/all/modules/modulea/modulea.module ... function modulea_helloworld() { return "<p>Our friends at " . __FUNCTION__ . " want to say, Hello World</p>" ; } ... #File: sites/all/modules/moduleb/moduleb.module function moduleb_helloworld() { return "<p>Our friends at " . __FUNCTION__ . " want to say, Hello World</p>" ; } |
Instead of echoing our strings, we’re returning them. Give the browser a refresh, and you should now see something like.
array
0 => string '<p>Our friends at modulea_helloworld want to say, Hello World</p>' (length=65)
1 => string '<p>Our friends at moduleb_helloworld want to say, Hello World</p>' (length=65)
Invoking a hook will always return an array, and that array will contain the values of each module’s hook implementation return value. if a hook implementation returns null (or lacks an explicit return) nothing is added to the return array. That’s why our initial return value was an empty array.
Let’s change Module A so it returns an array of strings.
1
2
3
4
|
function modulea_helloworld() { return array ( "one" , "two" , "three" ); } |
You might expect your hook invocation to return a nested array. Refresh the page, and you should see.
array
0 => string 'one' (length=3)
1 => string 'two' (length=3)
2 => string 'three' (length=5)
3 => string '<p>Our friends at moduleb_helloworld want to say, Hello World</p>' (length=65)
Instead of returning a nested array, Drupal has merged the hook implementation’s return values into the invocations return array. If you use an array with non-sequenced keys, (an “associative array”) something similar happens
1
2
3
4
|
function modulea_helloworld() { return array ( "foo" => "one" , "baz" => "two" , "bar" => "three" , "function" => __FUNCTION__ ); } |
Returns something like …
array
'foo' => string 'one' (length=3)
'baz' => string 'two' (length=3)
'bar' => string 'three' (length=5)
'function' => string 'modulea_helloworld' (length=18)
0 => string '<p>Our friends at moduleb_helloworld want to say, Hello World</p>' (length=65)
Returning an associative array merges the keys into our invocation’s return value. So what happens if there’s a key collision between two hook implementations? Give the following a try
1
2
3
4
5
6
7
8
9
10
11
12
|
#File: sites/all/modules/modulea/modulea.module ... function modulea_helloworld() { return array ( "foo" => "one" , "baz" => "two" , "bar" => "three" , "function" => __FUNCTION__ ); } ... #File: sites/all/modules/moduleb/moduleb.module function moduleb_helloworld() { return array ( 'function' => __FUNCTION__ ); } |
Both Hook implementations are returning an array with a key named ‘function’. Reload the page, and you’ll see
array
'foo' => string 'one' (length=3)
'baz' => string 'two' (length=3)
'bar' => string 'three' (length=5)
'function' =>
array
0 => string 'modulea_helloworld' (length=18)
1 => string 'moduleb_helloworld' (length=18)
So, if the keys collide, Drupal will merge the colliding keys into a nested array. When you’re invoking hooks in your Drupal code, it’s important to be aware of all the return values you could possibly get. When you’re implementing hooks (ex. for existing Drupal systems) it’s important to know what sort of return value the invoking code expects.
One last note: This merging of values described above only happens with PHP’s built in array type. If you’re using the standard library ArrayObject
or something that implements ArrayAccess
, Drupal will treat the returned value as an object, and merge the object itself into the array.
array
0 => object (ArrayObject)[5]
1 => object (ArrayObject)[5]
etc ...
Again, remember Drupal’s pre-PHP 5 OOP history. When Drupal was created ArrayObject’s weren’t even a gleam in Rasmus’s eye.
Hooks vs. Events
Return values are where hooks differ from most of the traditional event/observer systems I’ve seen. In most systems, the core code will do something, and then issue an event to let outsiders know it happened. This way, when Event A happens in the core system, outside developers can have other things happen.
An event observer will, typically, not return a value to be used by the core system. Hooks, on the other hand, take an active role in defining the behavior of the core system. One way of thinking about is that Event/Observers say
Hey, just so you know, this happened
Whereas Hooks say
Hey, we’re doing this thing, do you want to be part of it?
That’s why I prefer to think of Hooking as distributing a function call over multiple include files. It’s a subtle different, but once you understand it the rest of Drupal will start making a little more sense.
For Design Patterns folks, ircmaxell over at Stack Overflow told me that Hooks are an implementation of the Mediator pattern.
Invoking Hooks
There’s a few more things to cover in regards to invoking hooks. First, there may be times when you don’t want to trigger all the implemented hooks in the system. This is most typically done when a hook implementation provides a valuable bit of programing logic you want to take advantage of. There may also be times where a full, all module invocation would change the system state in an undesirable way.
In an ideal world, all our systems and modules would be architected such that this sort of thing wasn’t needed. Since none of us are riding Unicorns, Drupal provides the module_invoke
function
1
|
$results = module_invoke( 'modulea' , 'helloworld' ); |
The code above would call only our modulea_helloworld
hook implementation. Use it sparingly, as you’re denying other modules the opportunity to “hook into” whatever part of the code you’re using.
Next up is parameters for hooks. Both module_invoke
and module_invoke_all
accept an unlimited number of extra parameters.
1
2
|
module_invoke_all( 'helloworld' , 'one' , 'two' , 'three' ); module_invoke( 'modulea' , 'helloworld' , 'one' , 'two' , 'three' ); |
These parameters are, in turn, passed on to the hook implementations. Consider the following
1
2
3
4
|
function modulea_helloworld( $param , $another_param , $third ) { return array ( 'joined' =>implode( '##' , array ( $param , $another_param , $third ))); } |
The strings ‘one’,’two’, and ‘three’ are passed in as $param, $another_param, $third
.
Behind the scenes, Drupal implements this by using PHP’s func_get_args function. This implementation presented a problem, which brings us to the last thing we want to cover on hook invocation.
There are times where you want your hook implementation to be able to change some data structure you’re working with. In our 2011/PHP 5 world, we’d most likely achieve this by passing in an object.
1
2
3
4
|
$object = new SomeClass(); module_invoke( 'modulea' , 'helloworld' , $object ); //we've got an object that's been modified by our hook implementations $object ; |
Objects in PHP 5 are references, which means hook implementations could make all the changes they want. However, remember the context of Drupal. It’s a PHP 4 world, and everything is pass by copy. Passing in big arrays (or even PHP 4’s primitive objects) to functions and then returning them comes with potential performance problems, as another copy of the array or object needs to be made. PHP offers a solution to this, allowing you to declare your function in such a way that parameters are passed by reference
1
2
3
4
5
|
function somefunction(& $param ) { //the & in front of the parameters means if we change it down //in the function, it will be changed in the main program. } |
However, because module_invoke
and module_invoke_all
use func_get_args
, it’s impossible to pass values via the hook invocation by reference.
This led to the Drupal community coming up with two solutions
The first is the drupal_alter
function, which is an alternative way to invoke hook implementations. Doing
1
|
drupal_alter( 'helloworld' , $data ); |
would invoke the hook helloworld_alter
, with the variable $data being passed into hook implementations by reference.
Read that again and make sure the following sinks in. There’s no way to invoke the hook named hello_world
using drupal_alter
. The drupal_alter
function forces you to name you hooks with the _alter
naming convention. This is useful to people implementing the hooks, as they can expect that any hook ending with the name alter with have parameters passed by reference. In Drupal 7 you can pass up to three parameters in as reference parameters.
1
|
drupal_alter( 'helloworld' , $data , $foo , $bar ); |
Another thing to watch out for is drupal_alter
doesn’t return any values. It’s strictly for allowing modules to hook in and alter variables.
Breaking Encapsulation
Because of the constraints on drupal_alter
, there’s second alternative invocation method, which will give some of you the encapsulation jibblies. However, it’s in common use among the Drupal community; even core modules use it. Whether or not you agree with the post you’ll want to be familiar with it.
Drupal provide a function named module_implements
which will return a list of modules that implement a particular hook. Try the following
1
2
|
$results = module_implements( 'helloworld' ); var_dump( $results ); |
and you should get an array with your two modules
array
0 => string 'modulea' (length=7)
1 => string 'moduleb' (length=7)
When someone wants to pass a variable by reference into a hook implementation and not use the _alter
naming syntax, or they want to hook implementation to return something, you’ll see something like this.
1
2
3
4
5
6
7
8
9
10
11
12
|
$hook = 'helloworld' ; $etc = array ( 'one' , 'two' ); $param_by_ref = 'four' ; $all = array (); foreach (module_implements( $hook ) as $module ) { $function = $module . '_' . $hook ; $single_hook_return = $function ( $param_by_ref , $etc ); $all = array_merge ( $all , $single_hook_return ); } var_dump( $all ); echo '<p>Done</p>' ; |
Jibblies! The functionality provided by module_invoke_all
is replicated here, but outside the function. This breaks encapsulation, and we’re seeing another example of the black/white split in the core Drupal philosophy of “you’re either not a programmer, or you know the system explicitly”. Breaking module_invoke_all
’s encapsulation of the Hook system isn’t a big deal, because who needs a level of encapsulation between a programmer and the core system? AMIRITE?
The problem with this being in wide use is it essentially forces the hook implementation that exists today to exist for all time, or else backward compatibility with code that uses this be broken. That’s a trade off the community is willing to make, so be ready to see code like this in the wild.
Consumer of Hooks
All of that said, most of your time as a day-to-day Drupal programmer, especially in the beginning, will be spent implementing hooks provided by the core system and contrib (third party) modules. The Core Drupal APIs and Systems that are heavily promoted are all implemented, internally, using the module system. Each API may provide a number of different hooks for you to implement, each with it’s own conventions. Some may want you to alter a variable passed by reference, others may expect you to return values in a specific format.
Again Drupal’s various sub-systems use the module system to implement functionality. Third parties can use the module system to change default system behavior. Each sub-system may have a different design philosophy. This difference between sub-systems is, I think, the reason some people group Drupal into the “hard to learn” category. Instead of learning a single system, you need to learn many. It’s Hooks that tie them all together.
Like most steep learning curves, once you understand a particular API its power quickly makes the time investment worth it. Knowing how the module system works is the first step towards mastering Druapl. It’s the system all other systems use and rely on, and once you’re comfortable with it, you can start invoking hooks in your own modules, which will in turn allow other developers to use your module as an API. This is a key philosophy of the Drupal community, and one of the reasons we’re still talking about the platform more than a decade after it’s creation.
注:原文链接http://alanstorm.com/drupal_module_hooks
Drupal Module Hooks的更多相关文章
- drupal module 自定义
01 <?php function mytracer_menu() { $items = array(); $items['admin/config/mytracer'] = array( 't ...
- Drupal模块的安装方法
Drupal自身的安装很简单,新建一个数据库,然后根据安装提示一步一步做就OK了. 而Drupal可以通过安装各种模块来提供更多定制功能,这些模块的安装方法基本相同,一般来说,就是以下几步: 1) 从 ...
- Drupal Coder 模块远程命令执行分析(SA-CONTRIB-2016-039)
转载请注明文章出处:http://www.cnblogs.com/magic-zero/p/5787181.html 起初看到这个漏洞的时候是在exploit-db上边.地址在这里:https://w ...
- Linux LSM(Linux Security Modules) Hook Technology
目录 . 引言 . Linux Security Module Framework Introduction . LSM Sourcecode Analysis . LSMs Hook Engine: ...
- 基于BitNami for XAMPP进行Drupal7安装的教程(Win7平台)
BitNami是一个开源项目,该项目产生的开源软件包可用于安装Web应用程序和解决方案堆栈,以及虚拟设备.BitNami 提供wordpress.joomla.drupal.bbpress等开源程序的 ...
- web 应用常见安全漏洞
1. SQL 注入 SQL 注入就是通过给 web 应用接口传入一些特殊字符,达到欺骗服务器执行恶意的 SQL 命令. SQL 注入漏洞属于后端的范畴,但前端也可做体验上的优化. 原因 当使用外部不可 ...
- 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记(6)- 打包发布(PyInstaller3.3.1)
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生之打包发布. 经过上一篇软件优化之后,Jays-PyCOM已经初长成,该到了出去历练的时候了,只有经 ...
- Python - 使用Pyinstaller将Python代码生成可执行文件
1 - Pyinstaller简介 Home-page: http://www.pyinstaller.org PyInstaller是一个能够在多系统平台(Windows.*NIX.Mac OS)上 ...
- WARNING: Can not get binary dependencies for file...
环境: window7 64bit python 3.5 pyinstaller 3.2 用pyinstaller 将python文件打包成exe文件的过程中,出现了如下的错误 C:\Users\ca ...
随机推荐
- HTML5+CSS实现三列布局自适应
利用CSS的float属性可以将元素并排,做出三列并排的布局. 如这样的效果 实现的原理:只要将3个元素设置float属性,属性值为left,同时指定不同比例的宽度,及高度. 下面是实现代码 < ...
- 190320运算符&数据类型
一.运算符 1.算术运算符 + 加 - 减 * 乘 / 除 ** 平方 // 整除 % 取余 2.比较运算符 == 等于 > 大于 < 小于 <= 小于等于 >= 大于等于 ! ...
- python学习之路---day20--面向对象--多继承和super() 函数
一:python多继承 python多继承中,当一个类继承了多个父类时候,这个类拥有多个父类的所欲非私有的属性 l例子: class A: pass class B(A): pass class C( ...
- asp.net boilerplate 配置文件加载
- 【算法笔记】B1009 说反话
1009 说反话 (20 分) 给定一句英语,要求你编写程序,将句中所有单词的顺序颠倒输出. 输入格式: 测试输入包含一个测试用例,在一行内给出总长度不超过 80 的字符串.字符串由若干单词和若干空格 ...
- MVC4设置伪静态---路由伪静态
有些客户要求设置静态的,为了完成需求,而且更简单的做法就是设置伪静态,例如:http://localhost:80/Home/Index.html ,也可以访问http://localhost:80/ ...
- Modular Inverse (拓展欧几里得求逆元)
The modular modular multiplicative inverse of an integer a modulo m is an integer xsuch that a-1≡x ( ...
- Linux——文件和文件夹的操作
Linux有三种文件: 普通文件(包括文本文件.源码文件.可执行文件等等) 设备文件(或者成为特殊文件,linux通过设备文件与外部设备进行通讯,例如:光驱.打印机.终端.modern) 设备文件有两 ...
- 深入应用C++11:代码优化与工程级应用》勘误表
https://www.cnblogs.com/qicosmos/p/4562174.html
- Android报错
Error:Execution failed for task ':app:processDebugResources'. > com.android.ide.common.process. ...