当前位置: 首页 > 编程日记 > 正文

如何一起破解图形化Python调试器

15分钟内从零调试 (Zero-to-Debugging in 15 mins)

You don’t realize the value of a debugger until you’re stuck working on a hard-to-visualize problem. But once you fire up a development environment with decent debugging capabilities, you’ll never look back.

直到您陷于难以想象的问题,您才意识到调试器的价值。 但是,一旦启动了具有良好调试功能的开发环境,您将永远不会回头。

Want to know where you’re at in code execution? What’s taking so long? Just pause it and check.

想知道您在代码执行中的位置吗? 什么要花这么长时间? 只需暂停并检查。

Wonder what value is assigned to that variable? Mouse over it.

想知道为该变量分配了什么值? 将鼠标悬停在它上面。

Want to skip a bunch of code and continue running from a different section? Go for it.

是否要跳过一堆代码并继续从其他部分运行? 去吧。

Sometimes print(variable_name) is just not enough to give you an idea of what’s going on with your project. This is when a good debugger can help you figuring things out.

有时print(variable_name)不足以使您了解项目的进展情况。 这是一个好的调试器可以帮助您解决问题的时候。

Python already gives you a built-in debugger in the form of pdb (a command line tool). But thanks to Python’s awesome community, there are a more options that feature graphical interfaces. And there are a ton of Integrated Developer Environments (IDEs) that work with Python, such as JetBrain’s PyCharm, Wingare’s WingIDE, and even Microsoft’s Visual Studio Community.

Python已经以pdb (命令行工具)的形式为您提供了内置调试器。 但是感谢Python强大的社区,还有更多具有图形界面功能的选项。 并且有大量可与Python一起使用的集成开发环境(IDE),例如JetBrain的PyCharm , Wingare的WingIDE甚至Microsoft的Visual Studio社区 。

But you’re not here to hear how one debugger is better than another, or which one is prettier, or more elegant. You’re here to learn how simple it is to write a python debugger that steps through your code. That gives you a glimpse into Python’s internals.

但是您不会在这里听到一个调试器比另一个调试器如何好,或者哪个调试器更漂亮或更优雅。 您在这里了解编写编写逐步执行代码的python调试器的简单性。 这使您可以了解Python的内部结构。

I’m going to show you how you can build one, and in doing so scratch an itch I’ve had for a long time.

我将向您展示如何构建一个,并为此付出了我很长一段时间的痒。

Now let’s get to it.

现在开始吧。

关于如何组织和处理Python代码的快速入门 (A quick primer on how Python code is organized and processed)

Contrary to popular belief, Python is actually a compiled language. When you execute code, your module is run through a compiler that spits out bytecode which is cached as .pyc or __pycache__ files. The bytecode itself is what later is executed line by line.

与流行的看法相反,Python实际上是一种编译语言。 当您执行代码时,模块将通过编译器运行,该编译器吐出字节码 ,该字节码将缓存为.pyc__pycache__文件。 字节码本身就是后来逐行执行的代码。

In fact, the actual CPython code that runs a program is nothing more than a gigantic switch case statement running in a loop. It’s an if-else statement that looks at an instruction’s bytecode, then dispositions it based on what that operation is intended to do.

实际上,运行程序的实际CPython代码无非就是在循环中运行的巨大switch case语句。 这是一条if-else语句,它查看指令的字节码,然后根据该操作的意图对其进行处理。

The executable bytecode instructions are internally referenced as code objects, and the dis and inspect modules are used to produce or interpret them. These are immutable structures, that although referenced by other objects — like functions — do not contain any references themselves.

可执行字节码指令内部引用为 代码对象 ,以及disinspect模块用于生成或解释它们。 这些是不可变的结构,尽管被其他对象(如函数)引用,但它们本身不包含任何引用。

You can easily look at the bytecode that represents any given source through dis.dis(). Just give it a try with a random function or class. It’s a neat little exercise that’ll help you visualize what’s going on. The output will look something like this:

您可以通过dis.dis()轻松查看代表任何给定源的字节码。 尝试使用随机函数或类。 这是一个精巧的小练习,可以帮助您直观了解正在发生的事情。 输出将如下所示:

>>> def sample(a, b):
...     x = a + b
...     y = x * 2
...     print('Sample: ' + str(y))
...
>>> import dis
>>> dis.dis(sample)
2       0 LOAD_FAST                0 (a)3 LOAD_FAST                1 (b)6 BINARY_ADD7 STORE_FAST               2 (x)
3      10 LOAD_FAST                2 (x)13 LOAD_CONST               1 (2)16 BINARY_MULTIPLY17 STORE_FAST               3 (y)
4      20 LOAD_GLOBAL              0 (print)23 LOAD_CONST               2 ('Sample: ')26 LOAD_GLOBAL              1 (str)29 LOAD_FAST                3 (y)32 CALL_FUNCTION            1 (1 positional, 0 keyword pair)35 BINARY_ADD36 CALL_FUNCTION            1 (1 positional, 0 keyword pair)39 POP_TOP40 LOAD_CONST               0 (None)43 RETURN_VALUE

Notice that each line in bytecode references its respective position in source code on the left column, and that it’s not a one-to-one relationship. There could be multiple smaller — one could even say atomic — operations that makeup a higher level instruction.

请注意,字节码中的每一行都在左列的源代码中引用了其各自的位置,并且不是一对一的关系。 可能有多个较小的操作(甚至可以说是原子操作)组成了更高级别的指令。

A frame object in python is what represents an execution frame. It contains a reference to the code object that’s currently executing, the local variables that it’s running with, the global names (variables) that are available and references to any related frames (like the parent that spawned it).

python中的框架对象代表执行框架。 它包含对当前正在执行的代码对象的引用,与之一起运行的局部变量,可用的全局名称(变量)以及对任何相关框架(例如生成它的父框架)的引用。

There are lot more details about these objects to discuss here, but hopefully this is enough to wet your appetite. You won’t need much more for the purposes of our debugger, though you should check out the Diving Deeper section for links on where to look next.

有关这些对象的更多详细信息在这里讨论,但是希望这足以满足您的食欲。 尽管您应该查看“更深入的了解”部分以获取关于下一步查找的链接,但对于我们的调试器而言,您不需要太多。

进入sys模块 (Enter the sys module)

Python provides a number of utilities in its standard library through the sys module. Not only are there things like sys.path to get the python path or sys.platform to help find details about the OS in which you are running, but there’s also sys.settrace() and sys.setprofile() to help write language tools.

Python通过sys模块在其标准库中提供了许多实用程序。 不仅像sys.path这样可以获取python路径,或者像sys.platform这样可以帮助您找到正在运行的操作系统的详细信息,还有sys.settrace()sys.setprofile()可以帮助编写语言工具。

Yes, you read that right. Python already has built-in hooks to help analyze code and interact with program execution. The sys.settrace() function will allow you to run a callback whenever execution advances to a new frame object and gives us a reference to it, which in turn provides the code object you’re working with.

是的,你看的没错。 Python已经具有内置的挂钩,可帮助分析代码并与程序执行进行交互。 sys.settrace()函数将允许您在执行前进到新的框架对象并为其提供引用的情况下运行回调,从而提供您正在使用的代码对象。

For a quick example of how this looks, let’s reuse the function from earlier:

有关其外观的快速示例,让我们重用之前的功能:

def sample(a, b):x = a + by = x * 2print('Sample: ' + str(y))

Assuming that every time a new frame is executed, you want a callback that prints the code object and line number its executing, you can define it as:

假设每次执行新框架时,您都需要一个回调来打印代码对象及其执行的行号,则可以将其定义为:

def trace_calls(frame, event, arg):if frame.f_code.co_name == "sample":print(frame.f_code)

Now it’s simply a matter of setting it as our trace callback:

现在只需将其设置为我们的跟踪回调即可:

sys.settrace(trace_calls)

And executing sample(3,2) should produce

执行sample(3,2)应该产生

$ python debugger.py
<code object sample at 0x0000000000B46C90, file “.\test.py”, line 123>
Sample: 10

You need the if-statement to filter out function calls. Otherwise you’ll see a whole bunch of things that you don’t care about, especially when printing to the screen. Try it.

