标签归档:java

相当于e.printStackTrace的python

问题:相当于e.printStackTrace的python

我知道print(e)(其中e是一个异常)会打印发生的异常,但是,我试图找到与Java等效的python,e.printStackTrace()它可以将异常确切地跟踪到发生的那一行,并打印出整个轨迹。

谁能告诉我e.printStackTrace()Python 的等效功能吗?

I know that print(e) (where e is an Exception) prints the occurred exception but, I was trying to find the python equivalent of Java’s e.printStackTrace() that exactly traces the exception to what line it occurred and prints the entire trace of it.

Could anyone please tell me the equivalent of e.printStackTrace() in Python?


回答 0

import traceback
traceback.print_exc()

在一个except ...:块内执行此操作时,它将自动使用当前异常。有关更多信息,请参见http://docs.python.org/library/traceback.html

import traceback
traceback.print_exc()

When doing this inside an except ...: block it will automatically use the current exception. See http://docs.python.org/library/traceback.html for more information.


回答 1

也有logging.exception

import logging

...

try:
    g()
except Exception as ex:
    logging.exception("Something awful happened!")
    # will print this message followed by traceback

输出:

ERROR 2007-09-18 23:30:19,913 error 1294 Something awful happened!
Traceback (most recent call last):
  File "b.py", line 22, in f
    g()
  File "b.py", line 14, in g
    1/0
ZeroDivisionError: integer division or modulo by zero

(摘自http://blog.tplus1.com/index.php/2007/09/28/the-python-logging-module-is-much-better-than-print-statements/通过如何打印完整的回溯而无需暂停程序?

There is also logging.exception.

import logging

...

try:
    g()
except Exception as ex:
    logging.exception("Something awful happened!")
    # will print this message followed by traceback

Output:

ERROR 2007-09-18 23:30:19,913 error 1294 Something awful happened!
Traceback (most recent call last):
  File "b.py", line 22, in f
    g()
  File "b.py", line 14, in g
    1/0
ZeroDivisionError: integer division or modulo by zero

(From http://blog.tplus1.com/index.php/2007/09/28/the-python-logging-module-is-much-better-than-print-statements/ via How to print the full traceback without halting the program?)


回答 2

相当于e.printStackTrace的python

在Java中,这将执行以下操作(docs):

public void printStackTrace()

将这个throwable及其回溯打印到标准错误流中。

这样使用:

try
{ 
// code that may raise an error
}
catch (IOException e)
{
// exception handling
e.printStackTrace();
}

在Java中,标准错误流没有缓冲,因此输出立即到达。

Python 2中的相同语义是:

import traceback
import sys
try: # code that may raise an error
    pass 
except IOError as e: # exception handling
    # in Python 2, stderr is also unbuffered
    print >> sys.stderr, traceback.format_exc()
    # in Python 2, you can also from __future__ import print_function
    print(traceback.format_exc(), file=sys.stderr)
    # or as the top answer here demonstrates, use:
    traceback.print_exc()
    # which also uses stderr.

Python 3

在Python 3中,我们可以直接从异常对象获取回溯(对于线程代码,其行为可能更好)。另外,stderr是行缓冲的,但是print函数获取flush参数,因此可以立即将其打印到stderr:

    print(traceback.format_exception(None, # <- type(e) by docs, but ignored 
                                     e, e.__traceback__),
          file=sys.stderr, flush=True)

结论:

因此,在Python 3中,traceback.print_exc()尽管sys.stderr 默认使用,但会缓冲输出,您可能会丢失它。因此,为了获得尽可能相等的语义,请在Python 3中print与一起使用flush=True

e.printStackTrace equivalent in python

In Java, this does the following (docs):

public void printStackTrace()

Prints this throwable and its backtrace to the standard error stream…

This is used like this:

try
{ 
// code that may raise an error
}
catch (IOException e)
{
// exception handling
e.printStackTrace();
}

In Java, the Standard Error stream is unbuffered so that output arrives immediately.

The same semantics in Python 2 are:

import traceback
import sys
try: # code that may raise an error
    pass 
except IOError as e: # exception handling
    # in Python 2, stderr is also unbuffered
    print >> sys.stderr, traceback.format_exc()
    # in Python 2, you can also from __future__ import print_function
    print(traceback.format_exc(), file=sys.stderr)
    # or as the top answer here demonstrates, use:
    traceback.print_exc()
    # which also uses stderr.

Python 3

In Python 3, we can get the traceback directly from the exception object (which likely behaves better for threaded code). Also, stderr is line-buffered, but the print function gets a flush argument, so this would be immediately printed to stderr:

    print(traceback.format_exception(None, # <- type(e) by docs, but ignored 
                                     e, e.__traceback__),
          file=sys.stderr, flush=True)

Conclusion:

In Python 3, therefore, traceback.print_exc(), although it uses sys.stderr by default, would buffer the output, and you may possibly lose it. So to get as equivalent semantics as possible, in Python 3, use print with flush=True.


回答 3

添加到其他伟大的答案,我们可以使用Python logging库的debug()info()warning()error(),和critical()方法。引用Python 3.7.4的文档,

在kwargs中检查了三个关键字参数:exc_info,如果不将其评估为false,则会将异常信息添加到日志消息中。

这意味着,您可以使用Python logging库输出debug()或其他类型的消息,并且该logging库将在其输出中包括堆栈跟踪。考虑到这一点,我们可以执行以下操作:

import logging

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

def f():
    a = { 'foo': None }
    # the following line will raise KeyError
    b = a['bar']

def g():
    f()

try:
    g()
except Exception as e:
    logger.error(str(e), exc_info=True)

它将输出:

'bar'
Traceback (most recent call last):
  File "<ipython-input-2-8ae09e08766b>", line 18, in <module>
    g()
  File "<ipython-input-2-8ae09e08766b>", line 14, in g
    f()
  File "<ipython-input-2-8ae09e08766b>", line 10, in f
    b = a['bar']
KeyError: 'bar'

Adding to the other great answers, we can use the Python logging library’s debug(), info(), warning(), error(), and critical() methods. Quoting from the docs for Python 3.7.4,

There are three keyword arguments in kwargs which are inspected: exc_info which, if it does not evaluate as false, causes exception information to be added to the logging message.

What this means is, you can use the Python logging library to output a debug(), or other type of message, and the logging library will include the stack trace in its output. With this in mind, we can do the following:

import logging

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

def f():
    a = { 'foo': None }
    # the following line will raise KeyError
    b = a['bar']

def g():
    f()

try:
    g()
except Exception as e:
    logger.error(str(e), exc_info=True)

And it will output:

'bar'
Traceback (most recent call last):
  File "<ipython-input-2-8ae09e08766b>", line 18, in <module>
    g()
  File "<ipython-input-2-8ae09e08766b>", line 14, in g
    f()
  File "<ipython-input-2-8ae09e08766b>", line 10, in f
    b = a['bar']
KeyError: 'bar'

Java“虚拟机”与Python“解释器”的用语?

问题:Java“虚拟机”与Python“解释器”的用语?

在Java中始终使用“虚拟机”时,很少会读到Python“虚拟机”。

两者都解释字节码;为什么一个叫虚拟机,另一个叫解释器?

It seems rare to read of a Python “virtual machine” while in Java “virtual machine” is used all the time.

Both interpret byte codes; why call one a virtual machine and the other an interpreter?


回答 0

虚拟机是一种虚拟计算环境,具有一组特定的原子定义良好的指令,这些指令独立于任何特定语言而受到支持,通常将其视为自身的沙箱。VM与特定CPU的指令集相似,并且趋向于在更基本的级别上使用与下一条指令无关的此类指令(或字节码)的非常基本的构建块。指令仅基于虚拟机的当前状态确定性地执行,而不依赖于该时间点上指令流中其他位置的信息。

另一方面,解释器则更为复杂,因为它经过精心设计以解析某种语法流,该流必须是特定语言和特定语法的流,这些流必须在周围标记的上下文中进行解码。您无法孤立地查看每个字节甚至每一行,而确切地知道下一步该做什么。语言中的令牌不能像虚拟机的指令(字节码)那样孤立地获取。

Java编译器将Java语言转换为字节码流,这与C编译器将C语言程序转换为汇编代码无异。另一方面,解释器并没有真正将程序转换为任何定义良好的中间形式,它只是将程序操作作为解释源代码的过程。

对VM和解释器之间差异的另一项测试是,您是否认为它与语言无关。我们所知道的Java VM并不是真的特定于Java。您可以使用其他语言制作编译器,从而产生可以在JVM上运行的字节码。另一方面,我认为我们真的不会考虑将除Python以外的其他语言“编译”为Python以便由Python解释器解释。

由于解释过程的复杂性,这可能是一个相对缓慢的过程……特别是解析和标识语言标记等,并理解源的上下文以能够在解释器中进行执行过程。为了帮助加速此类解释语言,我们可以在此处定义更容易直接解释的预解析,预标记化源代码的中间形式。这种二进制形式仍在执行时进行解释,它只是从一种人类可读性差的形式开始,以提高性能。但是,执行该形式的逻辑不是虚拟机,因为仍然不能孤立地获取这些代码-周围令牌的上下文仍然很重要,它们现在处于另一种计算机效率更高的形式。

A virtual machine is a virtual computing environment with a specific set of atomic well defined instructions that are supported independent of any specific language and it is generally thought of as a sandbox unto itself. The VM is analogous to an instruction set of a specific CPU and tends to work at a more fundamental level with very basic building blocks of such instructions (or byte codes) that are independent of the next. An instruction executes deterministically based only on the current state of the virtual machine and does not depend on information elsewhere in the instruction stream at that point in time.

An interpreter on the other hand is more sophisticated in that it is tailored to parse a stream of some syntax that is of a specific language and of a specific grammer that must be decoded in the context of the surrounding tokens. You can’t look at each byte or even each line in isolation and know exactly what to do next. The tokens in the language can’t be taken in isolation like they can relative to the instructions (byte codes) of a VM.

A Java compiler converts Java language into a byte-code stream no different than a C compiler converts C Language programs into assembly code. An interpreter on the other hand doesn’t really convert the program into any well defined intermediate form, it just takes the program actions as a matter of the process of interpreting the source.

Another test of the difference between a VM and an interpreter is whether you think of it as being language independent. What we know as the Java VM is not really Java specific. You could make a compiler from other languages that result in byte codes that can be run on the JVM. On the other hand, I don’t think we would really think of “compiling” some other language other than Python into Python for interpretation by the Python interpreter.

Because of the sophistication of the interpretation process, this can be a relatively slow process….specifically parsing and identifying the language tokens, etc. and understanding the context of the source to be able to undertake the execution process within the interpreter. To help accelerate such interpreted languages, this is where we can define intermediate forms of pre-parsed, pre-tokenized source code that is more readily directly interpreted. This sort of binary form is still interpreted at execution time, it is just starting from a much less human readable form to improve performance. However, the logic executing that form is not a virtual machine, because those codes still can’t be taken in isolation – the context of the surrounding tokens still matter, they are just now in a different more computer efficient form.


回答 1

在这篇文章中,“虚拟机”是指进程虚拟机,而不是诸如Qemu或Virtualbox之类的系统虚拟机。流程虚拟机只是提供一般编程环境的程序-可以编程的程序。

Java具有解释器和虚拟机,而Python具有虚拟器和解释器。“虚拟机”是Java中更常见的术语,而“解释器”是Python中更常见的术语的原因与两种语言之间的主要差异有很大关系:静态类型(Java)与动态类型(Python)。在这种情况下,“类型”是指 原始数据类型 -这些类型建议数据在内存中的存储大小。Java虚拟机很容易。它要求程序员指定每个变量的原始数据类型。这为Java字节码提供了足够的信息,不仅可以由Java虚拟机解释和执行,甚至可以编译成机器指令。从某种意义上说,Python虚拟机更为复杂,因为它承担着在执行每个操作之前暂停的额外任务,以确定该操作涉及的每个变量或数据结构的原始数据类型。Python使程序员摆脱了对原始数据类型的思考,并允许在更高层次上表达操作。这种自由的代价是性能。“解释器”是Python的首选术语,因为它必须暂停以检查数据类型,并且因为动态类型语言的语法相对简洁,非常适合交互式界面。构建交互式Java接口没有技术上的障碍,但是尝试以交互方式编写任何静态类型的代码将很繁琐,因此并不能做到这一点。

在Java世界中,虚拟机抢占了舞台,因为它运行以某种语言编写的程序,这些程序实际上可以编译成机器指令,从而提高了速度和资源效率。相对而言,Java字节码可以由Java虚拟机执行,其性能接近已编译程序的性能。这是由于字节码中存在原始数据类型信息。Java虚拟机将Java归为自己的类别:

便携式解释静态类型语言

下一个最接近的是LLVM,但是LLVM在不同的级别上运行:

便携式解释汇编语言

Java和Python都使用了术语“字节码”,但是并非所有字节码都是一样的。字节码只是编译器/解释器使用的中间语言的通用术语。甚至gcc之类的C编译器都使用一种或多种中间语言来完成工作。Java字节码包含有关原始数据类型的信息,而Python字节码则不包含。在这方面,Python(以及Bash,Perl,Ruby等)虚拟机从根本上说比Java虚拟机要慢,或者说,它要做的工作更多。考虑不同字节码格式中包含哪些信息是很有用的:

  • llvm: cpu寄存器
  • Java:原始数据类型
  • Python:用户定义的类型

进行现实世界的类比:LLVM使用原子,Java虚拟机使用分子,Python虚拟机使用材料。由于一切最终都必须分解为亚原子粒子(真实机器操作),因此Python虚拟机具有最复杂的任务。

静态类型语言的解释器/编译器与动态类型语言的解释器/编译器所拥有的负担不同。静态类型的语言的程序员必须承担懈怠的工作,为此付出的代价是性能。但是,就像所有非确定性函数都是秘密确定性的一样,所有动态类型的语言也都是秘密静态类型的。因此,在Python将其名称更改为HAL 9000的同时,两种语言系列之间的性能差异应趋于平稳。

像Python这样的动态语言的虚拟机实现了一些理想化的逻辑机,并且不一定与任何实际的物理硬件都非常接近。相比之下,Java虚拟机在功能上与经典的C编译器更为相似,不同之处在于,它不发出机器指令,而是执行内置例程。在Python中,整数是一个Python对象,具有一系列附加的属性和方法。在Java中,int是指定的位数,通常为32。这并不是一个公平的比较。确实应该将Python整数与Java Integer类进行比较。Java的“ int”基元数据类型无法与Python语言中的任何事物进行比较,因为Python语言只是缺少这一层基元,Python字节码也是如此。

因为Java变量是显式类型的,所以可以合理地期望Jython性能之类的东西与cPython处于同一 水平。另一方面,几乎可以肯定,用Python实现的Java虚拟机的速度要比泥浆慢。而且不要指望Ruby,Perl等会有更好的表现。他们并非旨在这样做。它们是为“脚本编写”而设计的,这就是所谓的动态语言编程。

虚拟机中发生的每个操作最终都必须使用实际硬件。虚拟机包含预编译的例程,这些例程足够通用以执行逻辑操作的任何组合。虚拟机可能不会发出新的机器指令,但是虚拟机肯定正在以复杂的顺序一遍又一遍地执行自己的例程。Java虚拟机,Python虚拟机以及所有其他通用虚拟机在意义上是相同的,它们可以被诱使执行您可以梦想的任何逻辑,但是它们在执行哪些任务方面有所不同承担什么,他们留给程序员什么任务。

Psyco for Python并不是一个完整的Python虚拟机,而是一个即时编译器,它在认为可以编译几行代码的点上劫持了常规的Python虚拟机,主要是在它认为某些原始类型的地方循环即使值在每次迭代中都在变化,变量也将保持不变。在这种情况下,它可以放弃常规虚拟机的某些不可靠的类型确定。但是,您必须小心一点,以免将其从Psyco的脚下拉出来。但是,Pysco通常知道,如果不能完全确定类型不会更改,则只能使用常规虚拟机。

这个故事的寓意是原始数据类型信息确实对编译器/虚拟机有帮助。

最后,从所有角度来看,请考虑一下:由Python解释器/虚拟机执行的Python程序,该Java解释器/虚拟机在LLVM中运行的Java解释器/虚拟机在iPhone上运行的qemu虚拟机中运行。

永久链接

In this post, “virtual machine” refers to process virtual machines, not to system virtual machines like Qemu or Virtualbox. A process virtual machine is simply a program which provides a general programming environment — a program which can be programmed.

Java has an interpreter as well as a virtual machine, and Python has a virtual machine as well as an interpreter. The reason “virtual machine” is a more common term in Java and “interpreter” is a more common term in Python has a lot to do with the major difference between the two languages: static typing (Java) vs dynamic typing (Python). In this context, “type” refers to primitive data types — types which suggest the in-memory storage size of the data. The Java virtual machine has it easy. It requires the programmer to specify the primitive data type of each variable. This provides sufficient information for Java bytecode not only to be interpreted and executed by the Java virtual machine, but even to be compiled into machine instructions. The Python virtual machine is more complex in the sense that it takes on the additional task of pausing before the execution of each operation to determine the primitive data types for each variable or data structure involved in the operation. Python frees the programmer from thinking in terms of primitive data types, and allows operations to be expressed at a higher level. The price of this freedom is performance. “Interpreter” is the preferred term for Python because it has to pause to inspect data types, and also because the comparatively concise syntax of dynamically-typed languages is a good fit for interactive interfaces. There’s no technical barrier to building an interactive Java interface, but trying to write any statically-typed code interactively would be tedious, so it just isn’t done that way.

In the Java world, the virtual machine steals the show because it runs programs written in a language which can actually be compiled into machine instructions, and the result is speed and resource efficiency. Java bytecode can be executed by the Java virtual machine with performance approaching that of compiled programs, relatively speaking. This is due to the presence of primitive data type information in the bytecode. The Java virtual machine puts Java in a category of its own:

portable interpreted statically-typed language

The next closest thing is LLVM, but LLVM operates at a different level:

portable interpreted assembly language

The term “bytecode” is used in both Java and Python, but not all bytecode is created equal. bytecode is just the generic term for intermediate languages used by compilers/interpreters. Even C compilers like gcc use an intermediate language (or several) to get the job done. Java bytecode contains information about primitive data types, whereas Python bytecode does not. In this respect, the Python (and Bash,Perl,Ruby, etc.) virtual machine truly is fundamentally slower than the Java virtual machine, or rather, it simply has more work to do. It is useful to consider what information is contained in different bytecode formats:

  • llvm: cpu registers
  • Java: primitive data types
  • Python: user-defined types

To draw a real-world analogy: LLVM works with atoms, the Java virtual machine works with molecules, and The Python virtual machine works with materials. Since everything must eventually decompose into subatomic particles (real machine operations), the Python virtual machine has the most complex task.

Intepreters/compilers of statically-typed languages just don’t have the same baggage that interpreters/compilers of dynamically-typed languages have. Programmers of statically-typed languages have to take up the slack, for which the payoff is performance. However, just as all nondeterministic functions are secretly deterministic, so are all dynamically-typed languages secretly statically-typed. Performance differences between the two language families should therefore level out around the time Python changes its name to HAL 9000.

The virtual machines of dynamic languages like Python implement some idealized logical machine, and don’t necessarily correspond very closely to any real physical hardware. The Java virtual machine, in contrast, is more similar in functionality to a classical C compiler, except that instead of emitting machine instructions, it executes built-in routines. In Python, an integer is a Python object with a bunch of attributes and methods attached to it. In Java, an int is a designated number of bits, usually 32. It’s not really a fair comparison. Python integers should really be compared to the Java Integer class. Java’s “int” primitive data type can’t be compared to anything in the Python language, because the Python language simply lacks this layer of primitives, and so does Python bytecode.

Because Java variables are explicitly typed, one can reasonably expect something like Jython performance to be in the same ballpark as cPython. On the other hand, a Java virtual machine implemented in Python is almost guaranteed to be slower than mud. And don’t expect Ruby, Perl, etc., to fare any better. They weren’t designed to do that. They were designed for “scripting”, which is what programming in a dynamic language is called.

Every operation that takes place in a virtual machine eventually has to hit real hardware. Virtual machines contain pre-compiled routines which are general enough to to execute any combination of logical operations. A virtual machine may not be emitting new machine instructions, but it certainly is executing its own routines over and over in arbirtrarily complex sequences. The Java virtual machine, the Python virtual machine, and all the other general-purpose virtual machines out there are equal in the sense that they can be coaxed into performing any logic you can dream up, but they are different in terms of what tasks they take on, and what tasks they leave to the programmer.

Psyco for Python is not a full Python virtual machine, but a just-in-time compiler that hijacks the regular Python virtual machine at points it thinks it can compile a few lines of code — mainly loops where it thinks the primitive type of some variable will remain constant even if the value is changing with each iteration. In that case, it can forego some of the incessent type determination of the regular virtual machine. You have to be a little careful, though, lest you pull the type out from under Psyco’s feet. Pysco, however, usually knows to just fall back to the regular virtual machine if it isn’t completely confident the type won’t change.

The moral of the story is that primitive data type information is really helpful to a compiler/virtual machine.

Finally, to put it all in perspective consider this: a Python program executed by a Python interpreter/virtual machine implemented in Java running on a Java interpreter/virtual machine implemented in LLVM running in a qemu virtual machine running on an iPhone.

permalink


回答 2

术语不同的一个可能原因是,人们通常考虑将python解释器提供给人类可读的原始源代码,而不用担心字节码和所有这些。

在Java中,必须显式编译为字节码,然后仅运行字节码,而不是在VM上运行源代码。

即使Python在后台使用虚拟机,但从用户的角度来看,大多数时候都可以忽略此细节。

Probably one reason for the different terminology is that one normally thinks of feeding the python interpreter raw human-readable source code and not worrying about bytecode and all that.

In Java, you have to explicitly compile to bytecode and then run just the bytecode, not source code on the VM.

Even though Python uses a virtual machine under the covers, from a user’s perspective, one can ignore this detail most of the time.


回答 3

解释器,将源代码转换为一些有效的中间表示(代码),并立即执行该代码。

虚拟机,显式执行由解释器系统一部分的编译器构建的存储的预编译代码。

虚拟机的一个非常重要的特征是,内部运行的软件仅限于虚拟机提供的资源。准确地说,它无法突破其虚拟世界。考虑一下安全执行远程代码Java Applets。

在python的情况下,如果我们保留pyc文件(如本文评论中所述),则该机制将变得更像VM,并且此字节码执行速度更快-仍将对其进行解释,但会采用更加计算机友好的形式。如果从整体上看,PVM是Python Interpreter的最后一步。

底线是,当提及Python Interpreter时,这意味着我们将其作为一个整体来提及;而当我们说PVM时,这意味着我们仅是在谈论Python Interpreter的一部分,即运行时环境。与Java类似,我们引用了differyl,JRE,JVM,JDK等不同部分。

有关更多信息,请参阅Wikipedia Entry:解释器Virtual Machine这里还有另一个。在这里,您可以找到应用程序虚拟机比较。它有助于理解编译器,解释器和VM之间的区别。

Interpreter, translates source code into some efficient intermediate representation (code) and immediately executes this.

Virtual Machine, explicitly executes stored pre-compiled code built by a compiler which is part of the interpreter system.

A very important characteristic of a virtual machine is that the software running inside, is limited to the resources provided by the virtual machine. Precisely, it cannot break out of its virtual world. Think of secure execution of remote code, Java Applets.

In case of python, if we are keeping pyc files, as mentioned in the comment of this post, then the mechanism would become more like a VM, and this bytecode executes faster — it would still be interpreted but from a much computer friendlier form. If we look at this as a whole, PVM is a last step of Python Interpreter.

The bottomline is, when refer Python Interpreter, it means we are referring it as a whole, and when we say PVM, that means we are just talking about a part of Python Interpreter, a runtime-environment. Similar to that of Java, we refer different parts differentyl, JRE, JVM, JDK, etc.

For more, Wikipedia Entry: Interpreter, and Virtual Machine. Yet another one here. Here you can find the Comparison of application virtual machines. It helps in understanding the difference between, Compilers, Interpreters, and VMs.


回答 4

术语解释器是一个可以追溯到早期Shell脚本语言的传统术语。随着“脚本语言”发展成为功能齐全的语言,并且其相应的平台变得更加复杂和沙盒化,虚拟机和解释器(在Python的意义上)之间的区别非常小或根本不存在。

Python解释器的功能仍然与Shell脚本相同,因为它无需执行单独的编译步骤即可执行。除此之外,Python的解释器(或Perl或Ruby的)与Java的虚拟机之间的差异主要是实现细节。(有人可能会说Java比Python更能进行沙盒测试,但最终两者都可以通过本机C接口提供对基础体系结构的访问。)

The term interpreter is a legacy term dating back to earlier shell scripting languages. As “scripting languages” have evolved into full featured languages and their corresponding platforms have become more sophisticated and sandboxed, the distinction between a virtual machine and an interpreter (in the Python sense), is very small or non-existent.

The Python interpreter still functions in the same way as a shell script, in the sense that it can be executed without a separate compile step. Beyond that, the differences between Python’s interpreter (or Perl or Ruby’s) and Java’s virtual machine are mostly implementation details. (One could argue that Java is more fully sandboxed than Python, but both ultimately provide access to the underlying architecture via a native C interface.)


回答 5

为了提供对“ 为什么要使用Java虚拟机,但要使用Python解释器 ” 这个问题的深刻答案,让我们尝试回到编译理论领域来作为讨论的起点。

程序编译的典型过程包括以下步骤:

  1. 词法分析。将程序文本拆分为有意义的“单词”,称为标记(作为过程的一部分,所有注释,空格,换行符等都将被删除,因为它们不影响程序行为)。结果是令牌的有序流。
  2. 语法分析。从令牌流中构建所谓的抽象语法树(AST)。AST建立令牌之间的关系,并因此定义程序评估的顺序。
  3. 语义分析。使用有关编程语言的类型和一组语义规则的信息来验证AST的语义正确性。(例如,a = b + c从syntaxis的角度来看是正确的语句,但是从语义的角度来看,如果a声明为常量对象则是完全错误的)
  4. 中间代码生成。将AST序列化为与机器无关的“原始”操作的线性顺序流。实际上,代码生成器遍历AST并记录评估步骤的顺序。结果,从程序的树状表示中,我们获得了更简单的列表状表示,其中保留了程序评估的顺序。
  5. 机器代码生成。机器独立的“原始”字节码形式的程序被转换为特定处理器体系结构的机器码。

好。现在让我们定义术语。

在该词的经典含义中,解释程序假定执行基于直接从程序文本产生的基于AST的程序评估。在这种情况下,程序将以源代码而解释器通常是通过动态方式(逐条陈述或逐行)由程序文本提供的。对于每个输入语句,解释器都会构建其AST并立即评估它以更改程序的“状态”。这是脚本语言演示的一种典型行为。考虑一下Bash,Windows CMD等。从概念上讲,Python也采用这种方式。

如果我们在解释器中生成与机器无关的二进制二进制字节码的中间步骤时替换了基于AST的执行步骤,我们会将程序执行的整个过程分为两个独立的阶段:编译和执行。在那种情况下,以前是解释器的程序将成为字节码编译器,它将程序从文本形式转换为某种二进制形式。然后,该程序以该二进制形式而不是源代码形式进行分发。在用户计算机上,该字节码被馈送到一个新的实体- 虚拟机中,该实体实际上会解释该字节码。因此,虚拟机也称为字节码解释器。但是请注意这里!古典口译员是文本解释器,但是虚拟机是二进制解释器!这是Java和C#采取的方法。

最后,如果将机器代码生成添加到字节码编译器中,则可以实现所谓的经典编译器。经典的编译器将程序源代码转换为特定处理器的机器代码。然后,可以在目标处理器上直接执行该机器代码,而无需任何其他中介(没有任何类型的解释器,既没有文本解释器也没有二进制解释器)。

现在让我们回到最初的问题,并考虑Java与Python。

Java最初被设计为具有尽可能少的实现依赖性。它的设计基于“一次编写,随处运行”(WORA)的原则。为了实现它,Java最初被设计为一种编程语言,可以编译为独立于机器的二进制字节码,然后可以在支持Java的所有平台上执行而无需重新编译。您可以像基于WORA的C ++一样思考Java。实际上,JavaPython等脚本语言更接近C ++。但是与C ++相比Java成可以编译成二进制字节码然后C ++虚拟机环境中执行,而C ++被设计为以计算机代码编译,然后由目标处理器直接执行。

Python最初被设计为一种脚本编程语言,可以解释脚本(按照编程语言规则编写的文本形式的程序)。因此,Python最初像Bash或Windows CMD一样,支持单行命令或语句的动态解释。出于同样的原因,巨蟒的初步实现了没有任何一种字节码编译器和这样的字节码内的执行虚拟机,而是从一开始的Python有需要解释这是能够理解和评价Python程序文本

由于这个原因,在历史上,Java的开发者倾向于谈论Java虚拟机(因为最初的Java已经为包的Java字节码编译器和字节码解释器JVM)和Python的开发者倾向于谈论的Python解释器(因为最初的Python有而不是任何虚拟机,而是一种经典的文本解释器,可以直接执行程序文本,而无需进行任何形式的编译或转换为任何形式的二进制代码)。

目前,Python还具有虚拟机,可以编译和解释Python字节码。这个事实为混乱带来了额外的投资”为什么要使用Java虚拟机,但要使用Python解释器?程序将演示完全相同的行为,并从相等的输入产生相同的输出。唯一可观察到的差异是程序执行的速度和解释器消耗的内存量。因此,Python中的虚拟机并不是语言设计中不可避免的部分,而只是主要Python解释器的可选扩展。

可以类似的方式考虑Java。底层的Java具有JIT编译器,可以有选择地将Java类的方法编译为目标平台的机器代码,然后直接执行它。但!Java仍然使用字节码解释作为Java程序执行的主要方式。就像Python实施将引擎盖下的虚拟机专门用作优化技术一样,Java虚拟机仅将即时编译器用于优化目的。同样,仅由于直接执行机器代码比解释Java字节码至少快十倍的事实。就像Python一样,对于Java语言设计人员和Java程序开发人员而言,JVM罩下的JIT编译器的存在绝对是透明的。带有和不带有JIT编译器的JVM都可以实现相同的Java编程语言。并且以相同的方式,可以在带有和不带有JIT的JVM中执行相同的程序,并且相同的程序将表现出完全相同的行为,并从两个JVM(带有和不带有JIT)的相等输入中产生相同的输出。就像Python一样,它们之间唯一可观察到的差异将在于执行速度和JVM消耗的内存量。最后,就像Python一样,Java中的JIT也不是语言设计中不可避免的一部分,而只是主要JVM实现的可选扩展。并且相同的程序将演示完全相同的行为,并从两个JVM(带有和不带有JIT)的相等输入中产生相同的输出。就像Python一样,它们之间唯一可观察到的差异将在于执行速度和JVM消耗的内存量。最后,就像Python一样,Java中的JIT也不是语言设计中不可避免的一部分,而只是主要JVM实现的可选扩展。并且相同的程序将演示完全相同的行为,并从两个JVM(带有和不带有JIT)的相等输入中产生相同的输出。就像Python一样,它们之间唯一可观察到的差异将在于执行速度和JVM消耗的内存量。最后,就像Python一样,Java中的JIT也不是语言设计中不可避免的一部分,而只是主要JVM实现的可选扩展。

从Java和Python虚拟机的设计和实现的角度来看,它们有显着差异,而(注意!)这两个都仍然是虚拟机。JVM是具有简单基本操作和高指令分发成本的低级虚拟机的示例。Python本身就是一个高级虚拟机,其指令说明了复杂的行为,而指令的派发成本却不那么高。Java以非常低的抽象级别运行。JVM在定义良好的原始类型的小型集合上运行,并且在字节码指令和本机代码指令之间具有非常紧密的对应关系(通常是一对一)。相反,Python虚拟机以较高的抽象级别运行,它以复杂的数据类型(对象)运行,并支持即席多态性,而字节码指令则暴露出复杂的行为,可以通过一系列多个本机机器码指令来表示。例如,Python支持无限范围数学。因此,Python VM被迫对可能的大整数采用长运算,对此运算结果可能会使机器字溢出。因此,Python中用于算术的一个字节码指令可以公开给Python VM内部的函数调用,而在JVM中,算术操作将公开给由一个或几条本机机器指令表示的简单操作。因此,Python VM被迫对可能的大整数采用长运算,对此运算结果可能会使机器字溢出。因此,Python中用于算术的一个字节码指令可以公开给Python VM内部的函数调用,而在JVM中,算术操作将公开给由一个或几条本机机器指令表示的简单操作。因此,Python VM被迫对可能的大整数采用长运算,对此运算结果可能会使机器字溢出。因此,Python中用于算术的一个字节码指令可以公开给Python VM内部的函数调用,而在JVM中,算术操作将公开给由一个或几条本机机器指令表示的简单操作。

结果,我们可以得出以下结论。Java虚拟机,但Python解释器是因为:

  1. 虚拟机一词假定二进制字节码解释,而术语解释器假定程序文本解释。
  2. 过去,Java是为二进制字节码解释而设计和实现的,而Python最初是为程序文本解释而设计和实现的。因此,术语“ Java虚拟机”是历史悠久的,并且在Java社区中已得到很好的确立。同样,术语“ Python解释器”是历史悠久的,在Python社区中已得到很好的确立。人民倾向于延长传统并使用很久以前使用的相同术语。
  3. 最后,当前,对于Java,二进制字节码解释是程序执行的主要方式,而JIT编译只是可选的透明优化。对于Python,目前,程序文本解释是Python程序执行的主要方式,而编译为Python VM字节码只是一种可选的透明优化。

因此,Java和Python拥有的虚拟机都是二进制字节码解释器,这可能导致混淆,例如“ 为什么使用Java虚拟机,但是使用Python解释器?“这里的关键是,对于Python来说,虚拟机不是程序执行的主要手段或必要手段;它只是经典文本解释器的可选扩展。另一方面,虚拟机是核心并且不可避免Java程序执行生态系统的一部分,用于编程语言设计的静态或动态类型选择主要仅影响虚拟机抽象级别,但并不决定是否需要虚拟机,可以设计使用两种类型系统的语言进行编译在虚拟机环境中进行,解释或执行,具体取决于其所需的执行模型。

To provide a deep answer to the question “Why Java Virtual Machine, but Python interpreter?” let’s try to go back to the field of compilation theory as to the starting point of the discussion.

The typical process of program compilation includes next steps:

  1. Lexical analysis. Splits program text into meaningful “words” called tokens (as part of the process all comments, spaces, new-lines etc. are removed, because they do not affect program behavior). The result is an ordered stream of tokens.
  2. Syntax analysis. Builds the so-called Abstract Syntax Tree (AST) from the stream of tokens. AST establish relations between tokens and, as a consequence, defines an order of evaluation of the program.
  3. Semantic analysis. Verifies semantical correctness of the AST using information about types and a set of semantical rules of the programming language. (For example, a = b + c is a correct statement from the syntaxis point of view, but completely incorrect from the semantic point of view if a was declared as a constant object)
  4. Intermediate code generation. Serializes AST into the linearly ordered stream of machine independent “primitive” operations. In fact, code generator traverses AST and logs the order of evaluation steps. As a result, from the tree-like representation of the program, we achieve much more simple list-like representation in which order of program evaluation is preserved.
  5. Machine code generation. The program in the form of machine independent “primitive” bytecode is translated into machine code of particular processor architecture.

Ok. Lets now define the terms.

Interpreter, in the classical meaning of that word, assumes execution based on the program evaluation based on AST produced directly from the program text. In that case, a program is distributed in the form of source code and the interpreter is fed by program text, frequently in a dynamic way (statement-by-statement or line-by-line). For each input statement, interpreter builds its AST and immediately evaluates it changing the “state” of the program. This is a typical behavior demonstrated by scripting languages. Consider for example Bash, Windows CMD etc. Conceptually, Python takes this way too.

If we replace the AST-based execution step on the generation of intermediate machine-independent binary bytecode step in the interpreter we will split the entire process of program execution into two separate phases: compilation and execution. In that case what previously was an interpreter will become a bytecode compiler, which will transform the program from the form of the text into some binary form. Then the program is distributed in that binary form, but not in the form of source code. On the user machine, that bytecode is fed into a new entity — virtual machine, which in fact interpret that bytecode. Due to this, virtual machines are also called bytecode interpreter. But put your attention here! A classical interpreter is a text interpreter, but a virtual machine is a binary interpreter! This is an approach taken by Java and C#.

Finally, if we add the machine code generation to the bytecode compiler we achieve in result what we call a classical compiler. A classical compiler converts the program source code into the machine code of a particular processor. That machine code then can be directly executed on the target processor without any additional mediation (without any kind of interpreter neither text interpreter nor binary interpreter).

Lets now go back to the original question and consider Java vs Python.

Java was initially designed to have as few implementation dependencies as possible. Its design is based on the principle “write once, run anywhere” (WORA). To implement it, Java was initially designed as a programming language that compiles into machine-independent binary bytecode, which then can be executed on all platforms that support Java without the need for its recompilation. You can think about Java like about WORA-based C++. Actually, Java is closer to C++ than to the scripting languages like Python. But in contrast to C++, Java was designed to be compiled into binary bytecode which then is executed in the environment of the virtual machine, while C++ was designed to be compiled in machine code and then directly executed by the target processor.

Python was initially designed as a kind of scripting programing language which interprets scripts (programs in the form of the text written in accordance with the programming language rules). Due to this, Python has initially supported a dynamic interpretation of one-line commands or statements, as the Bash or Windows CMD do. For the same reason, initial implementations of Python had not any kind of bytecode compilers and virtual machines for execution of such bytecode inside, but from the start Python had required interpreter which is capable to understand and evaluate Python program text.

Due to this, historically, Java developers tended to talk about Java Virtual Machine (because initially, Java has come as package of Java bytecode compiler and bytecode interpreterJVM), and Python developers tended to talk about Python interpreter (because initially Python has not any virtual machine and was a kind of classical text interpreter that executes program text directly without any sort of compilation or transformation into any form of binary code).

Currently, Python also has the virtual machine under the hood and can compile and interpret Python bytecode. And that fact makes an additional investment into the confusion “Why Java Virtual Machine, but Python interpreter?“, because it seems that implementations of both languages contain virtual machines. But! Even in the current moment interpretation of program text is a primary way of Python programs execution. Python implementations exploit virtual machines under the hood exclusively as an optimization technique. Interpretation of binary bytecode in the virtual machine is much more efficient than a direct interpretation of the original program text. At the same time, the presence of the virtual machine in the Python is absolutely transparent for both Python language designers and Python programs developers. The same language can be implemented in interpreters with and without the virtual machine. In the same way, the same programs can be executed in interpreters with and without the virtual machine, and that programs will demonstrate exactly the same behavior and produce equally the same output from the equal input. The only observable difference will be the speed of program execution and the amount of memory consumed by the interpreter. Thus, the virtual machine in Python is not an unavoidable part of the language design, but just an optional extension of the major Python interpreter.

Java can be considered in a similar way. Java under the hood has a JIT compiler and can selectively compile methods of Java class into machine code of the target platform and then directly execute it. But! Java still uses bytecode interpretation as a primary way of Java program execution. Like Python implementations which exploit virtual machines under the hood exclusively as an optimization technique, the Java virtual machines use Just-In-Time compilers exclusively for optimization purposes. Similarly, just because of the fact that direct execution of the machine code at least ten times faster than the interpretation of Java bytecode. And like in the case of Python, the presence of JIT compiler under the hood of JVM is absolutely transparent for both Java language designers and Java program developers. The same Java programming language can be implemented by JVM with and without JIT compiler. And in the same way, the same programs can be executed in JVMs with and without JIT inside, and the same programs will demonstrate exactly the same behavior and produce equally the same output from the equal input on both JVMs (with and without JIT). And like in the case of Python, the only observable difference between them, will be in the speed of execution and in the amount of memory consumed by JVM. And finally, like in the case of Python, JIT in Java also is not an unavoidable part of the language design, but just an optional extension of the major JVM implementations.

From the point of view of design and implementation of virtual machines of Java and Python, they differ significantly, while (attention!) both still stay virtual machines. JVM is an example of a low-level virtual machine with simple basic operations and high instruction dispatch cost. Python in its turn is a high-level virtual machine, for which instructions demonstrate complex behavior, and instruction dispatch cost is not so significant. Java operates with very low abstraction level. JVM operates on the small well-defined set of primitive types and has very tight correspondence (typically one to one) between bytecode instructions and native machine code instructions. In contrary, Python virtual machine operates at high abstraction level, it operates with complex data types (objects) and supports ad-hoc polymorphism, while bytecode instructions expose complex behavior, which can be represented by a series of multiple native machine code instructions. For example, Python supports unbounded range mathematics. Thus Python VM is forced to exploit long arithmetics for potentially big integers for which result of the operation can overflow the machine word. Hence, one bytecode instruction for arithmetics in Python can expose into the function call inside Python VM, while in JVM arithmetic operation will expose into simple operation expressed by one or few native machine instructions.

As a result, we can draw the next conclusions. Java Virtual Machine but Python interpreter is because:

  1. The term of virtual machine assumes binary bytecode interpretation, while the term interpreter assumes program text interpretation.
  2. Historically, Java was designed and implemented for binary bytecode interpretation and Python was initially designed and implemented for program text interpretation. Thus, the term “Java Virtual Machine” is historical and well established in the Java community. And similarly, the term “Python Interpreter” is historical and well established in the Python community. Peoples tend to prolong the tradition and use the same terms that were used long before.
  3. Finally, currently, for Java, binary bytecode interpretation is a primary way of programs execution, while JIT-compilation is just an optional and transparent optimization. And for Python, currently, program text interpretation is a primary way of Python programs execution, while compilation into Python VM bytecode is just an optional and transparent optimization.

Therefore, both Java and Python have virtual machines are binary bytecode interpreters, which can lead to confusion such as “Why Java Virtual Machine, but Python interpreter?“. The key point here is that for Python, a virtual machine is not a primary or necessary means of program execution; it is just an optional extension of the classical text interpreter. On the other hand, a virtual machine is a core and unavoidable part of Java program execution ecosystem. Static or dynamic typing choice for the programming language design affects mainly the virtual machine abstraction level only, but does not dictate whether or not a virtual machine is needed. Languages using both typing systems can be designed to be compiled, interpreted, or executed within the environment of virtual machine, depending on their desired execution model.


回答 6

它们之间没有真正的区别,人们只是遵循创建者选择的约定。

There’s no real difference between them, people just follow the conventions the creators have chosen.


回答 7

别忘了Python具有适用于x86的JIT编译器,这使问题更加混乱。(请参见psyco)。

仅当讨论VM的性能问题时,对“解释语言”进行更严格的解释才有用,例如,与Python相比,Ruby被认为较慢,因为它是一种解释语言,与Python不同-在其他方面话语,情境就是一切。

Don’t forget that Python has JIT compilers available for x86, further confusing the issue. (See psyco).

A more strict interpretation of an ‘interpreted language’ only becomes useful when discussing performance issues of the VM, for example, compared with Python, Ruby was (is?) considered to be slower because it is an interpreted language, unlike Python – in other words, context is everything.


回答 8

Python可以解释代码,而无需将其编译为字节码。Java不能

Python是一种解释型语言,与编译型语言相反,尽管由于字节码编译器的存在,两者之间的区别可能很模糊。这意味着源文件可以直接运行,而无需显式创建然后运行的可执行文件。

(来自文档)。

在Java中,每个文件必须编译为.class文件,然后文件在JVM上运行。相反,python是通过您的主脚本导入的,以帮助加快这些文件的后续使用。

但是,在典型情况下,大多数python(至少是CPython)代码在仿真的堆栈机中运行,其指令与JVM的指令几乎相同,因此没有太大的区别。

但是,造成这种区分的真正原因是,从一开始,java就将其自身标记为“便携式可执行字节码”,而python则将其自身标记为具有REPL的动态解释语言。地名棒!

Python can interpret code without compiling it to bytecode. Java can’t.

Python is an interpreted language, as opposed to a compiled one, though the distinction can be blurry because of the presence of the bytecode compiler. This means that source files can be run directly without explicitly creating an executable which is then run.

(from the documentation).

In java, every single file has to be compiled to a .class file, which then runs on the JVM. On the contrary, python does that are imported by your main script, to help speed up subsequent uses of those files.

However, in the typical case, most of the python (at least, CPython) code runs in an emulated stack machine, which has nearly identical instructions to those of the JVM, so there’s no great difference.

The real reason for the distiction however is because, from the beginning, java branded itself as “portable, executable bytecode” and python branded itself as dynamic, interpreted language with a REPL. Names stick!


回答 9

首先,您应该了解,编程或计算机科学通常不是数学,并且对于我们经常使用的大多数术语,我们没有严格的定义。

现在您的问题:

什么是口译员(计算机科学中)

它按最小的可执行单元翻译源代码,然后执行该单元。

什么是虚拟机

对于JVM,虚拟机是一种包含解释器,类加载器,垃圾收集器,线程调度程序,JIT编译器和许多其他东西的软件。

如您所见,解释器是JVM的一部分,而整个JVM不能称为解释器,因为它包含许多其他组件。

为什么在谈论python时使用单词“解释器”

使用java,编译部分是显式的。另一方面,关于java的编译和解释过程,python并不像java那样明确,从最终用户的角度来看,解释是用于执行python程序的唯一机制

First of all you should understand that programming or computer science in general is not mathematics and we don’t have rigorous definitions for most of the terms we use often.

now to your question :

what is an Interpreter (in computer science)

It translates source code by smallest executable unit and then executes that unit.

what is a virtual machine

in case of JVM the virtual machine is a software which contains an Interpreter, class loaders, garbage collector, thread scheduler , JIT compiler and many other things.

as you can see interpreter is a part or JVM and whole JVM can not be called an interpreter because it contains many other components.

why use word “Interpreter” when talking about python

with java the compilation part is explicit. python on the other hand is not explicit as java about its compilation and interpretation process, from end user’s perspective interpretation is the only mechanism used to execute python programs


回答 10

不,他们都不都解释字节码。

如果您使用pypy运行,Python仅解释字节码。否则,它将被编译为C并在该级别进行解释。

Java编译为字节码。

No, they don’t both interpret byte code.

Python only interprets bytecode if you are running with pypy. Otherwise it is compiled into C and interpreted at that level.

Java compiles to bytecode.


回答 11

我认为两者之间的界线是模糊的,人们大多参数“解释器”一词的含义以及该语言与“解释器…编译器”谱的每一侧的距离。没有人能100%赚钱。我认为编写具有任何价值的Java或Python实现很容易。

目前,Java和Python都具有虚拟机和字节码,尽管其中一个使用具体的值大小(例如32位整数)进行操作,而另一个则必须确定每个调用的大小,我认为这并没有定义术语之间的边界。

关于Python没有正式定义字节码并且仅存在于内存中的说法也没有使我信服,因为我正计划开发仅识别Python字节码且编译部分将在浏览器JS机器中完成的设备。

性能只是关于具体的实现。我们不需要知道对象的大小即可使用它,最后,在大多数情况下,我们使用结构而不是基本类型。通过重新使用现有的Python,可以优化Python VM,从而消除在表达式计算期间每次创建新对象的需求。一旦完成,计算两个整数之和之间就不会有全局性能差异,这就是Java的亮点。

两者之间没有致命的区别,只有一些实现上的细微差别和缺乏优化与最终用户无关,也许是在她开始注意到性能落后的时候,但这又是实现而不是体系结构问题。

I think the lines between both are blurred, people mostly argue around meaning of word “interpreter” and how close the language stands to each side of “interpreter…compiler” spectrum. None makes 100% however. I think it is easy to write Java or Python implementation which be of any value of the spectrum.

Currently both Java and Python have virtual machines and bytecode, though one operates by concrete value sizes (like 32-bit integer) while other has to determine the size for each call, which in my opinion doesn’t define the border between the terms.

The argument that Python doesn’t have officially defined bytecode and it exists only in memory also doesn’t convince me, just because I am planning to develop devices which will recognize only Python bytecode and the compilation part will be done in browser JS machine.

Performance is only about the concrete implementation. We don’t need to know the size of the object to be able to work with it, and finally, in most cases, we work with structures, not basic types. It is possible to optimize Python VM in the way that it will eliminate the need of creating new object each time during expression calculation, by reusing existing one. Once it is done, there is no global performance difference between calculating sum of two integers, which is where Java shines.

There is no killer difference between the two, only some implementation nuances and lack of optimization which are irrelevant to the end user, maybe up at the point where she starts to notice performance lags, but again it is implementation and not architecture issue.


回答 12

对于提到python不需要生成字节码的帖子,我不确定那是真的。似乎Python中的所有可调用对象都必须具有.__code__.co_code包含字节码的属性。我看不出有一个有意义的理由将python称为“未编译”,仅仅是因为编译后的工件可能无法保存。并且通常不是通过设计在Python中保存的,例如,所有理解都会为其输入编译新的字节码,这就是为什么理解变量作用域之间compile(mode='exec, ...)和编译(compile(mode='single', ...)例如在运行python脚本和使用pdb之间)不一致的原因

for posts that mention that python does not need to generate byte code, I’m not sure that’s true. it seems that all callables in Python must have a .__code__.co_code attribute which contains the byte code. I don’t see a meaningful reason to call python “not compiled” just because the compiled artifacts may not be saved; and often aren’t saved by design in Python, for example all comprehension compile new bytecode for it’s input, this is the reason comprehension variable scope is not consistent between compile(mode='exec, ...) and compile compile(mode='single', ...) such as between running a python script and using pdb


寻求澄清有关弱类型语言的明显矛盾

问题:寻求澄清有关弱类型语言的明显矛盾

我想我了解强类型,但是每次我寻找弱类型的示例时,我最终都会找到简单地自动强制转换类型的编程语言示例。

例如,在这篇名为“ 打字:强vs.弱”,“静态vs.动态 ”的文章中,Python是强类型的,因为如果尝试执行以下操作,则会得到异常:

Python

1 + "1"
Traceback (most recent call last):
File "", line 1, in ? 
TypeError: unsupported operand type(s) for +: 'int' and 'str'

但是,在Java和C#中这种事情是可能的,因此我们不认为它们只是弱类型的。

爪哇

  int a = 10;
  String b = "b";
  String result = a + b;
  System.out.println(result);

C#

int a = 10;
string b = "b";
string c = a + b;
Console.WriteLine(c);

在另一篇名为弱类型语言的文章中,作者说Perl弱类型仅仅是因为我可以将字符串连接成数字,反之亦然,而无需任何显式转换。

佩尔

$a=10;
$b="a";
$c=$a.$b;
print $c; #10a

因此,同一示例使Perl的类型较弱,但Java和C#?的类型却没有。

真是的

作者似乎暗示一种阻止对不同类型的值执行某些操作的语言是强类型的,而相反的意思是弱类型。

因此,在某些时候,我感到被提示相信,如果一种语言在类型之间提供大量自动转换或强制转换(例如perl),最终可能会被认为是弱类型,而其他仅提供少量转换的语言可能最终会被视为弱类型。被认为是强类型的。

但是,我倾向于相信,在这种相互交流中我一定是错的,我只是不知道为什么或如何解释它。

因此,我的问题是:

  • 语言真正弱键入到底意味着什么?
  • 您能否提及与该语言完成的自动转换/自动强制无关的弱类型的任何好例子?
  • 语言可以同时弱输入和强输入吗?

I think I understand strong typing, but every time I look for examples for what is weak typing I end up finding examples of programming languages that simply coerce/convert types automatically.

For instance, in this article named Typing: Strong vs. Weak, Static vs. Dynamic says that Python is strongly typed because you get an exception if you try to:

Python

1 + "1"
Traceback (most recent call last):
File "", line 1, in ? 
TypeError: unsupported operand type(s) for +: 'int' and 'str'

However, such thing is possible in Java and in C#, and we do not consider them weakly typed just for that.

Java

  int a = 10;
  String b = "b";
  String result = a + b;
  System.out.println(result);

C#

int a = 10;
string b = "b";
string c = a + b;
Console.WriteLine(c);

In this another article named Weakly Type Languages the author says that Perl is weakly typed simply because I can concatenate a string to a number and viceversa without any explicit conversion.

Perl

$a=10;
$b="a";
$c=$a.$b;
print $c; #10a

So the same example makes Perl weakly typed, but not Java and C#?.

Gee, this is confusing

The authors seem to imply that a language that prevents the application of certain operations on values of different types is strongly typed and the contrary means weakly typed.

Therefore, at some point I have felt prompted to believe that if a language provides a lot of automatic conversions or coercion between types (as perl) may end up being considered weakly typed, whereas other languages that provide only a few conversions may end up being considered strongly typed.

I am inclined to believe, though, that I must be wrong in this interepretation, I just do not know why or how to explain it.

So, my questions are:

  • What does it really mean for a language to be truly weakly typed?
  • Could you mention any good examples of weakly typing that are not related to automatic conversion/automatic coercion done by the language?
  • Can a language be weakly typed and strongly typed at the same time?

回答 0

更新:这个问题是我在2012年10月15日发布的博客的主题。感谢您提出的伟大问题!


语言“弱类型化”的真正含义是什么?

它的意思是“这种语言使用的类型系统令人讨厌”。相比之下,“强类型”语言是具有令人愉悦的类型系统的语言。

这些术语本质上是没有意义的,您应该避免使用它们。维基百科列出了“强类型”的十一种不同含义,其中有几种是矛盾的。这表明在涉及术语“强类型”或“弱类型”的任何对话中,造成混乱的可能性很高。

您真正可以肯定地说的是,正在讨论的“强类型”语言在类型系统上有一些其他限制,无论是在运行时还是编译时,都缺乏在讨论中的“弱类型”语言。没有进一步的上下文,就无法确定该限制是什么。

不应使用“强类型”和“弱类型”,而应详细描述您所指的类型安全。例如,C#在大多数情况下静态类型的语言,类型安全的语言和内存安全的语言。C#允许违反所有三种“强”类型的输入形式。强制转换运算符违反静态类型;它对编译器说:“我比您更了解此表达式的运行时类型”。如果开发人员错误,则运行时将抛出异常以保护类型安全。如果开发人员希望破坏类型安全性或存储安全性,则可以通过制作“不安全”块来关闭类型安全性系统来做到这一点。在不安全的块中,您可以使用指针魔术来将int视为浮点型(违反类型安全性)或写入您不拥有的内存。(破坏内存安全。)

C#施加了在编译时和运行时都进行检查的类型限制,因此与进行较少的编译时检查或较少的运行时检查的语言相比,C#使其成为“强类型”语言。C#还允许您在特殊情况下绕这些限制进行最终运行,与不允许您进行此类最终运行的语言相比,它成为“弱类型”语言。

到底是什么 很难说。这取决于说话者的观点及其对各种语言功能的态度。

UPDATE: This question was the subject of my blog on the 15th of October, 2012. Thanks for the great question!


What does it really mean for a language to be “weakly typed”?

It means “this language uses a type system that I find distasteful”. A “strongly typed” language by contrast is a language with a type system that I find pleasant.

The terms are essentially meaningless and you should avoid them. Wikipedia lists eleven different meanings for “strongly typed”, several of which are contradictory. This indicates that the odds of confusion being created are high in any conversation involving the term “strongly typed” or “weakly typed”.

All that you can really say with any certainty is that a “strongly typed” language under discussion has some additional restriction in the type system, either at runtime or compile time, that a “weakly typed” language under discussion lacks. What that restriction might be cannot be determined without further context.

Instead of using “strongly typed” and “weakly typed”, you should describe in detail what kind of type safety you mean. For example, C# is a statically typed language and a type safe language and a memory safe language, for the most part. C# allows all three of those forms of “strong” typing to be violated. The cast operator violates static typing; it says to the compiler “I know more about the runtime type of this expression than you do”. If the developer is wrong, then the runtime will throw an exception in order to protect type safety. If the developer wishes to break type safety or memory safety, they can do so by turning off the type safety system by making an “unsafe” block. In an unsafe block you can use pointer magic to treat an int as a float (violating type safety) or to write to memory you do not own. (Violating memory safety.)

C# imposes type restrictions that are checked at both compile-time and at runtime, thereby making it a “strongly typed” language compared to languages that do less compile-time checking or less runtime checking. C# also allows you to in special circumstances do an end-run around those restrictions, making it a “weakly typed” language compared with languages which do not allow you to do such an end-run.

Which is it really? It is impossible to say; it depends on the point of view of the speaker and their attitude towards the various language features.


回答 1

正如其他人指出的那样,术语“强类型”和“弱类型”具有许多不同的含义,因此您的问题没有一个答案。但是,由于您在问题中特别提到了Perl,因此让我尝试解释Perl弱键入的含义。

关键是,在Perl中,没有“整数变量”,“浮点变量”,“字符串变量”或“布尔变量”之类的东西。实际上,据用户所知(通常),甚至没有整数,浮点数,字符串或布尔:您所拥有的都是“标量”,它们同时是所有这些东西。因此,您可以例如编写:

$foo = "123" + "456";           # $foo = 579
$bar = substr($foo, 2, 1);      # $bar = 9
$bar .= " lives";               # $bar = "9 lives"
$foo -= $bar;                   # $foo = 579 - 9 = 570

当然,正如您正确指出的那样,所有这些都可以看作是强制类型。但是关键是,在Perl中,类型始终是强制的。实际上,用户很难说出变量的内部“类型”是什么:在我上面的示例的第2行,询问变量的值$bar是字符串"9"还是数字9几乎没有意义,因为就Perl而言,它们是同一回事。实际上,Perl标量甚至有可能在内部同时具有字符串和数字值,例如$foo上面第2行之后的情况。

不利的一面是,由于Perl变量是无类型的(或者,不向用户公开其内部类型),因此不能重载运算符以对不同类型的参数执行不同的操作。您不能只说“此运算符将对数字执行X,对字符串执行Y”,因为该运算符无法(不会)告诉其参数是哪种类型的值。

因此,例如,Perl同时具有并且需要数字加法运算符(+)和字符串连接运算符(.):如上所述,添加字符串("1" + "2" == "3")或连接数字(1 . 2 == 12)很好。同样,数字比较操作符==!=<><=>=<=>比较它们的参数的数值,而字符串比较操作符eqneltgtlegecmp字典顺序比较它们为字符串。所以2 < 10,但是2 gt 10(但是"02" lt 10,虽然"02" == 2)。(请注意,某些其他语言(例如JavaScript)会尝试容纳类似Perl的弱类型做运算符重载。这通常会导致丑陋,例如失去与+。)的关联性。

(美中不足的是,由于历史原因,Perl 5确实有一些极端情况,例如按位逻辑运算符,其行为取决于其参数的内部表示。通常认为这是令人讨厌的设计缺陷,因为内部表述可能会由于令人惊讶的原因而发生变化,因此仅预测那些操作员在给定情况下的操作可能很棘手。)

综上所述,可以说Perl 确实具有强类型。它们不是您可能期望的那种类型。具体来说,除了上面讨论的“标量”类型外,Perl还具有两种结构化类型:“数组”和“哈希”。这些是非常从标量不同,到了那里的Perl变量具有不同的点印记,指示它们的类型($用于标量,@数组,%对于散列)1。有这些类型之间的强制规则,这样你就可以写例如%foo = @bar,但其中不少是相当有损耗:例如,$foo = @bar分配长度的数组 @bar$foo,而不是其内容。(此外,还有其他一些奇怪的类型,例如typeglob和I / O句柄,您通常不会看到它们是公开的。)

同样,在这种出色的设计中,有一个小缺点是引用类型的存在,它们是一种特殊的标量(可以使用ref运算符将其与普通标量区分开)。可以将引用用作普通标量,但是它们的字符串/数字值并不是特别有用,并且如果您使用普通标量操作对其进行修改,它们往往会失去其特殊的引用性。同样,任何Perl变量2都可以作为范例。通常的意见是,如果您发现自己在Perl中检查了对象的类,则说明您做错了什么。bless编入一个类,将其变成该类的对象。Perl中的OO类系统在某种程度上与上述原始类型(或无类型性)系统正交,尽管它在遵循鸭子类型的意义上也是“弱”的


1实际上,印记表示被访问的值的类型,以使得例如在阵列中的第一标@foo$foo[0]。有关更多详细信息,请参见perlfaq4

2(通常)通过引用访问Perl中的对象,但实际上得到的bless是引用所指向的(可能是匿名的)变量。但是,祝福实际上是变量的属性,而不是变量的值,因此,例如,将实际的祝福变量分配给另一个变量,只会给您一个浅浅的,没有祝福的副本。有关更多详细信息,请参见perlobj

As others have noted, the terms “strongly typed” and “weakly typed” have so many different meanings that there’s no single answer to your question. However, since you specifically mentioned Perl in your question, let me try to explain in what sense Perl is weakly typed.

The point is that, in Perl, there is no such thing as an “integer variable”, a “float variable”, a “string variable” or a “boolean variable”. In fact, as far as the user can (usually) tell, there aren’t even integer, float, string or boolean values: all you have are “scalars”, which are all of these things at the same time. So you can, for example, write:

$foo = "123" + "456";           # $foo = 579
$bar = substr($foo, 2, 1);      # $bar = 9
$bar .= " lives";               # $bar = "9 lives"
$foo -= $bar;                   # $foo = 579 - 9 = 570

Of course, as you correctly note, all of this can be seen as just type coercion. But the point is that, in Perl, types are always coerced. In fact, it’s quite hard for a user to tell what the internal “type” of a variable might be: at line 2 in my example above, asking whether the value of $bar is the string "9" or the number 9 is pretty much meaningless, since, as far as Perl is concerned, those are the same thing. Indeed, it’s even possible for a Perl scalar to internally have both a string and a numeric value at the same time, as is e.g. the case for $foo after line 2 above.

The flip side of all this is that, since Perl variables are untyped (or, rather, don’t expose their internal type to the user), operators cannot be overloaded to do different things for different types of arguments; you can’t just say “this operator will do X for numbers and Y for strings”, because the operator can’t (won’t) tell which kind of values its arguments are.

Thus, for example, Perl has and needs both a numeric addition operator (+) and a string concatenation operator (.): as you saw above, it’s perfectly fine to add strings ("1" + "2" == "3") or to concatenate numbers (1 . 2 == 12). Similarly, the numeric comparison operators ==, !=, <, >, <=, >= and <=> compare the numeric values of their arguments, while the string comparison operators eq, ne, lt, gt, le, ge and cmp compare them lexicographically as strings. So 2 < 10, but 2 gt 10 (but "02" lt 10, while "02" == 2). (Mind you, certain other languages, like JavaScript, try to accommodate Perl-like weak typing while also doing operator overloading. This often leads to ugliness, like the loss of associativity for +.)

(The fly in the ointment here is that, for historical reasons, Perl 5 does have a few corner cases, like the bitwise logical operators, whose behavior depends on the internal representation of their arguments. Those are generally considered an annoying design flaw, since the internal representation can change for surprising reasons, and so predicting just what those operators do in a given situation can be tricky.)

All that said, one could argue that Perl does have strong types; they’re just not the kind of types you might expect. Specifically, in addition to the “scalar” type discussed above, Perl also has two structured types: “array” and “hash”. Those are very distinct from scalars, to the point where Perl variables have different sigils indicating their type ($ for scalars, @ for arrays, % for hashes)1. There are coercion rules between these types, so you can write e.g. %foo = @bar, but many of them are quite lossy: for example, $foo = @bar assigns the length of the array @bar to $foo, not its contents. (Also, there are a few other strange types, like typeglobs and I/O handles, that you don’t often see exposed.)

Also, a slight chink in this nice design is the existence of reference types, which are a special kind of scalars (and which can be distinguished from normal scalars, using the ref operator). It’s possible to use references as normal scalars, but their string/numeric values are not particularly useful, and they tend to lose their special reference-ness if you modify them using normal scalar operations. Also, any Perl variable2 can be blessed to a class, turning it into an object of that class; the OO class system in Perl is somewhat orthogonal to the primitive type (or typelessness) system described above, although it’s also “weak” in the sense of following the duck typing paradigm. The general opinion is that, if you find yourself checking the class of an object in Perl, you’re doing something wrong.


1 Actually, the sigil denotes the type of the value being accessed, so that e.g. the first scalar in the array @foo is denoted $foo[0]. See perlfaq4 for more details.

2 Objects in Perl are (normally) accessed through references to them, but what actually gets blessed is the (possibly anonymous) variable the reference points to. However, the blessing is indeed a property of the variable, not of its value, so e.g. that assigning the actual blessed variable to another one just gives you a shallow, unblessed copy of it. See perlobj for more details.


回答 2

除了Eric所说的以外,请考虑以下C代码:

void f(void* x);

f(42);
f("hello");

与诸如Python,C#,Java或其他语言之类的语言相比,上面的类型是弱类型的,因为我们会丢失类型信息。Eric正确指出,在C#中,我们可以通过强制转换来绕过编译器,有效地告诉它“我比您更了解此变量的类型”。

但是即使那样,运行时仍会检查类型!如果强制转换无效,则运行时系统将对其进行捕获并引发异常。

使用类型擦除不会发生这种情况–类型信息会被丢弃。强制转换void*为C可以做到这一点。在这方面,以上内容与C#方法声明(例如)从根本上有所不同void f(Object x)

(从技术上讲,C#还允许通过不安全的代码或编组来擦除类型。)

是尽可能弱的类型。其他的一切只是一个静态还是动态类型检查,即时间的事一个类型被选中。

In addition to what Eric has said, consider the following C code:

void f(void* x);

f(42);
f("hello");

In contrast to languages such as Python, C#, Java or whatnot, the above is weakly typed because we lose type information. Eric correctly pointed out that in C# we can circumvent the compiler by casting, effectively telling it “I know more about the type of this variable than you”.

But even then, the runtime will still check the type! If the cast is invalid, the runtime system will catch it and throw an exception.

With type erasure, this doesn’t happen – type information is thrown away. A cast to void* in C does exactly that. In this regard, the above is fundamentally different from a C# method declaration such as void f(Object x).

(Technically, C# also allows type erasure through unsafe code or marshalling.)

This is as weakly typed as it gets. Everything else is just a matter of static vs. dynamic type checking, i.e. of the time when a type is checked.


回答 3

Wikipedia的“强类型”文章就是一个很好的例子:

通常,强类型意味着编程语言对允许发生的混合进行了严格的限制。

弱打字

a = 2
b = "2"

concatenate(a, b) # returns "22"
add(a, b) # returns 4

强类型

a = 2
b = "2"

concatenate(a, b) # Type Error
add(a, b) # Type Error
concatenate(str(a), b) #Returns "22"
add(a, int(b)) # Returns 4

请注意,弱类型的语言可以混合不同类型而不会出错。强类型语言要求输入类型为预期类型。在强类型语言中,可以转换类型(str(a)将整数转换为字符串)或强制转换(int(b))。

这一切都取决于键入的解释。

A perfect example comes from the wikipedia article of Strong Typing:

Generally strong typing implies that the programming language places severe restrictions on the intermixing that is permitted to occur.

Weak Typing

a = 2
b = "2"

concatenate(a, b) # returns "22"
add(a, b) # returns 4

Strong Typing

a = 2
b = "2"

concatenate(a, b) # Type Error
add(a, b) # Type Error
concatenate(str(a), b) #Returns "22"
add(a, int(b)) # Returns 4

Notice that a weak typing language can intermix different types without errors. A strong type language requires the input types to be the expected types. In a strong type language a type can be converted (str(a) converts an integer to a string) or cast (int(b)).

This all depends on the interpretation of typing.


回答 4

我想通过自己对这个问题的研究来为讨论做出贡献,正如其他人评论并做出贡献一样,我一直在阅读他们的答案并遵循他们的参考文献,并且发现了有趣的信息。如建议的那样,在程序员论坛中可能会更好地讨论其中的大多数内容,因为它似乎是理论上的而非实际的。

从理论的角度来看,我认为Luca Cardelli和Peter Wegner撰写的关于理解类型,数据抽象和多态性的文章是我所读过的最好的论据之一。

一种类型可以看作是一套衣服(或盔甲),可以保护基础的无类型表示形式免受任意使用或非预期使用。它提供了一个保护性遮盖物,该遮盖物隐藏了底层表示并限制了对象与其他对象交互的方式。在无类型的系统中,无类型的对象是裸露 的,其基础表示形式公开给所有人看。违反字体系统需要脱下防护服并直接在裸露的衣服上操作。

该说法似乎表明,弱类型输入将使我们能够访问类型的内部结构并像对待其他类型(另一种类型)一样对其进行操作。也许我们可以用不安全的代码(由Eric提及)或由Konrad提及的用c类型擦除的指针来做。

文章继续…

所有表达式类型一致的语言称为强类型语言。如果语言是强类型的,则其编译器可以保证所接受的程序将在没有类型错误的情况下执行。通常,我们应该努力实现强类型化,并在可能的情况下采用静态类型。请注意,每种静态类型的语言都是强类型的,但相反不一定是正确的。

因此,强类型表示没有类型错误,我只能假设弱类型意味着相反:可能存在类型错误。在运行时还是编译时?在这里似乎无关紧要。

有趣的是,按照该定义,具有强大类型强制性的语言(如Perl)将被视为强类型化的,因​​为系统不会失败,但是它通过将类型强制为适当的和定义良好的对等来处理类型。

另一方面,我是否可以说ClassCastExceptionArrayStoreException(在Java中)和InvalidCastExceptionArrayTypeMismatchException(在C#中)的允许表示至少在编译时处于弱类型的水平?埃里克的答案似乎同意这一点。

在此问题的答案之一提供的参考文献之一中提供的第二篇名为类型化编程的文章中,Luca Cardelli深入研究了类型冲突的概念:

大多数系统编程语言都允许任意类型的违反,有些是不加区分的,有些仅在程序的受限部分中。涉及类型冲突的操作称为不健全。类型违规分为几类[我们可以提到]:

基本值强制:包括整数,布尔值,字符,集合等之间的转换。这里不需要类型冲突,因为可以提供内置接口来以类型健全的方式执行强制。

这样,像操作员提供的那样的类型强制可以被认为是类型冲突,但是除非它们破坏了类型系统的一致性,否则我们可以说它们不会导致弱类型系统。

基于此,Python,Perl,Java或C#都不是弱类型。

Cardelli提到了两个类型错误,我很好地考虑了真正弱类型的情况:

地址算术。如有必要,应该有一个内置的(不健全的)接口,提供对地址和类型转换的适当操作。各种情况都涉及到堆的指针(对于重定位收集器非常危险),指向堆栈的指针,指向静态区域的指针以及指向其他地址空间的指针。有时,数组索引可以代替地址算法。 内存映射。这涉及将内存区域视为非结构化数组,尽管它包含结构化数据。这是内存分配器和收集器的典型特征。

诸如C(由Konrad提及)或.Net中不安全代码(由Eric提及)之类的语言中可能发生的这类事情实际上暗示着弱键入。

我相信到目前为止,最好的答案是埃里克(Eric),因为这个概念的定义是非常理论性的,当涉及到特定语言时,对所有这些概念的解释可能会得出不同的结论。

I would like to contribute to the discussion with my own research on the subject, as others comment and contribute I have been reading their answers and following their references and I have found interesting information. As suggested, it is probable that most of this would be better discussed in the Programmers forum, since it appears to be more theoretical than practical.

From a theoretical standpoint, I think the article by Luca Cardelli and Peter Wegner named On Understanding Types, Data Abstraction and Polymorphism has one of the best arguments I have read.

A type may be viewed as a set of clothes (or a suit of armor) that protects an underlying untyped representation from arbitrary or unintended use. It provides a protective covering that hides the underlying representation and constrains the way objects may interact with other objects. In an untyped system untyped objects are naked in that the underlying representation is exposed for all to see. Violating the type system involves removing the protective set of clothing and operating directly on the naked representation.

This statement seems to suggest that weakly typing would let us access the inner structure of a type and manipulate it as if it was something else (another type). Perhaps what we could do with unsafe code (mentioned by Eric) or with c type-erased pointers mentioned by Konrad.

The article continues…

Languages in which all expressions are type-consistent are called strongly typed languages. If a language is strongly typed its compiler can guarantee that the programs it accepts will execute without type errors. In general, we should strive for strong typing, and adopt static typing whenever possible. Note that every statically typed language is strongly typed but the converse is not necessarily true.

As such, strong typing means the absence of type errors, I can only assume that weak typing means the contrary: the likely presence of type errors. At runtime or compile time? Seems irrelevant here.

Funny thing, as per this definition, a language with powerful type coercions like Perl would be considered strongly typed, because the system is not failing, but it is dealing with the types by coercing them into appropriate and well defined equivalences.

On the other hand, could I say than the allowance of ClassCastException and ArrayStoreException (in Java) and InvalidCastException, ArrayTypeMismatchException (in C#) would indicate a level of weakly typing, at least at compile time? Eric’s answer seems to agree with this.

In a second article named Typeful Programming provided in one of the references provided in one of the answers in this question, Luca Cardelli delves into the concept of type violations:

Most system programming languages allow arbitrary type violations, some indiscriminately, some only in restricted parts of a program. Operations that involve type violations are called unsound. Type violations fall in several classes [among which we can mention]:

Basic-value coercions: These include conversions between integers, booleans, characters, sets, etc. There is no need for type violations here, because built-in interfaces can be provided to carry out the coercions in a type-sound way.

As such, type coercions like those provided by operators could be considered type violations, but unless they break the consistency of the type system, we might say that they do not lead to a weakly typed system.

Based on this neither Python, Perl, Java or C# are weakly typed.

Cardelli mentions two type vilations that I very well consider cases of truly weak typing:

Address arithmetic. If necessary, there should be a built-in (unsound) interface, providing the adequate operations on addresses and type conversions. Various situations involve pointers into the heap (very dangerous with relocating collectors), pointers to the stack, pointers to static areas, and pointers into other address spaces. Sometimes array indexing can replace address arithmetic. Memory mapping. This involves looking at an area of memory as an unstructured array, although it contains structured data. This is typical of memory allocators and collectors.

This kind of things possible in languages like C (mentioned by Konrad) or through unsafe code in .Net (mentioned by Eric) would truly imply weakly typing.

I believe the best answer so far is Eric’s, because the definition of this concepts is very theoretical, and when it comes to a particular language, the interpretations of all these concepts may lead to different debatable conclusions.


回答 5

弱类型的确确实意味着可以隐式强制转换很大比例的类型,试图猜测编码器的意图。

强类型意味着没有强制类型,或者至少没有强制类型。

静态类型意味着您的变量类型在编译时确定。

最近,许多人将“明显键入”与“强烈键入”混淆。“清单式输入”是指您明确声明变量的类型。

Python通常是强类型的,尽管您可以在布尔上下文中使用几乎所有内容,布尔值可以在整数上下文中使用,并且您可以在浮点上下文中使用整数。它没有明显的类型,因为您不需要声明您的类型(Cython除外,尽管它很有趣,但它并不完全是python)。它也不是静态类型的。

C和C ++是明显类型化,静态类型化和某种程度强类型化的,因​​为您声明类型,类型是在编译时确定的,并且可以混合使用整数和指针,整数和双精度,甚至将指向一种类型的指针转​​换为指向另一种类型的指针。

Haskell是一个有趣的示例,因为它不是显式键入的,而是静态和强类型的。

Weak typing does indeed mean that a high percentage of types can be implicitly coerced, attempting to guess what the coder intended.

Strong typing means that types are not coerced, or at least coerced less.

Static typing means your variables’ types are determined at compile time.

Many people have recently been confusing “manifestly typed” with “strongly typed”. “Manifestly typed” means that you declare your variables’ types explicitly.

Python is mostly strongly typed, though you can use almost anything in a boolean context, and booleans can be used in an integer context, and you can use an integer in a float context. It is not manifestly typed, because you don’t need to declare your types (except for Cython, which isn’t entirely python, albeit interesting). It is also not statically typed.

C and C++ are manifestly typed, statically typed, and somewhat strongly typed, because you declare your types, types are determined at compile time, and you can mix integers and pointers, or integers and doubles, or even cast a pointer to one type into a pointer to another type.

Haskell is an interesting example, because it is not manifestly typed, but it’s also statically and strongly typed.


回答 6

强<=>弱类型不仅是关于一种数据类型的语言将语言自动将多少值强制转换为另一种数据的连续性,还涉及到对实际的强弱程度。在Python和Java中,大多数情况下在C#中,值的类型设置为固定。在Perl中,不是那么多-实际上只有少数几个不同的值类型可以存储在变量中。

让我们一一打开案例。


Python

在Python示例中1 + "1"+运算符调用__add__for类型int,将字符串"1"作为参数,但是这会导致NotImplemented:

>>> (1).__add__('1')
NotImplemented

接下来,解释器尝试__radd__str的:

>>> '1'.__radd__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'

由于失败,+操作员将结果与失败TypeError: unsupported operand type(s) for +: 'int' and 'str'。这样,该异常并不能说明强类型,但是该运算符+ 不会自动将其参数强制转换为同一类型,这说明了Python不是连续体中最弱类型的语言。

另一方面,在Python 'a' * 5 实现了:

>>> 'a' * 5
'aaaaa'

那是,

>>> 'a'.__mul__(5)
'aaaaa'

操作不同的事实需要强类型化-但是,*在乘法之前将值强制转换为数字的相反情况并不一定会使值弱类型化。


爪哇

Java示例String result = "1" + 1;之所以起作用,仅是因为为方便起见,运算符+被字符串重载。Java +运算符使用创建一个替换序列StringBuilder(请参阅参考资料):

String result = a + b;
// becomes something like
String result = new StringBuilder().append(a).append(b).toString()

这是一个非常静态的键入的示例,没有实际的强制性- StringBuilder有一种append(Object)专门用于此的方法。该文档说:

追加Object参数的字符串表示形式。

总体效果就好像参数已由方法转换为String.valueOf(Object)字符串,然后将该字符串的字符附加到此字符序列。

String.valueOf

返回Object参数的字符串表示形式。[返回]如果参数为null,则字符串等于"null"; 否则,obj.toString()返回的值。

因此,这种情况绝对不会被语言强制-将所有问题都委派给对象本身。


C#

根据此处Jon Skeet答案,该类+甚至都不会重载运算符string-类似于Java,这归功于静态和强类型化,这是编译器生成的便利。


佩尔

正如perldata解释的那样,

Perl具有三种内置数据类型:标量,标量数组和标量的关联数组,称为“哈希”。标量是单个字符串(任何大小,仅受可用内存限制),数字或对某物的引用(将在perlref中进行讨论)。普通数组是按数字索引的标量的有序列表,从0开始。哈希是通过其关联的字符串键索引的无序标量值的集合。

但是,Perl没有用于数字,布尔值,字符串,空值,undefineds,对其他对象的引用等的单独数据类型-它仅具有一种用于所有这些的类型,即标量类型。0是“ 0”的标量值。设置为字符串的标量变量实际上可以变成数字,并且从此开始,如果在数字上下文中访问则其行为就不同于“只是字符串”。标量可以在Perl中容纳任何内容,它与系统中存在的对象一样多。而在Python中,名称仅指对象,而在Perl中,名称中的标量值是可变对象。此外,基于对象的类型系统还基于此:perl中只有3种数据类型-标量,列表和哈希。Perl中的用户定义对象是对包的引用(指向之前3个中的任何一个的指针)bless-您可以获取任何此类值,并在需要的任何时候将其祝福给任何类。

Perl甚至允许您一时兴起地更改值的类-在Python中这是不可能的,在Python中创建某些类的值时,您需要显式构造具有该类object.__new__或类似值的该类的值。在Python中,创建后实际上不能更改对象的本质,在Perl中,您可以做很多事情:

package Foo;
package Bar;

my $val = 42;
# $val is now a scalar value set from double
bless \$val, Foo;
# all references to $val now belong to class Foo
my $obj = \$val;
# now $obj refers to the SV stored in $val
# thus this prints: Foo=SCALAR(0x1c7d8c8)
print \$val, "\n"; 
# all references to $val now belong to class Bar
bless \$val, Bar;
# thus this prints Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# we change the value stored in $val from number to a string
$val = 'abc';
# yet still the SV is blessed: Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# and on the course, the $obj now refers to a "Bar" even though
# at the time of copying it did refer to a "Foo".
print $obj, "\n";

因此,类型标识弱绑定到变量,并且可以通过任何引用即时更改它。实际上,如果您这样做

my $another = $val;

\$another没有类标识,即使仍然\$val会提供祝福的引用。


TL; DR

对于Perl而言,弱类型不仅仅是自动强制,还有很多更多的是,值的类型本身并没有固定不变,这与Python是动态但非常强类型的语言不同。这Python给人TypeError1 + "1"是一种迹象表明,语言是强类型,即使做一些有用的一个相反,如Java或C#不排除他们是强类型语言。

The strong <=> weak typing is not only about the continuum on how much or how little of the values are coerced automatically by the language for one datatype to another, but how strongly or weakly the actual values are typed. In Python and Java, and mostly in C#, the values have their types set in stone. In Perl, not so much – there are really only a handful of different valuetypes to store in a variable.

Let’s open the cases one by one.


Python

In Python example 1 + "1", + operator calls the __add__ for type int giving it the string "1" as an argument – however, this results in NotImplemented:

>>> (1).__add__('1')
NotImplemented

Next, the interpreter tries the __radd__ of str:

>>> '1'.__radd__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'

As it fails, the + operator fails with the the result TypeError: unsupported operand type(s) for +: 'int' and 'str'. As such, the exception does not say much about strong typing, but the fact that the operator + does not coerce its arguments automatically to the same type, is a pointer to the fact that Python is not the most weakly typed language in the continuum.

On the other hand, in Python 'a' * 5 is implemented:

>>> 'a' * 5
'aaaaa'

That is,

>>> 'a'.__mul__(5)
'aaaaa'

The fact that the operation is different requires some strong typing – however the opposite of * coercing the values to numbers before multiplying still would not necessarily make the values weakly typed.


Java

The Java example, String result = "1" + 1; works only because as a fact of convenience, the operator + is overloaded for strings. The Java + operator replaces the sequence with creating a StringBuilder (see this):

String result = a + b;
// becomes something like
String result = new StringBuilder().append(a).append(b).toString()

This is rather an example of very static typing, without no actual coercion – StringBuilder has a method append(Object) that is specifically used here. The documentation says the following:

Appends the string representation of the Object argument.

The overall effect is exactly as if the argument were converted to a string by the method String.valueOf(Object), and the characters of that string were then appended to this character sequence.

Where String.valueOf then

Returns the string representation of the Object argument. [Returns] if the argument is null, then a string equal to "null"; otherwise, the value of obj.toString() is returned.

Thus this is a case of absolutely no coercion by the language – delegating every concern to the objects itself.


C#

According to the Jon Skeet answer here, operator + is not even overloaded for the string class – akin to Java, this is just convenience generated by the compiler, thanks to both static and strong typing.


Perl

As the perldata explains,

Perl has three built-in data types: scalars, arrays of scalars, and associative arrays of scalars, known as “hashes”. A scalar is a single string (of any size, limited only by the available memory), number, or a reference to something (which will be discussed in perlref). Normal arrays are ordered lists of scalars indexed by number, starting with 0. Hashes are unordered collections of scalar values indexed by their associated string key.

Perl however does not have a separate data type for numbers, booleans, strings, nulls, undefineds, references to other objects etc – it just has one type for these all, the scalar type; 0 is a scalar value as much as is “0”. A scalar variable that was set as a string can really change into a number, and from there on behave differently from “just a string”, if it is accessed in a numerical context. The scalar can hold anything in Perl, it is as much the object as it exists in the system. whereas in Python the names just refers to the objects, in Perl the scalar values in the names are changeable objects. Furthermore, the Object Oriented Type system is glued on top of this: there are just 3 datatypes in perl – scalars, lists and hashes. A user defined object in Perl is a reference (that is a pointer to any of the 3 previous) blessed to a package – you can take any such value and bless it to any class at any instant you want.

Perl even allows you to change the classes of values at whim – this is not possible in Python where to create a value of some class you need to explicitly construct the value belonging to that class with object.__new__ or similar. In Python you cannot really change the essence of the object after the creation, in Perl you can do much anything:

package Foo;
package Bar;

my $val = 42;
# $val is now a scalar value set from double
bless \$val, Foo;
# all references to $val now belong to class Foo
my $obj = \$val;
# now $obj refers to the SV stored in $val
# thus this prints: Foo=SCALAR(0x1c7d8c8)
print \$val, "\n"; 
# all references to $val now belong to class Bar
bless \$val, Bar;
# thus this prints Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# we change the value stored in $val from number to a string
$val = 'abc';
# yet still the SV is blessed: Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# and on the course, the $obj now refers to a "Bar" even though
# at the time of copying it did refer to a "Foo".
print $obj, "\n";

thus the type identity is weakly bound to the variable, and it can be changed through any reference on the fly. In fact, if you do

my $another = $val;

\$another does not have the class identity, even though \$val will still give the blessed reference.


TL;DR

There are much more about weak typing to Perl than just automatic coercions, and it is more about that the types of the values themselves are not set into stone, unlike the Python which is dynamically yet very strongly typed language. That python gives TypeError on 1 + "1" is an indication that the language is strongly typed, even though the contrary one of doing something useful, as in Java or C# does not preclude them being strongly typed languages.


回答 7

正如许多其他人所表示的那样,“强”键入与“弱”键入的整个概念都是有问题的。

作为一个原型,Smalltalk是非常强类型的- 如果两个对象之间的操作不兼容,它将始终引发异常。但是,我怀疑此列表中很少有人将Smalltalk称为强类型语言,因为它是动态类型。

我发现“静态”与“动态”打字的概念比“强”与“弱”的打字更有用。静态类型的语言具有在编译时确定的所有类型,否则程序员必须明确声明。

与动态类型语言相反,后者是在运行时执行键入的。这通常是多态语言的要求,因此程序员不必事先确定关于两个对象之间的操作是否合法的决定。

在多态,动态类型的语言(如Smalltalk和Ruby)中,将“类型”视为“符合协议”更为有用。如果一个对象遵循与另一个对象相同的协议(即使两个对象不共享任何继承,混合或其他伏都教),则在运行系统中它们被视为相同的“类型”。更正确地说,此类系统中的对象是自治的,并且可以决定响应任何引用特定参数的特定消息是否有意义。

是否需要一个对象,该对象可以使用描述蓝色的对象参数对消息“ +”做出有意义的响应?您可以在动态类型的语言中执行此操作,但是在静态类型的语言中则很麻烦。

As many others have expressed, the entire notion of “strong” vs “weak” typing is problematic.

As a archetype, Smalltalk is very strongly typed — it will always raise an exception if an operation between two objects is incompatible. However, I suspect few on this list would call Smalltalk a strongly-typed language, because it is dynamically typed.

I find the notion of “static” versus “dynamic” typing more useful than “strong” versus “weak.” A statically-typed language has all the types figured out at compile-time, and the programmer has to explicitly declare if otherwise.

Contrast with a dynamically-typed language, where typing is performed at run-time. This is typically a requirement for polymorphic languages, so that decisions about whether an operation between two objects is legal does not have to be decided by the programmer in advance.

In polymorphic, dynamically-typed languages (like Smalltalk and Ruby), it’s more useful to think of a “type” as a “conformance to protocol.” If an object obeys a protocol the same way another object does — even if the two objects do not share any inheritance or mixins or other voodoo — they are considered the same “type” by the run-time system. More correctly, an object in such systems is autonomous, and can decide if it makes sense to respond to any particular message referring to any particular argument.

Want an object that can make some meaningful response to the message “+” with an object argument that describes the colour blue? You can do that in dynamically-typed languages, but it is a pain in statically-typed languages.


回答 8

我喜欢@Eric Lippert的答案,但要解决这个问题-强类型语言通常在程序的每个点都具有变量类型的显式知识。弱类型语言不会,因此它们可以尝试执行某种特定类型可能无法执行的操作。它认为最简单的方法是在函数中。C ++:

void func(string a) {...}

a已知该变量的类型为字符串,任何不兼容的操作都将在编译时捕获。

Python:

def func(a)
  ...

该变量a可以是任何东西,我们可以拥有调用无效方法的代码,该方法只会在运行时被捕获。

I like @Eric Lippert’s answer, but to address the question – strongly typed languages typically have explicit knowledge of the types of variables at each point of the program. Weakly typed languages do not, so they can attempt to perform an operation that may not be possible for a particular type. It think the easiest way to see this is in a function. C++:

void func(string a) {...}

The variable a is known to be of type string and any incompatible operation will be caught at compile time.

Python:

def func(a)
  ...

The variable a could be anything and we can have code that calls an invalid method, which will only get caught at runtime.


为什么Java虚拟机中没有GIL?为什么Python需要这么糟糕?

问题:为什么Java虚拟机中没有GIL?为什么Python需要这么糟糕?

我希望有人能够提供一些有关Java虚拟机的根本差异的见解,从而使Java虚拟机能够很好地实现线程而无需使用全局解释器锁(GIL),而Python则需要这样做。

I’m hoping someone can provide some insight as to what’s fundamentally different about the Java Virtual Machine that allows it to implement threads nicely without the need for a Global Interpreter Lock (GIL), while Python necessitates such an evil.


回答 0

Python(该语言)不需要GIL(这就是为什么它可以在JVM [Jython]和.NET [IronPython]上完美实现的原因,并且这些实现可以自由地使用多线程)。CPython(流行的实现)一直使用GIL来简化编码(尤其是垃圾收集机制的编码)和非线程安全的C编码库的集成(过去有很多这样的库); -)。

空载燕子项目,其它的宏伟目标中,做计划一个GIL -免费的虚拟机为Python -引用该网站,“此外,我们打算移除GIL和修复在Python多线程的状态,我们认为,这是可以通过实施更复杂的GC系统来实现,例如IBM的Recycler(Bacon等,2001)。”

Python (the language) doesn’t need a GIL (which is why it can perfectly be implemented on JVM [Jython] and .NET [IronPython], and those implementations multithread freely). CPython (the popular implementation) has always used a GIL for ease of coding (esp. the coding of the garbage collection mechanisms) and of integration of non-thread-safe C-coded libraries (there used to be a ton of those around;-).

The Unladen Swallow project, among other ambitious goals, does plan a GIL-free virtual machine for Python — to quote that site, “In addition, we intend to remove the GIL and fix the state of multithreading in Python. We believe this is possible through the implementation of a more sophisticated GC system, something like IBM’s Recycler (Bacon et al, 2001).”


回答 1

JVM(至少是热点)的确与“ GIL”具有类似的概念,它的锁定粒度要好得多,其中大部分来自更先进的GC热点。

在CPython中,这是一个很大的锁(可能并非如此,但对于参数而言已经足够好了),在JVM中,它的使用范围更广,涉及不同的概念。

例如,查看热点代码中的vm / runtime / safepoint.hpp,这实际上是一个障碍。一旦到达安全点,整个VM就Java代码而言都已停止,就像python VM在GIL处停止一样。

在Java世界中,此类VM暂停事件被称为“世界停止”,在这些时候,只有绑定到某些条件的本机代码可以自由运行,其余的VM已停止。

另外,由于Java中缺少粗略的锁,因此JNI的编写变得更加困难,因为JVM对其FFI调用的环境的保证较少,这是cpython相当容易的事情之一(尽管不像使用ctypes那样容易)。

The JVM (at least hotspot) does have a similar concept to the “GIL”, it’s just much finer in its lock granularity, most of this comes from the GC’s in hotspot which are more advanced.

In CPython it’s one big lock (probably not that true, but good enough for arguments sake), in the JVM it’s more spread about with different concepts depending on where it is used.

Take a look at, for example, vm/runtime/safepoint.hpp in the hotspot code, which is effectively a barrier. Once at a safepoint the entire VM has stopped with regard to java code, much like the python VM stops at the GIL.

In the Java world such VM pausing events are known as “stop-the-world”, at these points only native code that is bound to certain criteria is free running, the rest of the VM has been stopped.

Also the lack of a coarse lock in java makes JNI much more difficult to write, as the JVM makes less guarantees about its environment for FFI calls, one of the things that cpython makes fairly easy (although not as easy as using ctypes).


回答 2

以下是此博客文章http://www.grouplens.org/node/244中的注释,它暗示了为什么为IronPython或Jython取消GIL这么容易的原因,这是CPython使用引用计数,而另外2个VM具有垃圾回收器。

为什么我不知道这是为什么的确切机制,但这听起来似乎是合理的原因。

There is a comment down below in this blog post http://www.grouplens.org/node/244 that hints at the reason why it was so easy dispense with a GIL for IronPython or Jython, it is that CPython uses reference counting whereas the other 2 VMs have garbage collectors.

The exact mechanics of why this is so I don’t get, but it does sounds like a plausible reason.


回答 3

在此链接中,它们具有以下解释:

…“解释器的部分不是线程安全的,尽管主要是因为通过大量使用锁使它们全部成为线程安全,这会极大地减慢单线程()。这似乎与使用引用计数(JVM)的CPython垃圾收集器有关。而CLR不需要,因此不需要每次都锁定/释放引用计数。但是,即使有人想到了可接受的解决方案并实施了该解决方案,第三方库仍然会遇到同样的问题。”

In this link they have the following explanation:

… “Parts of the Interpreter aren’t threadsafe, though mostly because making them all threadsafe by massive lock usage would slow single-threaded extremely (source). This seems to be related to the CPython garbage collector using reference counting (the JVM and CLR don’t, and therefore don’t need to lock/release a reference count every time). But even if someone thought of an acceptable solution and implemented it, third party libraries would still have the same problems.”


回答 4

Python缺少jit / aot,并且它在多线程处理器上编写的时间框架不存在。另外,您可以重新编译缺少GIL的Julia lang中的所有内容,并提高Python代码的速度。而且Jython有点烂,它比Cpython和Java慢。如果您想使用Python并考虑使用并行插件,则不会立即提高速度,但是可以使用合适的插件进行并行编程。

Python lacks jit/aot and the time frame it was written at multithreaded processors didn’t exist. Alternatively you could recompile everything in Julia lang which lacks GIL and gain some speed boost on your Python code. Also Jython kind of sucks it’s slower than Cpython and Java. If you want to stick to Python consider using parallel plugins, you won’t gain an instant speed boost but you can do parallel programming with the right plugin.


Botframework-sdk-BOT框架为构建对话应用程序提供了最全面的体验

BOT框架为构建对话应用程序提供了最全面的体验

使用Bot Framework SDK,开发人员可以构建与自由格式或具有引导交互的机器人进行交互,包括使用包含文本、图像和操作按钮的简单文本或富卡

开发人员可以使用他们喜欢的编程语言(包括C#、JS、Python和Java)建模和构建复杂的对话,也可以使用Bot Framework Composer,这是一个开源的可视化创作画布,供开发人员和多学科团队设计和构建对话体验,包括语言理解、QNA Maker和BOT回复的复杂组合(Language Generation)

签出 Bot Framework ecosystem部分,了解与Bot Framework SDK相关的其他工具和服务的更多信息

快速链接

|Bot Framework Composer|C# Repo|JS Repo|Python Repo|Java Repo|BF CLI|

BOT框架SDK v4

Bot Framework SDK v4是一个open source SDK使开发人员能够使用他们最喜欢的编程语言建模和构建复杂的对话

C# JS python Java语言
稳定释放 packages packages packages packages
文档 docs docs docs docs
样本 .NET CoreWebAPI Node.jsTypeScriptes6 Python Java

通道和适配器

有两种方式可以将你的机器人连接到客户端体验:

  • Azure Bot服务频道-通过Azure Bot服务提供语言和SDK独立支持
  • BOT框架SDK适配器-每种语言适配器组件
客户端 蔚蓝通道 C#适配器 JS适配器 Python适配器
微软团队 Azure
直达线路 Azure
网络聊天 Azure Botkit
Skype Azure
电子邮件 Azure
Facebook Azure SDK Botkit
松弛 Azure SDK Botkit SDK
Kik Azure
电报 Azure
线路 Azure
GroupMe Azure
Twilio(短信) Azure SDK Botkit
Alexa技能 Community Community
谷歌行动 Community Community
Google Hangout Botkit
WebEx SDK Botkit
WhatsApp(Infobip) Community
缩放 Community
RingCentral Community
科尔塔纳 Azure
控制台 Community

社区开源项目

以下开放源码社区提供了各种组件来扩展您的bot应用程序,包括适配器、识别器、对话框和中间件

C# JavaScript python Java语言
Bot Framework Community C# JavaScript Python Java
Botkit JavaScript

问题和帮助

如果您对Bot Framework SDK或使用Azure Bot服务有任何疑问,我们鼓励您联系社区和Azure Bot服务开发团队寻求帮助

查看所有可用的支持选项here

问题和功能请求

我们在不同的位置跟踪Bot Framework SDK、工具和Azure Bot服务的功能问题和功能需求。如果您发现问题或有功能请求,请将问题提交到以下存储库

项目 描述 链接
SDK v4.NET 用于.NET、连接器、中间件、对话框、提示、Luis和QNA的核心bot运行时 File an issue
SDK v4 JavaScript 用于TypeScript/Javascript、连接器、中间件、对话框、提示符、Luis和QNA的核心bot运行时 File an issue
SDK v4 Python Python、连接器、中间件、对话框、提示、Luis和QNA的核心bot运行时 File an issue
SDK v4 Java 面向Java、连接器、中间件、对话框、提示、Luis和QNA的核心bot运行时 File an issue
BOT框架组合器 BOT框架合成器电子和Web应用程序 File an issue
BOT框架CLI BOT框架cli工具 File an issue
网络聊天 BOT框架网络聊天工具 File an issue

以前的版本

BOT框架生态系统

BOT框架组合器

Bot Framework Composer是一个集成开发工具,供开发人员和多学科团队使用Microsoft Bot Framework构建机器人和对话体验。在此工具中,您将找到构建复杂对话体验所需的一切

博基特

Botkit是一个开发人员工具和SDK,用于为主要消息传递平台构建聊天机器人、应用程序和自定义集成。僵尸机器人hear()触发器,ask()问题和say()回复。开发人员可以使用此语法构建对话框-现在可与最新版本的Bot Framework SDK交叉兼容

此外,botkit还附带了6个平台适配器,允许Javascript bot应用程序直接与消息传递平台通信:SlackWebex TeamsGoogle HangoutsFacebook MessengerTwilio,以及Web chat

botkit是Microsoft Bot Framework的一部分,在MIT Open Source license

BOT框架虚拟助手解决方案加速器

这个Bot Framework Solutions repository是世界上最大的Virtual Assistant Solution Accelerator,它提供了一组模板、解决方案加速器和技能,以帮助构建复杂的对话体验

  • Virtual Assistant.客户和合作伙伴非常需要为他们的品牌量身定做一个对话助手,为他们的用户量身定做,并且在各种画布和设备上都可以使用。

    这汇集了所有支持组件,并极大地简化了新BOT项目的创建,包括:基本对话意图、调度集成、QNA Maker、Application Insight和自动化部署

  • Skills.一个可重复使用的会话技能构建块库,使您可以向Bot添加功能。我们目前提供:日历,电子邮件,任务,兴趣点,汽车,天气和新闻技能。技能包括以源代码形式交付的Luis模型、对话框和集成代码,以便根据需要进行自定义和扩展
  • Analytics.使用Bot Framework Analytics解决方案获得对您的机器人的健康状况和行为的重要见解,其中包括:示例Application Insights查询和Power BI仪表板,以全面了解您的机器人与用户的对话

Azure Bot服务

Azure Bot服务使您能够托管完全拥有和控制您的数据的企业级智能机器人。开发者可以在Skype、微软团队、Cortana、网络聊天等平台上注册机器人并将其连接到用户。[Docs]

  • 直通JS客户端:如果您希望在Azure Bot服务中使用Direct Line频道,并且没有使用Webchat客户端,则可以在您的自定义应用程序中使用Direct Line JS客户端。[Readme]

  • 直接线路语音信道:我们正在将Bot框架和Microsoft的语音服务结合在一起,以提供一个通道,支持从客户端到BOT应用程序的双向流式语音和文本。若要注册,请向您的Azure Bot服务添加“Direct Line Speech”频道
  • 为您的Bot-Direct Line App服务扩展提供更好的隔离:Direct Line App Service Extension可以作为VNET的一部分进行部署,使IT管理员能够更好地控制会话流量,并由于减少了跳数而改善了会话延迟。单击此处开始使用Direct Line App Service Extension。VNET允许您在Azure中创建自己的私有空间,并且对您的云网络至关重要,因为它提供隔离、分段和其他主要优势

BOT框架仿真器

这个Bot Framework Emulator是一个跨平台的桌面应用程序,允许bot开发人员测试和调试使用Bot Framework SDK构建的bot。可以使用Bot Framework Emulator测试在计算机上本地运行的Bot或连接到远程运行的Bot。[Download latest|Docs]

BOT框架网络聊天

机器人框架Web Chat是Azure Bot服务的一个高度可自定义的基于Web的客户端聊天控件,它为用户提供了在网页中直接与你的机器人交互的功能。[Stable release|Docs|Samples]

BOT框架CLI

Bot Framework CLI工具托管open source跨平台Bot Framework CLI工具,旨在支持构建强大的端到端开发工作流。Bot Framework CLI工具取代了legacy standalone tools用于管理僵尸程序和相关服务。BF CLI将跨平台工具集合聚合到一个紧密一致的界面中

相关服务

语言理解

一种基于机器学习的服务,用于构建自然语言体验。快速创建可持续改进的企业就绪型定制模型。语言理解服务(Language Underming Service,Luis)允许您的应用程序用他们自己的话来理解他们想要的东西。[Docs|Add language understanding to your bot]

QNA制造商

QnA Maker是一种基于云的API服务,可在您的数据上创建会话问答层。使用QNA Maker,您可以在几分钟内根据FAQ URL、结构化文档、产品手册或编辑内容构建、培训和发布一个简单的问答机器人。[Docs|Add qnamaker to your bot]

派单

调度工具允许您构建语言模型,允许您在不同的组件(如QNA、Luis和自定义代码)之间进行调度。[Readme]

语音服务

语音服务将音频转换为文本,通过统一的语音服务进行语音翻译和文本到语音的转换。有了语音服务,你可以将语音集成到你的机器人中,创建自定义唤醒词,并用多种语言创作。[Docs]

适配卡

Adaptive Cards是一个开放标准,供开发人员以通用且一致的方式交换卡内容,并被Bot Framework开发人员用来创建出色的跨通道转换体验

  • 开放式框架,原生性能-简单的开放式卡格式支持共享工具的生态系统、应用程序之间的无缝集成以及任何设备上的本机跨平台性能
  • 从第一天起启用语音-我们生活在一个令人兴奋的时代,在这个时代,用户可以与他们的设备交谈。适配卡拥抱了这一新世界,并从头开始设计以支持这些新体验

贡献

请参阅我们的contributing guidelines

报告安全问题

安全问题和错误应通过电子邮件私下报告给Microsoft安全响应中心(MSRC),地址为secure@microsoft.com您应该会在24小时内收到回复。如果您由于某些原因没有收到您的邮件,请通过电子邮件跟进,以确保我们收到您的原始邮件。更多信息,包括MSRC PGP密钥,可以在Security TechCenter

版权所有(C)Microsoft Corporation。版权所有

编译语言与口译语言

问题:编译语言与口译语言

我正在尝试更好地理解它们之间的区别。我在网上找到了很多解释,但是它们倾向于抽象的差异,而不是实际的含义。

我的大部分编程经验都来自CPython(动态的,解释的)和Java(静态的,编译的)。但是,我知道还有其他种类的解释和编译语言。除了可以从以编译语言编写的程序中分发可执行文件这一事实之外,每种类型是否都有优点/缺点?通常,我听到人们争辩说解释语言可以交互使用,但是我相信编译语言也可以具有交互实现,对吗?

I’m trying to get a better understanding of the difference. I’ve found a lot of explanations online, but they tend towards the abstract differences rather than the practical implications.

Most of my programming experiences has been with CPython (dynamic, interpreted), and Java (static, compiled). However, I understand that there are other kinds of interpreted and compiled languages. Aside from the fact that executable files can be distributed from programs written in compiled languages, are there any advantages/disadvantages to each type? Oftentimes, I hear people arguing that interpreted languages can be used interactively, but I believe that compiled languages can have interactive implementations as well, correct?


回答 0

编译语言是一种程序,一旦编译,该程序就会在目标计算机的指令中表示出来。例如,源代码中的加号“ +”操作可以直接转换为机器代码中的“ ADD”指令。

一种解释语言是其中所述指令不被目标机器直接执行,而是读取和执行通过一些其它方案(其通常写入本机机器的语言)。例如,解释器将在运行时识别相同的“ +”操作,然后使用适当的参数调用其自己的“ add(a,b)”函数,然后执行机器代码“ ADD”指令。

您可以使用解释语言或编译语言来做任何事情,反之亦然-它们都是图灵完整的。但是,两者在实现和使用上都有优点和缺点。

我将完全概括(纯粹主义者请原谅!),但是,粗略地讲,这是编译语言的优点:

  • 通过直接使用目标计算机的本机代码来提高性能
  • 在编译阶段进行功能强大的优化的机会

以下是解释语言的优点:

  • 易于实现(编写好的编译器非常困难!)
  • 无需运行编译阶段:可以“即时”直接执行代码
  • 可以更方便地使用动态语言

请注意,诸如字节码编译之类的现代技术增加了一些额外的复杂性-此处发生的是,编译器针对的是“虚拟机”,该“虚拟机”与底层硬件不同。然后可以在以后的阶段再次编译这些虚拟机指令,以获取本机代码(例如,由Java JVM JIT编译器完成)。

A compiled language is one where the program, once compiled, is expressed in the instructions of the target machine. For example, an addition “+” operation in your source code could be translated directly to the “ADD” instruction in machine code.

An interpreted language is one where the instructions are not directly executed by the target machine, but instead read and executed by some other program (which normally is written in the language of the native machine). For example, the same “+” operation would be recognised by the interpreter at run time, which would then call its own “add(a,b)” function with the appropriate arguments, which would then execute the machine code “ADD” instruction.

You can do anything that you can do in an interpreted language in a compiled language and vice-versa – they are both Turing complete. Both however have advantages and disadvantages for implementation and use.

I’m going to completely generalise (purists forgive me!) but, roughly, here are the advantages of compiled languages:

  • Faster performance by directly using the native code of the target machine
  • Opportunity to apply quite powerful optimisations during the compile stage

And here are the advantages of interpreted languages:

  • Easier to implement (writing good compilers is very hard!!)
  • No need to run a compilation stage: can execute code directly “on the fly”
  • Can be more convenient for dynamic languages

Note that modern techniques such as bytecode compilation add some extra complexity – what happens here is that the compiler targets a “virtual machine” which is not the same as the underlying hardware. These virtual machine instructions can then be compiled again at a later stage to get native code (e.g. as done by the Java JVM JIT compiler).


回答 1

语言本身既不会编译也不会解释,而仅是语言的特定实现。Java是一个完美的例子。有一个基于字节码的平台(JVM),一个本机编译器(gcj)和一个Java超集的插入器(bsh)。那么,Java现在是什么?字节码编译,本机编译还是解释?

Scala,Haskell或Ocaml是经过编译和解释的其他语言。这些语言中的每一种都有一个交互式解释器,以及用于字节码或本机代码的编译器。

因此,通常通过“编译”和“解释”对语言进行分类没有多大意义。

A language itself is neither compiled nor interpreted, only a specific implementation of a language is. Java is a perfect example. There is a bytecode-based platform (the JVM), a native compiler (gcj) and an interpeter for a superset of Java (bsh). So what is Java now? Bytecode-compiled, native-compiled or interpreted?

Other languages, which are compiled as well as interpreted, are Scala, Haskell or Ocaml. Each of these languages has an interactive interpreter, as well as a compiler to byte-code or native machine code.

So generally categorizing languages by “compiled” and “interpreted” doesn’t make much sense.


回答 2

开始思考:过去的爆炸

很久很久以前,曾经有计算解释器和编译器。各种大惊小怪的结果使一个人的优胜劣汰。普遍的观点在当时是沿着线的东西:

  • 口译员:快速开发(编辑和运行)。执行速度很慢,因为每个语句每次执行时都必须将其解释为机器代码(想想这对于执行数千次循环意味着什么)。
  • 编译器:开发缓慢(编辑,编译,链接和运行。编译/链接步骤可能需要花费大量时间)。快速执行。整个程序已经在本机代码中。

在解释的程序和编译的程序之间存在一个或两个数量级的运行时性能差异。其他区别点,例如代码的运行时可变性,也引起了一些关注,但主要区别在于运行时性能问题。

如今,景观已发展到某种程度,以至于汇编/解释的区别几乎是无关紧要的。许多编译语言要求运行时服务不是完全基于机器代码的。而且,大多数解释语言在执行之前都会被“编译”为字节码。字节码解释器可能非常高效,并且从执行速度的角度来看,可以与某些编译器生成的代码相媲美。

经典的区别是,编译器使用某种运行时系统生成本机代码,解释器读取源代码并动态生成代码。如今,几乎没有经典的解释器了-几乎所有经典的解释器都编译成字节码(或其他半编译状态),然后在虚拟“机器”上运行。

Start thinking in terms of a: blast from the past

Once upon a time, long long ago, there lived in the land of computing interpreters and compilers. All kinds of fuss ensued over the merits of one over the other. The general opinion at that time was something along the lines of:

  • Interpreter: Fast to develop (edit and run). Slow to execute because each statement had to be interpreted into machine code every time it was executed (think of what this meant for a loop executed thousands of times).
  • Compiler: Slow to develop (edit, compile, link and run. The compile/link steps could take serious time). Fast to execute. The whole program was already in native machine code.

A one or two order of magnitude difference in the runtime performance existed between an interpreted program and a compiled program. Other distinguishing points, run-time mutability of the code for example, were also of some interest but the major distinction revolved around the run-time performance issues.

Today the landscape has evolved to such an extent that the compiled/interpreted distinction is pretty much irrelevant. Many compiled languages call upon run-time services that are not completely machine code based. Also, most interpreted languages are “compiled” into byte-code before execution. Byte-code interpreters can be very efficient and rival some compiler generated code from an execution speed point of view.

The classic difference is that compilers generated native machine code, interpreters read source code and generated machine code on the fly using some sort of run-time system. Today there are very few classic interpreters left – almost all of them compile into byte-code (or some other semi-compiled state) which then runs on a virtual “machine”.


回答 3

极端简单的情况:

  • 编译器将生成目标计算机的本机可执行文件格式的二进制可执行文件。该二进制文件包含除系统库以外的所有必需资源。它无需任何准备和处理即可运行,并且像闪电一样运行,因为该代码是目标计算机上CPU的本机代码。

  • 解释器将在循环中向用户显示提示,用户可以在其中输入语句或代码,并且在命中RUN或等效命令时,解释器将检查,扫描,解析并以解释方式执行每一行,直到程序运行至停止点或错误为止。因为每一行都是独立处理的,并且解释器不会从以前的行中“学到”任何东西,所以每行每次都需要将人类可读的语言转换为机器指令,所以这太慢了。从好的方面来说,用户可以通过各种方式检查程序并与之交互:更改变量,更改代码,在跟踪或调试模式下运行……等等。

顺便说一句,让我解释一下生活不再那么简单了。例如,

  • 许多解释器会预编译给出的代码,因此不必一次又一次地重复翻译步骤。
  • 一些编译器不编译为特定于CPU的机器指令,而是编译为字节码,这是一种虚拟机器的人造机器代码。这使编译后的程序更具可移植性,但是在每个目标系统上都需要一个字节码解释器。
  • 字节码解释器(我现在在这里看着Java)倾向于在执行之前为目标部分的CPU重新编译它们获得的字节码(称为JIT)。为了节省时间,通常只对经常运行的代码(热点)执行此操作。
  • 一些看起来和行为像解释器的系统(例如,Clojure)会立即编译它们获得的任何代码,但允许以交互方式访问程序环境。从根本上来说,这就是二进制编译器为解释器带来的便利。
  • 一些编译器并没有真正编译,只是预消化和压缩代码。我听说前阵子就是Perl的工作方式。因此,有时编译器只是在做一些工作,而且大部分仍在解释中。

最终,如今,解释与编译是一个折衷方案,花费(一次)编译的时间通常会因更好的运行时性能而获得回报,但是解释性环境为交互提供了更多机会。编译与解释主要是关于如何“理解”程序的工作如何在不同的过程之间进行划分的问题,而如今,由于语言和产品试图同时兼顾两者的优势,这条线有些模糊。

The extreme and simple cases:

  • A compiler will produce a binary executable in the target machine’s native executable format. This binary file contains all required resources except for system libraries; it’s ready to run with no further preparation and processing and it runs like lightning because the code is the native code for the CPU on the target machine.

  • An interpreter will present the user with a prompt in a loop where he can enter statements or code, and upon hitting RUN or the equivalent the interpreter will examine, scan, parse and interpretatively execute each line until the program runs to a stopping point or an error. Because each line is treated on its own and the interpreter doesn’t “learn” anything from having seen the line before, the effort of converting human-readable language to machine instructions is incurred every time for every line, so it’s dog slow. On the bright side, the user can inspect and otherwise interact with his program in all kinds of ways: Changing variables, changing code, running in trace or debug modes… whatever.

With those out of the way, let me explain that life ain’t so simple any more. For instance,

  • Many interpreters will pre-compile the code they’re given so the translation step doesn’t have to be repeated again and again.
  • Some compilers compile not to CPU-specific machine instructions but to bytecode, a kind of artificial machine code for a ficticious machine. This makes the compiled program a bit more portable, but requires a bytecode interpreter on every target system.
  • The bytecode interpreters (I’m looking at Java here) recently tend to re-compile the bytecode they get for the CPU of the target section just before execution (called JIT). To save time, this is often only done for code that runs often (hotspots).
  • Some systems that look and act like interpreters (Clojure, for instance) compile any code they get, immediately, but allow interactive access to the program’s environment. That’s basically the convenience of interpreters with the speed of binary compilation.
  • Some compilers don’t really compile, they just pre-digest and compress code. I heard a while back that’s how Perl works. So sometimes the compiler is just doing a bit of the work and most of it is still interpretation.

In the end, these days, interpreting vs. compiling is a trade-off, with time spent (once) compiling often being rewarded by better runtime performance, but an interpretative environment giving more opportunities for interaction. Compiling vs. interpreting is mostly a matter of how the work of “understanding” the program is divided up between different processes, and the line is a bit blurry these days as languages and products try to offer the best of both worlds.


回答 4

来自http://www.quora.com/What-is-the-difference-between-compiled-and-interpreted-programming-languages

这没有什么区别,因为“编译程序设计语言”和“解释程序设计语言”不是有意义的概念。任何编程语言(实际上是任何一种编程语言)都可以解释或编译。因此,解释和编译是实现技术,而不是语言的属性。

解释是一种技术,通过该技术,另一个程序(解释器)代表正在解释的程序执行操作以使其运行。如果您可以想象阅读程序并按照程序说的做一步一步,例如在草稿纸上说,那也是解释器的工作。解释程序的常见原因是解释器相对容易编写。另一个原因是,解释器可以监视程序在运行时试图执行的操作,以执行安全性策略。

编译是一种技术,通过该技术可以将用一种语言(“源语言”)编写的程序转换为另一种语言(“目标语言”)的程序,这希望与原始程序具有相同的含义。在进行翻译时,编译器通常还会尝试以使目标程序更快的方式(不改变其含义!)对程序进行转换。编译程序的一个常见原因是,有一种很好的方法可以以目标语言快速运行程序,而无需一路解释源语言。

根据上述定义,您可能已经猜到这两种实现技术不是互斥的,甚至可能是互补的。传统上,编译器的目标语言是机器代码或类似的东西,它表示特定计算机CPU可以理解的任何数量的编程语言。然后,机器代码将“运行在金属上”(尽管如果看起来足够接近,人们可能会发现“金属”的工作原理很像解释器)。但是,如今,使用编译器生成要解释的目标代码已经非常普遍了,例如,Java曾经(有时仍然这样做)就是这种方式。有些编译器会将其他语言翻译成JavaScript,然后通常在网络浏览器中运行,这些浏览器可能会解释JavaScript,或将其编译为虚拟机或本机代码。我们还提供了机器码解释器,可用于在另一种机器上模拟一种硬件。或者,可以使用编译器生成目标代码,然后该目标代码将成为另一编译器的源代码,后者甚至可以及时在内存中编译代码以使其运行,然后依次运行。。。你明白了。有很多方法可以组合这些概念。

From http://www.quora.com/What-is-the-difference-between-compiled-and-interpreted-programming-languages

There is no difference, because “compiled programming language” and “interpreted programming language” aren’t meaningful concepts. Any programming language, and I really mean any, can be interpreted or compiled. Thus, interpretation and compilation are implementation techniques, not attributes of languages.

Interpretation is a technique whereby another program, the interpreter, performs operations on behalf of the program being interpreted in order to run it. If you can imagine reading a program and doing what it says to do step-by-step, say on a piece of scratch paper, that’s just what an interpreter does as well. A common reason to interpret a program is that interpreters are relatively easy to write. Another reason is that an interpreter can monitor what a program tries to do as it runs, to enforce a policy, say, for security.

Compilation is a technique whereby a program written in one language (the “source language”) is translated into a program in another language (the “object language”), which hopefully means the same thing as the original program. While doing the translation, it is common for the compiler to also try to transform the program in ways that will make the object program faster (without changing its meaning!). A common reason to compile a program is that there’s some good way to run programs in the object language quickly and without the overhead of interpreting the source language along the way.

You may have guessed, based on the above definitions, that these two implementation techniques are not mutually exclusive, and may even be complementary. Traditionally, the object language of a compiler was machine code or something similar, which refers to any number of programming languages understood by particular computer CPUs. The machine code would then run “on the metal” (though one might see, if one looks closely enough, that the “metal” works a lot like an interpreter). Today, however, it’s very common to use a compiler to generate object code that is meant to be interpreted—for example, this is how Java used to (and sometimes still does) work. There are compilers that translate other languages to JavaScript, which is then often run in a web browser, which might interpret the JavaScript, or compile it a virtual machine or native code. We also have interpreters for machine code, which can be used to emulate one kind of hardware on another. Or, one might use a compiler to generate object code that is then the source code for another compiler, which might even compile code in memory just in time for it to run, which in turn . . . you get the idea. There are many ways to combine these concepts.


回答 5

与已编译的源代码相比,已解释的源代码的最大优势是PORTABILITY

如果您的源代码已编译,则需要为要在其上运行程序的每种类型的处理器和/或平台编译一个不同的可执行文件(例如,一个用于Windows x86,一个用于Windows x64,一个用于Linux x64,等等。上)。此外,除非您的代码完全符合标准并且不使用任何平台特定的功能/库,否则您实际上将需要编写和维护多个代码库!

如果您的源代码被解释,则只需编写一次即可,并且可以由任何平台上的适当解释器来解释和执行它!它是便携式的!需要注意的是一个解释器本身是一个可执行程序编写和编译为特定平台。

编译后代码的一个优点是,它向最终用户隐藏了源代码(可能是知识产权),因为您部署了晦涩的二进制可执行文件,而不是部署原始的人类可读源代码。

The biggest advantage of interpreted source code over compiled source code is PORTABILITY.

If your source code is compiled, you need to compile a different executable for each type of processor and/or platform that you want your program to run on (e.g. one for Windows x86, one for Windows x64, one for Linux x64, and so on). Furthermore, unless your code is completely standards compliant and does not use any platform-specific functions/libraries, you will actually need to write and maintain multiple code bases!

If your source code is interpreted, you only need to write it once and it can be interpreted and executed by an appropriate interpreter on any platform! It’s portable! Note that an interpreter itself is an executable program that is written and compiled for a specific platform.

An advantage of compiled code is that it hides the source code from the end user (which might be intellectual property) because instead of deploying the original human-readable source code, you deploy an obscure binary executable file.


回答 6

编译器和解释器完成相同的工作:将编程语言翻译为另一种编程语言,通常更接近硬件,通常指导可执行的机器代码。

传统上,“编译”是指这种翻译一次完成,由开发人员完成,然后将生成的可执行文件分发给用户。纯粹的例子:C ++。编译通常花费很长时间,并尝试进行大量昂贵的优化,以使生成的可执行文件运行更快。最终用户没有工具和知识来自己编译东西,并且可执行文件通常必须在各种硬件上运行,因此您不能进行许多针对硬件的优化。在开发过程中,单独的编译步骤意味着更长的反馈周期。

传统上,“已解释”是指当用户要运行程序时,翻译是“即时”进行的。纯粹的例子:香草PHP。天真的解释器每次运行时都必须解析和翻译每段代码,这使其非常慢。它无法进行复杂,成本高昂的优化,因为它们所花费的时间比执行所节省的时间还要长。但是它可以充分利用其运行的硬件的功能。缺少单独的编译步骤可减少开发过程中的反馈时间。

但是如今,“编译与解释”已不是一个黑白问题,介于两者之间。天真的,简单的口译员已经绝迹了。许多语言使用两步过程,其中将高级代码转换为平台无关的字节码(解释起来更快)。然后,您将拥有“及时编译器”,每个程序运行一次最多编译一次代码,有时缓存结果,甚至可以明智地决定解释很少运行的代码,并对运行频繁的代码进行强大的优化。在开发过程中,调试器甚至可以针对传统编译语言在正在运行的程序中切换代码。

A compiler and an interpreter do the same job: translating a programming language to another pgoramming language, usually closer to the hardware, often direct executable machine code.

Traditionally, “compiled” means that this translation happens all in one go, is done by a developer, and the resulting executable is distributed to users. Pure example: C++. Compilation usually takes pretty long and tries to do lots of expensive optmization so that the resulting executable runs faster. End users don’t have the tools and knowledge to compile stuff themselves, and the executable often has to run on a variety of hardware, so you can’t do many hardware-specific optimizations. During development, the separate compilation step means a longer feedback cycle.

Traditionally, “interpreted” means that the translation happens “on the fly”, when the user wants to run the program. Pure example: vanilla PHP. A naive interpreter has to parse and translate every piece of code every time it runs, which makes it very slow. It can’t do complex, costly optimizations because they’d take longer than the time saved in execution. But it can fully use the capabilities of the hardware it runs on. The lack of a separrate compilation step reduces feedback time during development.

But nowadays “compiled vs. interpreted” is not a black-or-white issue, there are shades in between. Naive, simple interpreters are pretty much extinct. Many languages use a two-step process where the high-level code is translated to a platform-independant bytecode (which is much faster to interpret). Then you have “just in time compilers” which compile code at most once per program run, sometimes cache results, and even intelligently decide to interpret code that’s run rarely, and do powerful optimizations for code that runs a lot. During development, debuggers are capable of switching code inside a running program even for traditionally compiled languages.


回答 7

首先,澄清一下,Java不是完全以C ++的方式静态编译和链接的。它被编译成字节码,然后由JVM解释。JVM可以及时对本机语言进行编译,但不必这样做。

更重要的是:我认为互动是主要的实际差异。由于所有内容均已解释,因此您可以摘录一小段代码,然后针对环境的当前状态进行解析和运行。因此,如果您已经执行过初始化变量的代码,则可以访问该变量,等等。它确实可以将其自身用于诸如功能样式之类的事情。

但是,解释会花费很多,尤其是当您拥有一个具有大量引用和上下文的大型系统时。根据定义,这是浪费的,因为可能必须两次解释和优化相同的代码(尽管大多数运行时对此都有一些缓存和优化)。尽管如此,您仍然需要支付运行时成本,并且经常需要运行时环境。您也不太可能看到复杂的过程间优化,因为目前它们的性能还不够互动。

因此,对于那些变化不大的大型系统,对于某些语言而言,预编译和预链接所有内容更有意义,请执行您可以做的所有优化。最终将获得非常精益的运行时,该运行时已针对目标计算机进行了优化。

至于生成可执行文件,与恕我直言无关。您通常可以使用编译语言创建可执行文件。但是,您也可以使用解释语言创建可执行文件,只是解释器和运行时已打包在可执行文件中,并且对您隐藏了。这意味着您通常仍需支付运行时成本(尽管我确信对于某些语言,有一些方法可以将所有内容转换为树可执行文件)。

我不同意所有语言都可以互动。某些语言(例如C)与机器和整个链接结构紧密相关,因此我不确定您是否可以构建有意义的完整交互式版本

First, a clarification, Java is not fully static-compiled and linked in the way C++. It is compiled into bytecode, which is then interpreted by a JVM. The JVM can go and do just-in-time compilation to the native machine language, but doesn’t have to do it.

More to the point: I think interactivity is the main practical difference. Since everything is interpreted, you can take a small excerpt of code, parse and run it against the current state of the environment. Thus, if you had already executed code that initialized a variable, you would have access to that variable, etc. It really lends itself way to things like the functional style.

Interpretation, however, costs a lot, especially when you have a large system with a lot of references and context. By definition, it is wasteful because identical code may have to be interpreted and optimized twice (although most runtimes have some caching and optimizations for that). Still, you pay a runtime cost and often need a runtime environment. You are also less likely to see complex interprocedural optimizations because at present their performance is not sufficiently interactive.

Therefore, for large systems that are not going to change much, and for certain languages, it makes more sense to precompile and prelink everything, do all the optimizations that you can do. This ends up with a very lean runtime that is already optimized for the target machine.

As for generating executbles, that has little to do with it, IMHO. You can often create an executable from a compiled language. But you can also create an executable from an interpreted language, except that the interpreter and runtime is already packaged in the exectuable and hidden from you. This means that you generally still pay the runtime costs (although I am sure that for some language there are ways to translate everything to a tree executable).

I disagree that all languages could be made interactive. Certain languages, like C, are so tied to the machine and the entire link structure that I’m not sure you can build a meaningful fully-fledged interactive version


回答 8

给出实际答案相当困难,因为区别在于语言定义本身。可以为每种编译语言构建解释器,但不可能为每种解释语言构建编译器。语言的形式定义非常重要。从而使理论上的信息学方面的东西更受大学的欢迎。

It’s rather difficult to give a practical answer because the difference is about the language definition itself. It’s possible to build an interpreter for every compiled language, but it’s not possible to build an compiler for every interpreted language. It’s very much about the formal definition of a language. So that theoretical informatics stuff noboby likes at university.


回答 9

Python图书©2015 Imagine Publishing Ltd,仅通过第10页中提到的以下提示来区分差异:

一种解释性语言(例如Python)是一种将源代码转换为机器代码,然后在每次程序运行时执行的语言。这与诸如C之类的编译语言不同,后者仅将源代码转换为机器代码一次-每次程序运行时都会执行生成的机器代码。

The Python Book © 2015 Imagine Publishing Ltd, simply distunguishes the difference by the following hint mentioned in page 10 as:

An interpreted language such as Python is one where the source code is converted to machine code and then executed each time the program runs. This is different from a compiled language such as C, where the source code is only converted to machine code once – the resulting machine code is then executed each time the program runs.


回答 10

编译是从以编译的编程语言编写的代码创建可执行程序的过程。编译允许计算机运行和理解程序,而无需使用用于创建该程序的编程软件。编译程序时,通常是针对特定平台(例如IBM平台)编译的,该平台可与IBM兼容计算机一起使用,但不适用于其他平台(例如Apple平台)。第一个编译器是由Grace Hopper在哈佛Mark I计算机上开发的。今天,大多数高级语言将包括其自己的编译器或可用的工具包,可用于编译程序。与Java一起使用的编译器的一个很好的例子是Eclipse,而与C和C ++一起使用的编译器的一个例子是gcc命令。

Compile is the process of creating an executable program from code written in a compiled programming language. Compiling allows the computer to run and understand the program without the need of the programming software used to create it. When a program is compiled it is often compiled for a specific platform (e.g. IBM platform) that works with IBM compatible computers, but not other platforms (e.g. Apple platform). The first compiler was developed by Grace Hopper while working on the Harvard Mark I computer. Today, most high-level languages will include their own compiler or have toolkits available that can be used to compile the program. A good example of a compiler used with Java is Eclipse and an example of a compiler used with C and C++ is the gcc command. Depending on how big the program is it should take a few seconds or minutes to compile and if no errors are encountered while being compiled an executable file is created.check this information


回答 11

简短(不精确)的定义:

编译语言:整个程序立即转换为机器代码,然后由CPU运行机器代码。

解释的语言:逐行读取程序,一旦读取一行,CPU就会执行该行的机器指令。

但是,实际上,如今只有很少的语言是纯编译的或纯解释的,通常是混合的。有关图片的详细说明,请参见以下线程:

编译和解释之间有什么区别?

或我后来的博客文章:

https://orangejuiceliberationfront.com/the-difference-between-compiler-and-interpreter/

Short (un-precise) definition:

Compiled language: Entire program is translated to machine code at once, then the machine code is run by the CPU.

Interpreted language: Program is read line-by-line and as soon as a line is read the machine instructions for that line are executed by the CPU.

But really, few languages these days are purely compiled or purely interpreted, it often is a mix. For a more detailed description with pictures, see this thread:

What is the difference between compilation and interpretation?

Or my later blog post:

https://orangejuiceliberationfront.com/the-difference-between-compiler-and-interpreter/


经典编程书籍大全,涵盖:计算机系统与网络、系统架构、算法与数据结构、前端开发、后端开发、移动开发、数据库、测试、项目与团队、程序员职业修炼、求职面试等

太棒了-cs-书籍:超过200本经典的计算机书籍分享

经典的编程书单大全简介:

这里汇集如下主题的经典书籍:编程语言(JAVA、C++、C、python等等)、操作系统、计算机网络、系统架构、设计模式、程序员数学、测试、中间件、前端开发、后台开发、网络编程、linux使用及内核、求职面试、算法与数据结构安卓、IOS、数据库、redis等主流的编程学习书籍.

本仓库持续更新中,后续会陆续分享更多经典电子书,墙裂建议大家STAR下本仓库,下次找书直接Ctrl+F

如果国内访问Github网速较慢,可以访问码云:https://gitee.com/Marvinle/awesome-cs-books

大神刷题笔记

重要说明如果目录无法跳转的话,直接拉下去就可以了,这些书籍都是在同一个页面的,我只是方便大家找到对应的,弄了一个页内目录,不过有部分读者反馈他跳转不了(手机是绝对跳转不了的了)。


CS四大基础课

操作系统

编译原理

//TDOO

计算机网络

计算机组成原理

//TODO

计算机系统

算法和数据结构

网络编程

架构和设计模式

数据库和存储

C++

C++面试题集锦.PDF百度网盘链接密码:Lrv9

Java语言

Java语言

C语言

大数据

//TODO

机器学习和人工智能

//TODO

未分类

//TODO

全部汇总

目前我把电子书暂时放在公众号[编程指北]了,扫码关注下面公众号,回复“pdf”就有我收集的上百本经典计算机书籍,包含各个方向:

微信扫描上方二维码回复“pdf”

免责声明

书籍全部来源于网络其他人的整理,这里只是收集整理了他们的链接,如有侵权,马上联系我,我立马删除对应链接.我的邮箱:2039652520@qq.com

Buck-一个快速构建系统,鼓励在各种平台和语言上创建小的、可重用的模块

Buck是一个构建工具。要了解Buck可以为您做些什么,请查看以下地址的文档http://buck.build/

安装

由于Buck用于构建Buck,因此初始构建过程包括两个阶段:

1.克隆buck仓库,并用蚂蚁引导:
git clone --depth 1 https://github.com/facebook/buck.git
cd buck
ant

您必须使用Java8或11才能成功编译。如果您看到来自ANT的编译错误,请检查您的JAVA_HOME指向这些版本中的一个

2.使用buck的自举版本构建buck:
./bin/buck build --show-output buck
# output will contain something like
# //programs:buck buck-out/gen/programs/buck.pex
buck-out/gen/programs/buck.pex --help
预置的降压二进制文件

预置的BUCK二进制文件,适用于任何BUCKsha可从以下地址下载https://jitpack.io/com/github/facebook/buck/<sha>/buck-<sha>.pex第一次请求buck版本时,它是通过jitpack因此,该初始二进制文件可能需要几分钟时间才能可用。每个后续请求都将直接服务于构建的工件。此功能也适用于任何buck叉子,因此您可以https://jitpack.io/com/github/<github-user-or-org>/buck/<sha>/buck-<sha>.pex

对于为JDK 11构建的buck二进制文件,请将url的末尾修改为buck-<sha>-java11.pex

功能已弃用

Buck试图在其内部快速行动。但是,对于面向用户的功能(构建规则、命令行界面等),Buck团队尝试使用优雅的弃用过程。请注意,这通常仅适用于有文档记录的功能,或文档较少但似乎使用广泛的功能。这个过程是:

  • 在Github上会打开一个问题,建议哪些内容将被弃用,以及何时将其删除。对于已弃用的较大功能,可能会有一段时间默认为新设置,旧行为只能与配置更改一起使用
  • 向Buck提交更改,该更改将旧行为置于配置标志之后,并将缺省值设置为旧行为。这些标志可在以下位置找到https://buck.build/concept/buckconfig.html#incompatible
  • 对于较大的功能,最终会进行更改,将默认行为设置为新行为。例如,当Skylark成为默认的构建文件解析器时
  • 当到达删除日期时,将提交更改以删除该功能。此时,配置值仍将进行解析,但不会由Buck在内部使用

许可证

Apache License 2.0

Mal-MAL-做一个Lisp

MAL-做一个Lisp

描述

1.Mal是一个受Clojure启发的Lisp解释器

2.MAL是一种学习工具

MAL的每个实现被分成11个增量的、自包含的(且可测试的)步骤,这些步骤演示了Lisp的核心概念。最后一步是能够自托管(运行mal的错误实现)。请参阅make-a-lisp process
guide

Make-a-LISP步骤包括:

每个Make-a-LISP步骤都有一个关联的架构图。该步骤的新元素以红色高亮显示。以下是step A

如果您对创建mal实现感兴趣(或者只是对使用mal做某事感兴趣),欢迎您加入我们的Discord或加入#mal onlibera.chat除了make-a-lisp
process guide
还有一个mal/make-a-lisp
FAQ
在这里我试图回答一些常见的问题

3.MAL用86种语言实现(91种不同实现,113种运行模式)

语言 创建者
Ada Chris Moore
Ada #2 Nicolas Boulenguez
GNU Awk Miutsuru Kariya
Bash 4 Joel Martin
BASIC(C64和QBASIC) Joel Martin
BBC BASIC V Ben Harris
C Joel Martin
C #2 Duncan Watts
C++ Stephen Thirlwall
C# Joel Martin
ChucK Vasilij Schneidermann
Clojure(Clojure和ClojureScript) Joel Martin
CoffeeScript Joel Martin
Common Lisp Iqbal Ansari
Crystal Linda_pp
D Dov Murik
Dart Harry Terkelsen
Elixir Martin Ek
Elm Jos van Bakel
Emacs Lisp Vasilij Schneidermann
Erlang Nathan Fiedler
ES6(ECMAScript 2015) Joel Martin
F# Peter Stephens
Factor Jordan Lewis
Fantom Dov Murik
Fennel sogaiu
Forth Chris Houser
GNU Guile Mu Lei
GNU Smalltalk Vasilij Schneidermann
Go Joel Martin
Groovy Joel Martin
Haskell Joel Martin
Haxe(Neko、Python、C++和JS) Joel Martin
Hy Joel Martin
Io Dov Murik
Janet sogaiu
Java Joel Martin
Java(松露/GraalVM) Matt McGill
JavaScript(Demo) Joel Martin
jq Ali MohammadPur
Julia Joel Martin
Kotlin Javier Fernandez-Ivern
LiveScript Jos van Bakel
Logo Dov Murik
Lua Joel Martin
GNU Make Joel Martin
mal itself Joel Martin
MATLAB(GNU Octave&MATLAB) Joel Martin
miniMAL(RepoDemo) Joel Martin
NASM Ben Dudson
Nim Dennis Felsing
Object Pascal Joel Martin
Objective C Joel Martin
OCaml Chris Houser
Perl Joel Martin
Perl 6 Hinrik Örn Sigurðsson
PHP Joel Martin
Picolisp Vasilij Schneidermann
Pike Dov Murik
PL/pgSQL(PostgreSQL) Joel Martin
PL/SQL(Oracle) Joel Martin
PostScript Joel Martin
PowerShell Joel Martin
Prolog Nicolas Boulenguez
Python(2.x和3.x) Joel Martin
Python #2(3.x) Gavin Lewis
RPython Joel Martin
R Joel Martin
Racket Joel Martin
Rexx Dov Murik
Ruby Joel Martin
Rust Joel Martin
Scala Joel Martin
Scheme (R7RS) Vasilij Schneidermann
Skew Dov Murik
Standard ML Fabian Bergström
Swift 2 Keith Rollin
Swift 3 Joel Martin
Swift 4 陆遥
Swift 5 Oleg Montak
Tcl Dov Murik
TypeScript Masahiro Wakame
Vala Simon Tatham
VHDL Dov Murik
Vimscript Dov Murik
Visual Basic.NET Joel Martin
WebAssembly(WASM) Joel Martin
Wren Dov Murik
XSLT Ali MohammadPur
Yorick Dov Murik
Zig Josh Tobin

演示文稿

Mal第一次出现在2014年Clojure West的闪电演讲中(不幸的是没有视频)。参见Examples/clojurewest2014.mal了解会议上的演示文稿(是的,该演示文稿是一个MALL程序)

在Midwest.io 2015上,乔尔·马丁(Joel Martin)就MAL做了题为“解锁的成就:一条更好的语言学习之路”的演讲VideoSlides

最近,乔尔在LambdaConf 2016大会上发表了题为“用10个增量步骤打造自己的Lisp解释器”的演讲:Part 1Part 2Part 3Part 4Slides

构建/运行实现

运行任何给定实现的最简单方法是使用docker。每个实现都有一个预先构建的停靠器映像,其中安装了语言依赖项。您可以在顶层Makefile中使用一个方便的目标启动REPL(其中impl是实现目录名,stepX是要运行的步骤):

make DOCKERIZE=1 "repl^IMPL^stepX"
    # OR stepA is the default step:
make DOCKERIZE=1 "repl^IMPL"

外部实现

以下实施作为单独的项目进行维护:

HolyC

生锈

  • by Tim Morgan
  • by vi-使用Pest语法,不使用典型的MAL基础设施(货币化步骤和内置的转换测试)

问:

  • by Ali Mohammad Pur-Q实现运行良好,但它需要专有的手动下载,不能Docker化(或集成到mal CI管道中),因此目前它仍然是一个单独的项目

其他MAL项目

  • malc详细说明:MAL(Make A Lisp)编译器。将MAL程序编译成LLVM汇编语言,然后编译成二进制
  • malcc-malcc是MAL语言的增量编译器实现。它使用微型C编译器作为编译器后端,并且完全支持MAL语言,包括宏、尾部调用消除,甚至运行时求值。“I Built a Lisp Compiler”发布有关该过程的帖子
  • frock+Clojure风格的PHP。使用mal/php运行程序
  • flk-无论Bash在哪里都可以运行的LISP
  • glisp详细说明:基于Lisp的自引导图形设计工具。Live Demo

实施详情

Ada

Ada实现是在Debian上使用GNAT4.9开发的。如果您有git、gnat和make(可选)的windows版本,它也可以在windows上编译而不变。没有外部依赖项(未实现ReadLine)

cd impls/ada
make
./stepX_YYY

Ada.2

第二个Ada实现是使用GNAT 8开发的,并与GNU读取线库链接

cd impls/ada
make
./stepX_YYY

GNU awk

Mal的GNU awk实现已经使用GNU awk 4.1.1进行了测试

cd impls/gawk
gawk -O -f stepX_YYY.awk

BASH 4

cd impls/bash
bash stepX_YYY.sh

基本(C64和QBasic)

Basic实现使用一个预处理器,该预处理器可以生成与C64 Basic(CBMv2)和QBasic兼容的Basic代码。C64模式已经过测试cbmbasic(当前需要打补丁的版本来修复线路输入问题),并且QBasic模式已经过测试qb64

生成C64代码并使用cbmbasic运行:

cd impls/basic
make stepX_YYY.bas
STEP=stepX_YYY ./run

生成QBasic代码并加载到qb64中:

cd impls/basic
make MODE=qbasic stepX_YYY.bas
./qb64 stepX_YYY.bas

感谢Steven Syrek有关此实现的原始灵感,请参阅

BBC Basic V

BBC Basic V实现可以在Brandy解释器中运行:

cd impls/bbc-basic
brandy -quit stepX_YYY.bbc

或在RISC OS 3或更高版本下的ARM BBC Basic V中:

*Dir bbc-basic.riscos
*Run setup
*Run stepX_YYY

C

mal的C实现需要以下库(lib和头包):glib、libffi6、libgc以及libedit或GNU readline库

cd impls/c
make
./stepX_YYY

C.2

mal的第二个C实现需要以下库(lib和头包):libedit、libgc、libdl和libffi

cd impls/c.2
make
./stepX_YYY

C++

构建mal的C++实现需要g++-4.9或clang++-3.5和readline兼容库。请参阅cpp/README.md有关更多详细信息,请执行以下操作:

cd impls/cpp
make
    # OR
make CXX=clang++-3.5
./stepX_YYY

C#

mal的C#实现已经在Linux上使用Mono C#编译器(MCS)和Mono运行时(2.10.8.1版)进行了测试。两者都是构建和运行C#实现所必需的

cd impls/cs
make
mono ./stepX_YYY.exe

卡盘

Chuck实现已经使用Chuck 1.3.5.2进行了测试

cd impls/chuck
./run

封闭式

在很大程度上,Clojure实现需要Clojure 1.5,然而,要通过所有测试,则需要Clojure 1.8.0-RC4

cd impls/clojure
lein with-profile +stepX trampoline run

CoffeeScript

sudo npm install -g coffee-script
cd impls/coffee
coffee ./stepX_YYY

通用Lisp

该实现已经在Ubuntu 16.04和Ubuntu 12.04上使用SBCL、CCL、CMUCL、GNU CLISP、ECL和Allegro CL进行了测试,请参阅README了解更多详细信息。如果您安装了上述依赖项,请执行以下操作来运行实现

cd impls/common-lisp
make
./run

水晶

MAL的晶体实现已经用Crystal 0.26.1进行了测试

cd impls/crystal
crystal run ./stepX_YYY.cr
    # OR
make   # needed to run tests
./stepX_YYY

D

使用GDC4.8对MAL的D实现进行了测试。它需要GNU读取线库

cd impls/d
make
./stepX_YYY

省道

DART实施已使用DART 1.20进行了测试

cd impls/dart
dart ./stepX_YYY

Emacs Lisp

Emacs Lisp的MAL实现已经使用Emacs 24.3和24.5进行了测试。虽然有非常基本的读数行编辑(<backspace>C-d工作,C-c取消进程),建议使用rlwrap

cd impls/elisp
emacs -Q --batch --load stepX_YYY.el
# with full readline support
rlwrap emacs -Q --batch --load stepX_YYY.el

灵丹妙药

MAL的长生不老的实现已经在长生不老的长生不老的1.0.5中进行了测试

cd impls/elixir
mix stepX_YYY
# Or with readline/line editing functionality:
iex -S mix stepX_YYY

榆树

MAL的ELM实现已经用ELM 0.18.0进行了测试

cd impls/elm
make stepX_YYY.js
STEP=stepX_YYY ./run

二郎

Mal的Erlang实现需要Erlang/OTP R17rebar要建造

cd impls/erlang
make
    # OR
MAL_STEP=stepX_YYY rebar compile escriptize # build individual step
./stepX_YYY

ES6(ECMAScript 2015)

ES6/ECMAScript 2015实施使用babel用于生成ES5兼容JavaScript的编译器。生成的代码已经在Node 0.12.4上进行了测试

cd impls/es6
make
node build/stepX_YYY.js

F#

mal的F#实现已经在Linux上使用Mono F#编译器(Fsharpc)和Mono运行时(版本3.12.1)进行了测试。单C#编译器(MCS)也是编译readline依赖项所必需的。所有这些都是构建和运行F#实现所必需的

cd impls/fsharp
make
mono ./stepX_YYY.exe

因素

MAL的因子实现已通过因子0.97(factorcode.org)

cd impls/factor
FACTOR_ROOTS=. factor -run=stepX_YYY

幻影

MAL的幻象实现已经用幻象1.0.70进行了测试

cd impls/fantom
make lib/fan/stepX_YYY.pod
STEP=stepX_YYY ./run

茴香

Mal的Fennel实现已经在Lua5.4上使用Fennel版本0.9.1进行了测试

cd impls/fennel
fennel ./stepX_YYY.fnl

第四

cd impls/forth
gforth stepX_YYY.fs

GNU Guile 2.1+

cd impls/guile
guile -L ./ stepX_YYY.scm

GNU Smalltalk

MALL的Smalltalk实现已经在GNU Smalltalk 3.2.91上进行了测试

cd impls/gnu-smalltalk
./run

MALL的GO实现要求在路径上安装GO。该实现已经在GO 1.3.1上进行了测试

cd impls/go
make
./stepX_YYY

时髦的

mal的Groovy实现需要Groovy才能运行,并且已经使用Groovy 1.8.6进行了测试

cd impls/groovy
make
groovy ./stepX_YYY.groovy

哈斯克尔

Haskell实现需要GHC编译器版本7.10.1或更高版本以及Haskell parsec和readline(或editline)包

cd impls/haskell
make
./stepX_YYY

Haxe(Neko、Python、C++和JavaScript)

Mal的Haxe实现需要编译Haxe3.2版。支持四种不同的Haxe目标:neko、Python、C++和JavaScript

cd impls/haxe
# Neko
make all-neko
neko ./stepX_YYY.n
# Python
make all-python
python3 ./stepX_YYY.py
# C++
make all-cpp
./cpp/stepX_YYY
# JavaScript
make all-js
node ./stepX_YYY.js

干草

MAL的Hy实现已经用Hy 0.13.0进行了测试

cd impls/hy
./stepX_YYY.hy

IO

已使用IO版本20110905测试了MAL的IO实现

cd impls/io
io ./stepX_YYY.io

珍妮特

MAIL的Janet实现已经使用Janet版本1.12.2进行了测试

cd impls/janet
janet ./stepX_YYY.janet

Java 1.7

mal的Java实现需要maven2来构建

cd impls/java
mvn compile
mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY
    # OR
mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY -Dexec.args="CMDLINE_ARGS"

Java,将Truffle用于GraalVM

这个Java实现可以在OpenJDK上运行,但是多亏了Truffle框架,它在GraalVM上的运行速度可以提高30倍。它已经在OpenJDK 11、GraalVM CE 20.1.0和GraalVM CE 21.1.0上进行了测试

cd impls/java-truffle
./gradlew build
STEP=stepX_YYY ./run

JavaScript/节点

cd impls/js
npm install
node stepX_YYY.js

朱莉娅

Mal的Julia实现需要Julia 0.4

cd impls/julia
julia stepX_YYY.jl

JQ

针对1.6版进行了测试,IO部门存在大量作弊行为

cd impls/jq
STEP=stepA_YYY ./run
    # with Debug
DEBUG=true STEP=stepA_YYY ./run

科特林

MAL的Kotlin实现已经使用Kotlin 1.0进行了测试

cd impls/kotlin
make
java -jar stepX_YYY.jar

LiveScript

已使用LiveScript 1.5测试了mal的LiveScript实现

cd impls/livescript
make
node_modules/.bin/lsc stepX_YYY.ls

徽标

MAL的Logo实现已经用UCBLogo 6.0进行了测试

cd impls/logo
logo stepX_YYY.lg

路亚

Mal的Lua实现已经使用Lua 5.3.5进行了测试。该实现需要安装luarock

cd impls/lua
make  # to build and link linenoise.so and rex_pcre.so
./stepX_YYY.lua

男性

运行mal的错误实现包括运行其他实现之一的STEPA,并传递作为命令行参数运行的mal步骤

cd impls/IMPL
IMPL_STEPA_CMD ../mal/stepX_YYY.mal

GNU Make 3.81

cd impls/make
make -f stepX_YYY.mk

NASM

MAL的NASM实现是为x86-64 Linux编写的,并且已经在Linux 3.16.0-4-AMD64和NASM版本2.11.05上进行了测试

cd impls/nasm
make
./stepX_YYY

NIM 1.0.4

MAL的NIM实现已经使用NIM 1.0.4进行了测试

cd impls/nim
make
  # OR
nimble build
./stepX_YYY

对象PASCAL

MAL的对象Pascal实现已经使用Free Pascal编译器版本2.6.2和2.6.4在Linux上构建和测试

cd impls/objpascal
make
./stepX_YYY

目标C

Mal的Objective C实现已经在Linux上使用CLANG/LLVM3.6进行了构建和测试。它还使用XCode7在OS X上进行了构建和测试

cd impls/objc
make
./stepX_YYY

OCaml 4.01.0

cd impls/ocaml
make
./stepX_YYY

MATLAB(GNU倍频程和MATLAB)

MATLAB实现已经在GNU Octave 4.2.1上进行了测试。它还在Linux上用MATLAB版本R2014a进行了测试。请注意,matlab是一个商业产品。

cd impls/matlab
./stepX_YYY
octave -q --no-gui --no-history --eval "stepX_YYY();quit;"
matlab -nodisplay -nosplash -nodesktop -nojvm -r "stepX_YYY();quit;"
    # OR with command line arguments
octave -q --no-gui --no-history --eval "stepX_YYY('arg1','arg2');quit;"
matlab -nodisplay -nosplash -nodesktop -nojvm -r "stepX_YYY('arg1','arg2');quit;"

极小值

miniMAL是用不到1024字节的JavaScript实现的小型Lisp解释器。要运行mal的最小实现,您需要下载/安装最小解释器(这需要Node.js)

cd impls/miniMAL
# Download miniMAL and dependencies
npm install
export PATH=`pwd`/node_modules/minimal-lisp/:$PATH
# Now run mal implementation in miniMAL
miniMAL ./stepX_YYY

Perl 5

Perl 5实现应该使用Perl 5.19.3和更高版本

要获得读取行编辑支持,请从CPAN安装Term::ReadLine::Perl或Term::ReadLine::GNU

cd impls/perl
perl stepX_YYY.pl

Perl 6

Perl6实现在Rakudo Perl6 2016.04上进行了测试

cd impls/perl6
perl6 stepX_YYY.pl

PHP 5.3

mal的PHP实现需要php命令行界面才能运行

cd impls/php
php stepX_YYY.php

皮奥利普

Picolisp实现需要libreadline和Picolisp 3.1.11或更高版本

cd impls/picolisp
./run

派克

Pike实现在Pike8.0上进行了测试

cd impls/pike
pike stepX_YYY.pike

pl/pgSQL(PostgreSQL SQL过程语言)

mal的PL/pgSQL实现需要一个正在运行的PostgreSQL服务器(“kanaka/mal-test-plpgsql”docker映像自动启动PostgreSQL服务器)。该实现连接到PostgreSQL服务器并创建名为“mal”的数据库来存储表和存储过程。包装器脚本使用psql命令连接到服务器,并默认为用户“postgres”,但可以使用PSQL_USER环境变量覆盖该值。可以使用PGPASSWORD环境变量指定密码。该实现已使用PostgreSQL 9.4进行了测试

cd impls/plpgsql
./wrap.sh stepX_YYY.sql
    # OR
PSQL_USER=myuser PGPASSWORD=mypass ./wrap.sh stepX_YYY.sql

PL/SQL(Oracle SQL过程语言)

mal的PL/SQL实现需要一个正在运行的Oracle DB服务器(“kanaka/mal-test-plsql”docker映像自动启动Oracle Express服务器)。该实现连接到Oracle服务器以创建类型、表和存储过程。默认的SQL*Plus登录值(用户名/口令@CONNECT_IDENTIFIER)是“SYSTEM/ORACLE”,但是可以用ORACLE_LOGON环境变量覆盖该值。该实施已使用Oracle Express Edition 11g Release 2进行了测试。请注意,任何SQL*Plus连接警告(用户密码过期等)都会干扰包装脚本与数据库通信的能力

cd impls/plsql
./wrap.sh stepX_YYY.sql
    # OR
ORACLE_LOGON=myuser/mypass@ORCL ./wrap.sh stepX_YYY.sql

PostScript Level 2/3

mal的PostScript实现需要运行Ghostscript。它已经使用Ghostscript 9.10进行了测试

cd impls/ps
gs -q -dNODISPLAY -I./ stepX_YYY.ps

PowerShell

Mal的PowerShell实现需要PowerShell脚本语言。它已经在Linux上使用PowerShell 6.0.0 Alpha 9进行了测试

cd impls/powershell
powershell ./stepX_YYY.ps1

序言

Prolog实现使用了一些特定于SWI-Prolog的结构,包括READLINE支持,并且已经在8.2.1版的Debian GNU/Linux上进行了测试

cd impls/prolog
swipl stepX_YYY

Python(2.x和3.x)

cd impls/python
python stepX_YYY.py

Python2(3.x)

第二个Python实现大量使用类型注释并使用Arpeggio解析器库

# Recommended: do these steps in a Python virtual environment.
pip3 install Arpeggio==1.9.0
python3 stepX_YYY.py

RPython

你一定是rpython在您的路径上(随附pypy)

cd impls/rpython
make        # this takes a very long time
./stepX_YYY

R

MALL R实现需要R(r-base-core)来运行

cd impls/r
make libs  # to download and build rdyncall
Rscript stepX_YYY.r

球拍(5.3)

Mal的racket实现需要运行racket编译器/解释器

cd impls/racket
./stepX_YYY.rkt

雷克斯

Mal的Rexx实现已经使用Regina Rexx 3.6进行了测试

cd impls/rexx
make
rexx -a ./stepX_YYY.rexxpp

拼音(1.9+)

cd impls/ruby
ruby stepX_YYY.rb

生锈(1.38+)

Mal的Rust实现需要使用Rust编译器和构建工具(Cargo)来构建

cd impls/rust
cargo run --release --bin stepX_YYY

缩放比例

安装Scala和SBT(http://www.scala-sbt.org/0.13/tutorial/Installing-sbt-on-Linux.html):

cd impls/scala
sbt 'run-main stepX_YYY'
    # OR
sbt compile
scala -classpath target/scala*/classes stepX_YYY

方案(R7RS)

MAL的方案实施已在赤壁-方案0.7.3、卡瓦2.4、高车0.9.5、鸡肉4.11.0、人马座0.8.3、气旋0.6.3(Git版本)和Foment 0.4(Git版本)上进行了测试。在弄清库是如何加载的并调整了R7RS实现的基础上,您应该能够让它在其他符合R7RS标准的实现上运行Makefilerun相应地编写脚本

cd impls/scheme
make symlinks
# chibi
scheme_MODE=chibi ./run
# kawa
make kawa
scheme_MODE=kawa ./run
# gauche
scheme_MODE=gauche ./run
# chicken
make chicken
scheme_MODE=chicken ./run
# sagittarius
scheme_MODE=sagittarius ./run
# cyclone
make cyclone
scheme_MODE=cyclone ./run
# foment
scheme_MODE=foment ./run

歪斜

MAL的不对称实现已经使用不对称0.7.42进行了测试

cd impls/skew
make
node stepX_YYY.js

标准ML(Poly/ML、MLton、莫斯科ML)

Mal的标准ML实现需要一个SML97实施。Makefile支持POLY/ML、MLTON、MOVICO ML,并已在POLY/ML 5.8.1、MLTON 20210117和MOSSIONS ML版本2.10上进行了测试

cd impls/sml
# Poly/ML
make sml_MODE=polyml
./stepX_YYY
# MLton
make sml_MODE=mlton
./stepX_YYY
# Moscow ML
make sml_MODE=mosml
./stepX_YYY

斯威夫特

MALL的SWIFT实施需要SWIFT 2.0编译器(XCode 7.0)来构建。由于语言和标准库中的更改,旧版本将无法运行

cd impls/swift
make
./stepX_YYY

斯威夫特3

MALL的SWIFT 3实施需要SWIFT 3.0编译器。它已经在SWIFT 3预览版3上进行了测试

cd impls/swift3
make
./stepX_YYY

斯威夫特4

MALL的SWIFT 4实施需要SWIFT 4.0编译器。它已在SWIFT 4.2.3版本中进行了测试

cd impls/swift4
make
./stepX_YYY

SWIFT 5

MALL的SWIFT 5实施需要SWIFT 5.0编译器。它已在SWIFT 5.1.1版本中进行了测试

cd impls/swift5
swift run stepX_YYY

TCL 8.6

Mal的Tcl实现需要运行Tcl 8.6。要获得readline行编辑支持,请安装tclreadline

cd impls/tcl
tclsh ./stepX_YYY.tcl

打字稿

mal的TypeScript实现需要TypeScript 2.2编译器。它已经在Node.js V6上进行了测试

cd impls/ts
make
node ./stepX_YYY.js

瓦拉

MALL的VALA实现已经用VALA0.40.8编译器进行了测试。您将需要安装valaclibreadline-dev或同等的

cd impls/vala
make
./stepX_YYY

VHDL

用GHDL0.29对mal的vhdl实现进行了测试。

cd impls/vhdl
make
./run_vhdl.sh ./stepX_YYY

Vimscript

Mal的Vimscript实现需要运行Vim 8.0

cd impls/vimscript
./run_vimscript.sh ./stepX_YYY.vim

Visual Basic.NET

Mal的VB.NET实现已经在Linux上使用Mono VB编译器(Vbnc)和Mono运行时(2.10.8.1版)进行了测试。构建和运行VB.NET实现需要两者

cd impls/vb
make
mono ./stepX_YYY.exe

WebAssembly(Wasm)

WebAssembly实现是用Wam(WebAssembly宏语言),并在几种不同的非Web嵌入(运行时)下运行:nodewasmtimewasmerlucetwaxwacewarpy

cd impls/wasm
# node
make wasm_MODE=node
./run.js ./stepX_YYY.wasm
# wasmtime
make wasm_MODE=wasmtime
wasmtime --dir=./ --dir=../ --dir=/ ./stepX_YYY.wasm
# wasmer
make wasm_MODE=wasmer
wasmer run --dir=./ --dir=../ --dir=/ ./stepX_YYY.wasm
# lucet
make wasm_MODE=lucet
lucet-wasi --dir=./:./ --dir=../:../ --dir=/:/ ./stepX_YYY.so
# wax
make wasm_MODE=wax
wax ./stepX_YYY.wasm
# wace
make wasm_MODE=wace_libc
wace ./stepX_YYY.wasm
# warpy
make wasm_MODE=warpy
warpy --argv --memory-pages 256 ./stepX_YYY.wasm

XSLT

mal的XSLT实现是用XSLT3编写的,并在Saxon 9.9.1.6家庭版上进行了测试

cd impls/xslt
STEP=stepX_YY ./run

雷恩

MAL的WREN实现在WREN 0.2.0上进行了测试

cd impls/wren
wren ./stepX_YYY.wren

约里克

MAL的Yorick实现在Yorick 2.2.04上进行了测试

cd impls/yorick
yorick -batch ./stepX_YYY.i

之字形

MAL的Zig实现在Zig0.5上进行了测试

cd impls/zig
zig build stepX_YYY

运行测试

顶层Makefile有许多有用的目标来协助实现、开发和测试。这个helpTarget提供目标和选项的列表:

make help

功能测试

中几乎有800个通用功能测试(针对所有实现)。tests/目录。每个步骤都有相应的测试文件,其中包含特定于该步骤的测试。这个runtest.py测试工具启动MAL步骤实现,然后将测试一次一个提供给实现,并将输出/返回值与预期的输出/返回值进行比较

  • 要在所有实现中运行所有测试(请准备等待):
make test
  • 要针对单个实施运行所有测试,请执行以下操作:
make "test^IMPL"

# e.g.
make "test^clojure"
make "test^js"
  • 要对所有实施运行单个步骤的测试,请执行以下操作:
make "test^stepX"

# e.g.
make "test^step2"
make "test^step7"
  • 要针对单个实施运行特定步骤的测试,请执行以下操作:
make "test^IMPL^stepX"

# e.g
make "test^ruby^step3"
make "test^ps^step4"

自托管功能测试

  • 若要在自托管模式下运行功能测试,请指定mal作为测试实现,并使用MAL_IMPLMake Variable以更改基础主机语言(默认值为JavaScript):
make MAL_IMPL=IMPL "test^mal^step2"

# e.g.
make "test^mal^step2"   # js is default
make MAL_IMPL=ruby "test^mal^step2"
make MAL_IMPL=python "test^mal^step2"

启动REPL

  • 要在特定步骤中启动实施的REPL,请执行以下操作:
make "repl^IMPL^stepX"

# e.g
make "repl^ruby^step3"
make "repl^ps^step4"
  • 如果您省略了这一步,那么stepA使用的是:
make "repl^IMPL"

# e.g
make "repl^ruby"
make "repl^ps"
  • 若要启动自托管实现的REPL,请指定mal作为REPL实现,并使用MAL_IMPLMake Variable以更改基础主机语言(默认值为JavaScript):
make MAL_IMPL=IMPL "repl^mal^stepX"

# e.g.
make "repl^mal^step2"   # js is default
make MAL_IMPL=ruby "repl^mal^step2"
make MAL_IMPL=python "repl^mal"

性能测试

警告:这些性能测试在统计上既不有效,也不全面;运行时性能不是mal的主要目标。如果你从这些性能测试中得出任何严肃的结论,那么请联系我,了解堪萨斯州一些令人惊叹的海滨房产,我愿意以低价卖给你

  • 要针对单个实施运行性能测试,请执行以下操作:
make "perf^IMPL"

# e.g.
make "perf^js"
  • 要对所有实施运行性能测试,请执行以下操作:
make "perf"

正在生成语言统计信息

  • 要报告单个实施的行和字节统计信息,请执行以下操作:
make "stats^IMPL"

# e.g.
make "stats^js"

对接测试

每个实现目录都包含一个Dockerfile,用于创建包含该实现的所有依赖项的docker映像。此外,顶级Makefile还支持在停靠器容器中通过传递以下参数来运行测试目标(以及perf、stats、repl等“DOCKERIZE=1”在make命令行上。例如:

make DOCKERIZE=1 "test^js^step3"

现有实现已经构建了坞站映像,并将其推送到坞站注册表。但是,如果您希望在本地构建或重建坞站映像,TopLevel Makefile提供了构建坞站映像的规则:

make "docker-build^IMPL"

注意事项

  • Docker镜像被命名为“Kanaka/mal-test-iml”
  • 基于JVM的语言实现(Groovy、Java、Clojure、Scala):您可能需要首先手动运行此命令一次make DOCKERIZE=1 "repl^IMPL"然后才能运行测试,因为需要下载运行时依赖项以避免测试超时。这些依赖项被下载到/mal目录中的点文件中,因此它们将在两次运行之间保持不变

许可证

MAL(make-a-lisp)是根据MPL 2.0(Mozilla Public License 2.0)许可的。有关更多详细信息,请参阅LICENSE.txt

Leetcode-master 刷题攻略:200W道经典题目刷题顺序,共60w字的详细图解,视频难点剖析,50余张思维导图

一些闲话:

  1. 介绍:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,关注作者
  2. Pdf版本「代码随想录」算法精讲 PDF 版本那就是。
  3. 刷题顺序:自述文件已经将刷题顺序排好了,按照顺序一道一道刷就可以。
  4. 学习社区:一起学习打卡/面试技巧/如何选择Offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入「代码随想录」学习社区那就是。
  5. 提交代码:本项目统一使用C++语言进行讲解,但已经有JAVA、Python、Go、JavaScript等等多语言版本,感谢这里的每一位贡献者,如果你也想贡献代码点亮你的头像,点击这里了解提交代码的方式.
  6. 转载须知:以下所有文章皆为我(程序员Carl)的原创.引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益.让我们一起维护一个良好的技术创作环境!


LeetCode刷题攻略

刷题攻略的背景

很多刚开始刷题的同学都有一个困惑:面对leetcode上近两千道题目,从何刷起.

大家平时刷题感觉效率低,浪费的时间主要在三点:

  • 找题
  • 找到了不应该现阶段做的题
  • 没有全套的优质题解可以参考

其实我之前在知乎上回答过这个问题,回答内容大概是按照如下类型来刷数组->链表->哈希表->字符串->栈与队列->树->回溯->贪心->动态规划->图论->高级数据结构,再从简单刷起,做了几个类型题目之后,再慢慢做中等题目、困难题目.

但我能设身处地的感受到:即使有这样一个整体规划,对于一位初学者甚至算法老手寻找合适自己的题目也是很困难,时间成本很高,而且题目还不一定就是经典题目.

对于刷题,我们都是想用最短的时间按照循序渐进的难度顺序把经典题目都做一遍,这样效率才是最高的!

所以我整理了LeetCode刷题攻略:一个超级详细的刷题顺序,每道题目都是我精心筛选,都是经典题目高频面试题,大家只要按照这个顺序刷就可以了,你没看错,自述已经把题目顺序都排好了,文章顺序就是刷题顺序!挨个刷就可以,不用自己再去题海里选题了!

而且每道题目我都写了的详细题解(图文并茂,难点配有视频),力扣上我的题解都是排在对应题目的首页,质量是有目共睹的.

那么现在我把刷题顺序都整理出来,是为了帮助更多的学习算法的同学少走弯路!

如果你在刷LeetCode,强烈建议先按照本攻略刷题顺序来刷,刷完了你会发现对整个知识体系有一个质的飞跃,不用在题海茫然的寻找方向.

最新文章会首发在公众号“代码随想录”,扫码看看吧,你会发现相见恨晚!

如何使用该刷题攻略

电脑端还看不到留言,大家可以在公众号「代码随想录」,左下角有“刷题攻略”,这是手机版刷题攻略,看完就会发现有很多录友(代码随想录的朋友们)在文章下留言打卡,这份刷题顺序和题解已经陪伴了上万录友了,同时也说明文章的质量是经过上万人的考验!

欢迎每一位学习算法的小伙伴加入到这个学习阵营来!

目前已经更新了,数组->链表->哈希表->字符串->栈与队列->树->回溯->贪心,八个专题了,正在讲解动态规划!

在刷题攻略中,每个专题开始都有理论基础篇,并不像是教科书般的理论介绍,而是从实战中归纳需要的基础知识.每个专题结束都有总结篇,最这个专题的归纳总结.

如果你是算法老手,这篇攻略也是复习的最佳资料,如果把每个系列对应的总结篇,快速过一遍,整个算法知识体系以及各种解法就重现脑海了.

目前“代码随想录”刷题攻略更新了:200多篇文章,精讲了200道经典算法题目,共60w字的详细图解,部分难点题目还搭配了20分钟左右的视频讲解那就是。

这里每一篇题解,都是精品,值得仔细琢磨那就是。

我在题目讲解中统一用C++语言,但你会发现下面几乎每篇题解都配有其他语言版本,JAVA、Python、go、javascript等等,这正是热心小伙们的贡献的代码,当然我也会严格把控代码质量。

所以也欢迎大家参与进来,完善题解的各个语言版本,拥抱开源,让更多小伙伴们收益那就是。

准备好了么,刷题攻略开始咯,快走快走!


前序

(持续更新中.)

知识星球精选

  1. 选择方向的时候,我也迷茫了
  2. 刷题就用库函数了,怎么了?
  3. 关于实习,大家可能有点迷茫!
  4. 马上秋招了,慌得很!
  5. Carl看了上百份简历,总结了这些!
  6. 面试中遇到了发散性问题…..
  7. 英语到底重不重要!
  8. 计算机专业要不要读研!
  9. 秋招和提前批都越来越提前了….
  10. 你的简历里「专业技能」写的够专业么?

数组

  1. 数组过于简单,但你该了解这些!
  2. 数组:每次遇到二分法,都是一看就会,一写就废
  3. 数组:就移除个元素很难么?
  4. 数组:有序数组的平方,还有序么?
  5. 数组:滑动窗口拯救了你
  6. 数组:这个循环可以转懵很多人!
  7. 数组:总结篇

链表

  1. 关于链表,你该了解这些!
  2. 链表:听说用虚拟头节点会方便很多?
  3. 链表:一道题目考察了常见的五个操作!
  4. 链表:听说过两天反转链表又写不出来了?
  5. 链表:两两交换链表中的节点
  6. 链表:删除链表的倒数第 N 个结点
  7. 链表:链表相交
  8. 链表:环找到了,那入口呢?
  9. 链表:总结篇!

哈希表

  1. 关于哈希表,你该了解这些!
  2. 哈希表:可以拿数组当哈希表来用,但哈希值不要太大
  3. 哈希表:哈希值太大了,还是得用set
  4. 哈希表:用set来判断快乐数
  5. 哈希表:map等候多时了
  6. 哈希表:其实需要哈希的地方都能找到map的身影
  7. 哈希表:这道题目我做过?
  8. 哈希表:解决了两数之和,那么能解决三数之和么?
  9. 双指针法:一样的道理,能解决四数之和
  10. 哈希表:总结篇!(每逢总结必经典)

字符串

  1. 字符串:这道题目,使用库函数一行代码搞定
  2. 字符串:简单的反转还不够!
  3. 字符串:替换空格
  4. 字符串:花式反转还不够!
  5. 字符串:反转个字符串还有这个用处?
  6. 帮你把KMP算法学个通透
  7. 字符串:KMP算法还能干这个!
  8. 字符串:总结篇!

双指针法

双指针法基本都是应用在数组,字符串与链表的题目上

  1. 数组:就移除个元素很难么?
  2. 字符串:这道题目,使用库函数一行代码搞定
  3. 字符串:替换空格
  4. 字符串:花式反转还不够!
  5. 链表:听说过两天反转链表又写不出来了?
  6. 链表:删除链表的倒数第 N 个结点
  7. 链表:链表相交
  8. 链表:环找到了,那入口呢?
  9. 哈希表:解决了两数之和,那么能解决三数之和么?
  10. 双指针法:一样的道理,能解决四数之和
  11. 双指针法:总结篇!

栈与队列

  1. 栈与队列:来看看栈和队列不为人知的一面
  2. 栈与队列:我用栈来实现队列怎么样?
  3. 栈与队列:用队列实现栈还有点别扭
  4. 栈与队列:系统中处处都是栈的应用
  5. 栈与队列:匹配问题都是栈的强项
  6. 栈与队列:有没有想过计算机是如何处理表达式的?
  7. 栈与队列:滑动窗口里求最大值引出一个重要数据结构
  8. 栈与队列:求前 K 个高频元素和队列有啥关系?
  9. 栈与队列:总结篇!

二叉树

题目分类大纲如下:

  1. 关于二叉树,你该了解这些!
  2. 二叉树:一入递归深似海,从此offer是路人
  3. 二叉树:听说递归能做的,栈也能做!
  4. 二叉树:前中后序迭代方式的写法就不能统一一下么?
  5. 二叉树:层序遍历登场!
  6. 二叉树:你真的会翻转二叉树么?
  7. 本周小结!(二叉树)
  8. 二叉树:我对称么?
  9. 二叉树:看看这些树的最大深度
  10. 二叉树:看看这些树的最小深度
  11. 二叉树:我有多少个节点?
  12. 二叉树:我平衡么?
  13. 二叉树:找我的所有路径?
  14. 本周总结!二叉树系列二
  15. 二叉树:以为使用了递归,其实还隐藏着回溯
  16. 二叉树:做了这么多题目了,我的左叶子之和是多少?
  17. 二叉树:我的左下角的值是多少?
  18. 二叉树:递归函数究竟什么时候需要返回值,什么时候不要返回值?
  19. 二叉树:构造二叉树登场!
  20. 二叉树:构造一棵最大的二叉树
  21. 本周小结!(二叉树系列三)
  22. 二叉树:合并两个二叉树
  23. 二叉树:二叉搜索树登场!
  24. 二叉树:我是不是一棵二叉搜索树
  25. 二叉树:搜索树的最小绝对差
  26. 二叉树:我的众数是多少?
  27. 二叉树:公共祖先问题
  28. 本周小结!(二叉树系列四)
  29. 二叉树:搜索树的公共祖先问题
  30. 二叉树:搜索树中的插入操作
  31. 二叉树:搜索树中的删除操作
  32. 二叉树:修剪一棵搜索树
  33. 二叉树:构造一棵搜索树
  34. 二叉树:搜索树转成累加树
  35. 二叉树:总结篇!(需要掌握的二叉树技能都在这里了)

回溯算法

题目分类大纲如下:

  1. 关于回溯算法,你该了解这些!
  2. 回溯算法:组合问题
  3. 回溯算法:组合问题再剪剪枝
  4. 回溯算法:求组合总和!
  5. 回溯算法:电话号码的字母组合
  6. 本周小结!(回溯算法系列一)
  7. 回溯算法:求组合总和(二)
  8. 回溯算法:求组合总和(三)
  9. 回溯算法:分割回文串
  10. 回溯算法:复原IP地址
  11. 回溯算法:求子集问题!
  12. 本周小结!(回溯算法系列二)
  13. 回溯算法:求子集问题(二)
  14. 回溯算法:递增子序列
  15. 回溯算法:排列问题!
  16. 回溯算法:排列问题(二)
  17. 本周小结!(回溯算法系列三)
  18. 回溯算法去重问题的另一种写法
  19. 回溯算法:重新安排行程
  20. 回溯算法:N皇后问题
  21. 回溯算法:解数独
  22. 一篇总结带你彻底搞透回溯算法!

贪心算法

题目分类大纲如下:

  1. 关于贪心算法,你该了解这些!
  2. 贪心算法:分发饼干
  3. 贪心算法:摆动序列
  4. 贪心算法:最大子序和
  5. 本周小结!(贪心算法系列一)
  6. 贪心算法:买卖股票的最佳时机II
  7. 贪心算法:跳跃游戏
  8. 贪心算法:跳跃游戏II
  9. 贪心算法:K次取反后最大化的数组和
  10. 本周小结!(贪心算法系列二)
  11. 贪心算法:加油站
  12. 贪心算法:分发糖果
  13. 贪心算法:柠檬水找零
  14. 贪心算法:根据身高重建队列
  15. 本周小结!(贪心算法系列三)
  16. 贪心算法:根据身高重建队列(续集)
  17. 贪心算法:用最少数量的箭引爆气球
  18. 贪心算法:无重叠区间
  19. 贪心算法:划分字母区间
  20. 贪心算法:合并区间
  21. 本周小结!(贪心算法系列四)
  22. 贪心算法:单调递增的数字
  23. 贪心算法:买卖股票的最佳时机含手续费
  24. 贪心算法:我要监控二叉树!
  25. 贪心算法:总结篇!(每逢总结必经典)

动态规划

动态规划专题已经开始啦,来不及解释了,小伙伴们上车别掉队!

  1. 关于动态规划,你该了解这些!
  2. 动态规划:斐波那契数
  3. 动态规划:爬楼梯
  4. 动态规划:使用最小花费爬楼梯
  5. 本周小结!(动态规划系列一)
  6. 动态规划:不同路径
  7. 动态规划:不同路径还不够,要有障碍!
  8. 动态规划:整数拆分,你要怎么拆?
  9. 动态规划:不同的二叉搜索树
  10. 本周小结!(动态规划系列二)

背包问题系列:

  1. 动态规划:关于01背包问题,你该了解这些!
  2. 动态规划:关于01背包问题,你该了解这些!(滚动数组)
  3. 动态规划:分割等和子集可以用01背包!
  4. 动态规划:最后一块石头的重量 II
  5. 本周小结!(动态规划系列三)
  6. 动态规划:目标和!
  7. 动态规划:一和零!
  8. 动态规划:关于完全背包,你该了解这些!
  9. 动态规划:给你一些零钱,你要怎么凑?
  10. 本周小结!(动态规划系列四)
  11. 动态规划:Carl称它为排列总和!
  12. 动态规划:以前我没得选,现在我选择再爬一次!
  13. 动态规划: 给我个机会,我再兑换一次零钱
  14. 动态规划:一样的套路,再求一次完全平方数
  15. 本周小结!(动态规划系列五)
  16. 动态规划:单词拆分
  17. 动态规划:关于多重背包,你该了解这些!
  18. 听说背包问题很难? 这篇总结篇来拯救你了

打家劫舍系列:

  1. 动态规划:开始打家劫舍!
  2. 动态规划:继续打家劫舍!
  3. 动态规划:还要打家劫舍!

股票系列:

  1. 动态规划:买卖股票的最佳时机
  2. 动态规划:本周我们都讲了这些(系列六)
  3. 动态规划:买卖股票的最佳时机II
  4. 动态规划:买卖股票的最佳时机III
  5. 动态规划:买卖股票的最佳时机IV
  6. 动态规划:最佳买卖股票时机含冷冻期
  7. 动态规划:本周我们都讲了这些(系列七)
  8. 动态规划:买卖股票的最佳时机含手续费
  9. 动态规划:股票系列总结篇

子序列系列:

  1. 动态规划:最长递增子序列
  2. 动态规划:最长连续递增序列
  3. 动态规划:最长重复子数组
  4. 动态规划:最长公共子序列
  5. 动态规划:不相交的线
  6. 动态规划:最大子序和
  7. 动态规划:判断子序列
  8. 动态规划:不同的子序列
  9. 动态规划:两个字符串的删除操作
  10. 动态规划:编辑距离
  11. 为了绝杀编辑距离,Carl做了三步铺垫,你都知道么?
  12. 动态规划:回文子串
  13. 动态规划:最长回文子序列
  14. 动态规划总结篇

(持续更新中.)

单调栈

  1. 单调栈:每日温度
  2. 单调栈:下一个更大元素I

图论

十大排序

数论

高级数据结构经典题目

  • 并查集
  • 最小生成树
  • 线段树
  • 树状数组
  • 字典树

海量数据处理

算法模板

各类基础算法模板

B站算法视频讲解

以下为B站「代码随想录」算法讲解视频:

(持续更新中.)

贡献者

你可以点此链接查看LeetCode-大师的所有贡献者。感谢你们补充了LeetCode-大师的其他语言版本,让更多的读者收益于此项目。

关于作者

大家好,我是程序员carl,哈工大师兄,acm校赛、黑龙江省赛、东北四省赛金牌、亚洲区域赛铜牌获得者,先后在腾讯和百度从事后端技术研发,csdn博客专家。对算法和C++后端技术有一定的见解,利用工作之余重新刷leetcode。

加入刷题微信群,备注:“个人简单介绍”+组队刷题

(也欢迎与我交流,备注:“个人简单介绍”+交流,围观朋友圈,做点赞之交(备注没有自我介绍不通过哦)


公众号

更多精彩文章持续更新,微信搜索:“代码随想录”第一时间围观,关注后回复:“666PDF”可以获得所有算法专题原创。

“代码随想录”每天准时为你推送一篇经典面试题目,帮你梳理算法知识体系,轻松学习算法!、并且公众号里有大量学习资源,也有我自己的学习心得和方法总结,更有上万录友们在这里打卡学习.

来看看就知道了,你会发现相见恨晚!