您需要使用if语句来过滤掉函数调用。 否则,您会看到一堆不需要的东西,特别是在屏幕上打印时。 试试吧。

The code and frame objects have quite a few fields to describe what they represent. These include things like the file being executed, the function, variable names, arguments, line numbers, and the list goes on. They are fundamental to the execution of any python code and you can go through the language documentation for more details.

代码和框架对象有很多字段来描述它们所代表的内容。 这些包括正在执行的文件,函数,变量名,参数,行号以及列表等内容。 它们是执行任何python代码的基础,您可以阅读语言文档以获取更多详细信息。

如果要调试每一行怎么办? (What if you want to debug every line?)

The trace mechanism will set subsequent callbacks depending on the return value of the first callback. Returning None means that you’re finished, while returning another function effectively sets it as the trace function inside that frame.

跟踪机制将根据第一个回调的返回值设置后续的回调。 返回None表示您已经完成,而返回另一个函数实际上将其设置为该帧内的trace函数。

Here’s what this looks like:

看起来是这样的:

5    def sample(a, b):
6        x = a + b
7        y = x * 2
8        print('Sample: ' + str(y))
9
10   def trace_calls(frame, event, arg):
11       if frame.f_code.co_name == "sample":
12           print(frame.f_code)
13           return trace_lines
14       return
15
16   def trace_lines(frame, event, arg):
17       print(frame.f_lineno)

Now, if you execute the same code as before, you can see it print the line numbers as you progress through it:

现在,如果您执行与以前相同的代码,则可以看到它在执行过程中打印行号:

$ python .\test.py
<code object sample at 0x00000000006D4DB0, file ".\test.py", line 5>
6
7
8
Sample: 10
8

将用户界面置于其前面 (Putting a user interface in front of it)

Using the sofi python module, you can easily produce a web application that directly interacts with our python code.

使用sofi python模块,您可以轻松地生成一个直接与我们的python代码进行交互的Web应用程序。

Here’s what you would do:

这是您要执行的操作:

  1. Show the file, function name and line number being executed.

    显示正在执行的文件,函数名称和行号。
  2. Show the code for the current frame with a pointer identifying the line.

    用标识行的指针显示当前帧的代码。
  3. Show the value of the local variables.

    显示局部变量的值。
  4. Provide step-by-step execution, meaning you have to block before executing a line until the user clicks a button.

    提供分步执行,这意味着您必须在执行一行之前阻塞,直到用户单击按钮为止。
  5. Add step-over functionality.

    添加跨步功能。
  6. Add a step-out mechanism.

    添加一个跳出机制。
  7. Provide a method of stopping execution.

    提供一种停止执行的方法。

From the UI perspective, #1, #2 and #3 can all be handled through a Bootstrap Panel where #1 is the title, and #2 and #3 are part of the body wrapped in samp tags to show proper spacing.

从UI角度来看,#1,#2和#3都可以通过Bootstrap 面板进行处理,其中#1是标题,而#2和#3是包裹在samp标签中的主体的一部分,以显示适当的间距。

Since the interface will essentially block waiting for user input, and the debugger waits for stop / go commands, it’s a good idea to separate those event loops using our old friend multiprocessing. You can then implement one queue to send debug commands to one process, and a different application queue for UI updates in the other.

由于该接口实际上将阻止等待用户输入,而调试器将等待stop / go命令,因此,最好使用我们的老朋友multiprocessing分离这些事件循环。 然后,您可以实现一个队列以将调试命令发送到一个进程,而在另一个队列中实现另一个用于UI更新的应用程序队列。

Through multiprocessing queues, it’s easy to block the debugger waiting for user commands at the trace_lines function using the .get() method.

通过多处理队列,使用.get()方法很容易在trace_lines函数中阻止调试器等待用户命令。

If the command is given to move to the next line of code (#4), everything stays the same, while stepping out (#6) will change the return value back to the trace_calls function — effectively removing further calls into trace_lines — and stop (#7) will raise a custom exception that will abort execution.

如果给出命令以移至下一行代码(#4),则所有内容均保持不变,而退出(#6)会将返回值更改回trace_calls函数-有效地将更多调用删除到trace_lines中并停止(#7)将引发一个自定义异常,该异常将中止执行。

# Block until you receive a debug command
cmd = trace_lines.debugq.get()
if cmd == 'step':# continue stepping through lines, return this callbackreturn trace_lines
elif cmd == 'stop':# Stop executionraise StopExecution()
elif cmd == 'over':# step out or over code, so point to trace_callsreturn trace_calls
class StopExecution(Exception):"""Custom exception used to abort code execution"""pass

Step-over functionality (#5) is implemented at the trace_calls level by never returning the trace_lines callback.

通过从不返回trace_lines回调,在trace_calls级别实现了跨步功能(#5)。

cmd = trace_lines.debugq.get()
if cmd == 'step':return trace_lines
elif cmd == 'over':return

Yes, I attached the queue objects as properties of the trace functions to simplify passing things around. Functions being objects is a great idea, though you shouldn’t abuse it either.

是的,我将队列对象附加为跟踪功能的属性,以简化传递过程。 将函数作为对象是一个好主意,尽管您也不应滥用它。

Now it’s just a matter of setting up the widgets for displaying data and the buttons for controlling flow.

现在只需设置用于显示数据的小部件和用于控制流的按钮即可。

You can pull out the source code from the code object of the executing frame using the inspect module.

您可以使用检查模块从执行框架的代码对象中提取源代码。

source = inspect.getsourcelines(frame.f_code)[0]

Now it’s a matter of formatting it line by line into div and samp tags, adding an indicator of a different color to the current line (available through f_lineno and co_firstline) and sticking that into a panel widget’s body, along with the string representation of the frame’s locals (which is a simple dictionary anyway):

现在,只需将其逐行格式化为divsamp标签,即可在当前行中添加其他颜色的指示器(可通过f_lineno co_firstline ),并将其与框架本地语言的字符串表示形式(无论如何都是简单的字典)粘贴到面板小部件的主体中:

def formatsource(source, firstline, currentline):for index, item  in enumerate(source):# Create a div for each line to better control formatdiv = Div()# Extremly simplified tab index check to add blank spaceif item[0:1] == '\t' or item[0:1] == ' ':div.style ='margin-left:15px;'# If this currently executing this line, add a red markif index == lineno - firstlineno:div.addelement(Bold('> ', style="color:red"))# Add the formatted code to the divdiv.addelement(Sample(item.replace("\n", "")))# Output the html that represents that divsource[index] = str(div)return "".join(source)

Only thing left to do is register a few event callbacks for button clicks that control execution flow by adding their respective commands to the debug queue. You do this inside a load event handler which triggers after the initial content finishes loading

剩下要做的就是为按钮单击注册一些事件回调,通过将它们各自的命令添加到调试队列中来控制执行流程。 您可以在加载事件处理程序中执行此操作,该处理程序将在初始内容完成加载后触发

@asyncio.coroutine
def load(event):"""Called when the initial html finishes loading"""# Start the debug processdebugprocess.start()# Register click functionsapp.register('click', step, selector="#code-next-button")app.register('click', stop, selector="#code-stop-button")app.register('click', over, selector="#code-over-button")# Make sure the display updatesyield from display()
@asyncio.coroutine
def step(event):debugq.put("step")# Make sure the display updatesyield from display()
@asyncio.coroutine
def stop(event):debugq.put("stop")
@asyncio.coroutine
def over(event):debugq.put("over")

How would this look?

看起来如何?

For a view of all of the code put together, check out the sofi-debugger project on GitHub:

要查看放在一起的所有代码,请查看GitHub上的sofi-debugger项目:

tryexceptpass/sofi-debuggerContribute to sofi-debugger development by creating an account on GitHub.github.com

tryexceptpass / sofi-debugger 通过在GitHub上创建一个帐户来促进sofi-debugger的开发。 github.com

关于您刚刚所做的一些注意事项 (Some notes on what you just did)

The functions from the sys module mentioned here are implemented in CPython and may not be available in other flavors or interpreters. Make sure to keep this in mind when experimenting.

此处提到的sys模块中的函数是在CPython中实现的,可能无法在其他版本或解释器中使用。 实验时请务必牢记这一点。

They are also specifically meant for use with debuggers, profilers or similar trace tools. This means that you should not be messing with them as part of a normal program or you may come across some unintended consequences, especially when interacting with other modules that may specifically target these same interfaces (like actual debuggers).

它们也专门用于调试器,事件探查器或类似的跟踪工具。 这意味着您不应该在常规程序中将它们弄乱,否则可能会遇到意想不到的后果,尤其是在与其他可能专门针对这些相同接口的模块进行交互时(例如实际的调试器)。

深潜 (Diving Deeper)

For a deeper dive into the Python language constructs, frames, code objects and the dis module, I emphatically recommend that you set aside some time and go through Phillip Guo’s (@pgbovine) CPython Internals lectures.

为了更深入地了解Python语言的结构,框架,代码对象和dis模块,我强烈建议您花一些时间,并通过Phillip Guo(@pgbovine)的CPython Internals讲座。



If you liked the article and want to read more about Python and software practices, please visit tryexceptpass.org. Stay informed with their latest content by subscribing to the mailing list.

如果您喜欢这篇文章,并想了解有关Python和软件实践的更多信息,请访问tryexceptpass.org 。 订阅邮件列表,随时了解其最新内容。

翻译自: https://www.freecodecamp.org/news/hacking-together-a-simple-graphical-python-debugger-efe7e6b1f9a8/

相关文章:

python 之路,Day11 (下)- sqlalchemy ORM

python 之路&#xff0c;Day11 - sqlalchemy ORM 本节内容 ORM介绍sqlalchemy安装sqlalchemy基本使用多外键关联多对多关系表结构设计作业1. ORM介绍 orm英文全称object relational mapping,就是对象映射关系程序&#xff0c;简单来说我们类似python这种面向对象的程序来说一切…

iOS事件响应链

1 如下 NSObject 显然是基类&#xff0c;都是继承与UIResponder. 可以看出UIApplication&#xff0c;UIView&#xff0c;UIViewController都是继承自UIResponder类&#xff0c;可以响应和处理事件 我们都是通过UIResonder 来查找控件的父视图控件。’ 发生触摸事件之后&…

论5级流水32bit risc cpu设计

前段时间用verilog写了一个32bit的risc cpu,五级流水&#xff0c;下板调试已经完全可用&#xff0c;准备后期加入浮点运算器&#xff0c;因为最近事情超级多&#xff0c;因此暂时先把RTL图传上来供大家参考&#xff0c;后面我会讲具体怎么设计。希望大家多多关注 :)转载于:http…

开源项目贡献者_嘿新手开源贡献者:请写博客。

开源项目贡献者by Shubheksha通过Shubheksha 嘿新手开源贡献者&#xff1a;请写博客。 (Hey newbie open source contributors: please blog more.) As a newbie open source contributor, I often felt lost and dejected. I couldn’t figure out how different modules fit…

instanceof, isinstance,isAssignableFrom的区别

instanceof运算符 只被用于对象引用变量&#xff0c;检查左边的被测试对象 是不是 右边类或接口的 实例化。如果被测对象是null值&#xff0c;则测试结果总是false。 形象地&#xff1a;自身实例或子类实例 instanceof 自身类 返回true 例&#xff1a; String snew String(&qu…

POJ - 3538 - Domestic Networks

先上题目&#xff1a; Domestic NetworksTime Limit: 2000MS Memory Limit: 65536KTotal Submissions: 732 Accepted: 204 Special JudgeDescription Alex is a system administrator of Domestic Networks Inc. His network connects apartments and spans over multiple buil…

iOS HitTest 机制

当用户触摸&#xff08;Touch&#xff09;屏幕进行交互时&#xff0c;系统首先要找到响应者&#xff08;Responder&#xff09;。系统检测到手指触摸&#xff08;Touch&#xff09;操作的时候&#xff0c;将Touch 以UIEvent 的方式加入到UIApplication 事件队列中去。UIApplica…

巨石加密_缓解巨石

巨石加密by Ian Belcher伊恩贝尔彻(Ian Belcher) 我们如何将技术堆栈转向基于服务&#xff0c;以开发人员体验为中心的设计 (How we pivoted our tech stack to a service-based, developer experience-focused design) This article documents the problems we experienced w…

Python函数中的参数(一)

函数传递参数时的简要关键点&#xff1a; 1、参数的传递是通过自动将对象赋值给本地变量名来实现的。函数参数在实际中只是Python赋值的一个实例。因为引用是以指针的形式实现的&#xff0c;所有的参数实际上都是通过指针进行传递的。 2、在函数内部的参数名的赋值不会影响调用…

LLDB 调试相关

LLDB 初始 LLDB 是一个有着 REPL 的特性和 C ,Python 插件的开源调试器。LLDB 绑定在 Xcode 内部&#xff0c;存在于主窗口底部的控制台中。调试器允许你在程序运行的特定时暂停它&#xff0c;你可以查看变量的值&#xff0c;执行自定的指令&#xff0c;并且按照你所认为合适的…

javascript优缺点_为什么要在JavaScript中使用静态类型? 优缺点

javascript优缺点by Preethi Kasireddy通过Preethi Kasireddy 为什么要在JavaScript中使用静态类型&#xff1f; 优缺点 (Why use static types in JavaScript? The Advantages and Disadvantages) We covered a lot of ground in Part 1! With syntax out of the way, let’…

大数的减法函数--c语言

代码展示&#xff1a; http://paste.ubuntu.com/23693598/ #include<stdio.h> #include<stdlib.h> #include<string.h> char * largeDiffer(char *a,char *b){ /* 使用说明 传入的a和b只能为整数 结果为a-b;返回的为字符指针&#xff0c;注意数组不要越…

json 基础

json格式 JSON格式&#xff1a;http://www.json.org/ python和JSON的关系请参考&#xff1a;http://docs.python.org/library/json.html JSON建构有两种结构&#xff1a; 1. “名称/值”对的集合&#xff08;A collection of name/value pairs&#xff09;。不同的语言中&#…

iOS 中 load 和 initialize的实现顺序

1 load 函数 调用时机&#xff0c;当类引用进项目的时候执行load函数&#xff0c;在main函数开始之前&#xff0c;与 这个类是否被用到是无关的&#xff0c;每个类的load函数都会自动调用一次。 1 父类和子类都实现load函数的时候&#xff0c;父类的load方法优先于子类 2 类…

需求简报_代码简报:有史以来最怪诞的丑毛衣

需求简报Here are three stories we published this week that are worth your time:这是我们本周发布的三个值得您关注的故事&#xff1a; The geekiest ugly sweater ever: 4 minute read 有史以来最怪异的丑毛衣&#xff1a; 4分钟阅读 Lessons from my post-bootcamp job …

C#内置函数 RunSql的使用

作用批量执行sql语句表达式.RunSQL(SQLStatement,UseTransaction)表达式.一个代表DoCmd对象的变量。注释&#xff1a;sqlstatement参数的最大长度为 32,768 个字符&#xff08;而"宏"窗口中的 SQL 语句操作参数的最大长度为 256 个字符&#xff09;。 官方说仅能用于…

swif 在字符串中查找特定字符索引以及改变字符串的指定位置的颜色 字体大小

1 第一种方式 var text "谁包含这个字母";let range:Range<String.Index> text.range(of: "含")!;let end_idx:Int text.distance(from: text.startIndex, to: range.lowerBound);// 打印2print(end_idx);类方法 抽取 // 查找对应索引static func…

SD卡的控制方法(指令集和控制时序)

1.SD卡的命令格式&#xff1a; SD卡的指令由6字节(Byte)组成&#xff0c;如下&#xff1a; Byte1&#xff1a;0 1 x x x x x x(命令号&#xff0c;由指令标志定义&#xff0c;如CMD39为100111即16进制0x27&#xff0c;那么完整的CMD39第一字节为01100111&#xff0c;即0x270x40…

javascript 代码_代码简介:2016年JavaScript的现状

javascript 代码Here are three stories we published this week that are worth your time:这是我们本周发布的三个值得您关注的故事&#xff1a; The state of JavaScript in 2016: 5 minute read 2016年JavaScript状况&#xff1a; 阅读5分钟 Upgrading to macOS Sierra wi…

Unity协程截图,WWWForm、WWW配合上传

先说一下原理。。 截图有两种方法&#xff0c;第一种&#xff1a; Application.CaptureScreenshot(url); 这个API可以截全屏并保存到指定路径 这里我们不采用此方法 下面的代码采用第二种方法&#xff0c;自己建一个Texture2D 这种方法灵活&#xff0c;操作性更高 WWWForm方法是…

OC 的反射机制以及使用场景

OC 的反射机制 一 定义概念 普遍的概念就是类似于java的反射机制&#xff0c;动态机制使得OC语言更加灵活。 反射机制就是可以根据指定的类名获取类的相关信息。 二 作用 1 根据类名获得class // 选择器 和字符串之间的相互转化 FOUNDATION_EXPORT NSString *NSStringFr…

centos 网卡聚合及Cisco交换机链路聚合

一、配置环境 centos 系统。网卡1口和2口做链路聚合。 交换机网口 6口和7口。 二、服务器操作步骤 centos 6 1.创建一个channel bonding interface #vi /etc/sysconfig/network-scripts/ifcfg-bond0 添加如下几行&#xff1a; GATEWAY192.168.10.1 DNS1202.106.0.20 DEVICEb…

graphql redux_如何在Redux应用程序中使用GraphQL

graphql reduxby Howon Song通过宋颂恩 如何在Redux应用程序中使用GraphQL (How to use GraphQL in your Redux app) Fetching and managing data in Redux requires too much work. As Sashko Stubailo points out:在Redux中获取和管理数据需要太多的工作。 正如Sashko Stuba…

原创:去繁存简,回归本源:微信小程序公开课信息分析《一》

以前我开过一些帖子&#xff0c;我们内部也做过一些讨论&#xff0c;我们从张小龙的碎屏图中 &#xff0c;发现了重要讯息&#xff1a; 1&#xff1a;微信支付将成为重要场景&#xff1b; 2&#xff1a;这些应用与春节关系不小&#xff0c;很多应用在春节时&#xff0c;有重要的…

ubuntu 14.0 下github 配置

一&#xff1a;创建Repositories 1:首先在github下创建一个帐号。这个不用多说&#xff0c;然后创建一个Repositories。 2:然后在ubuntu下安装git相关的东东&#xff1a; 1sudo apt-get install git-core git-gui git-doc -y 3:在ubuntu本地创建一个ssh密匙&#xff1a; 1ssh-k…

OC 消息转发实现多继承

消息转发实现多继承 在OC 中&#xff0c;一个类只支持单继承&#xff0c;但是可以通过别的手段实现多继承。 利用消息转发实现多继承。 在OC 中&#xff0c;对象调用方法实际是在发消息&#xff0c;对象接收到一条消息的时候&#xff0c;消息函数随着对象的isa 指针到自己的…

chatscript_如何使用ChatScript构建您的第一个聊天机器人

chatscriptby Giorgio Robino通过乔治罗宾诺(Giorgio Robino) 如何使用ChatScript构建您的第一个聊天机器人 (How to build your first chatbot using ChatScript) 10–10–2018: article updated with new github repo url.2018年10月10日&#xff1a;文章更新为新的github r…

web安全浅析

就之前本人主持开发的金融产品所遇到的安全问题&#xff0c;设计部分请参见&#xff1a;http://www.cnblogs.com/shenliang123/p/3835072.html 这里就部分web安全防护就简单的交流&#xff1a; 1.1系统安全 1.1.1 客户端脚本安全 &#xff08;1&#xff09;跨站脚本攻击&#…

HDU 1556 Color the ball

题解&#xff1a;基础的树状数组区间修改&#xff0c;单点查询。 #include <cstdio> #include <cstring> int c[100005],a,b,n; int modify(int x,int num){while(x<n)c[x]num,xx&-x;} int query(int x){int s0;while(x>0)sc[x],x-x&-x;return s;} …

OC协议实现多继承

协议实现多继承 协议实现多继承的话&#xff0c;只是简答的提供了接口&#xff0c;并灭有提供实现的方式。 A #import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGINprotocol StuAProtocal <NSObject>// 学生A 会游泳 - (void)swimming;endinterface Stude…