목차
함수 재이해
什么是函数式编程?
递归
함수형 프로그래밍이란 무엇인가요?
재귀
嵌套函数
闭包
闭包的问题
Lambdas
装饰器
백엔드 개발 파이썬 튜토리얼 Python 함수, 재귀 및 클로저를 사용하는 방법

Python 함수, 재귀 및 클로저를 사용하는 방법

May 10, 2023 pm 12:19 PM
python

함수 재이해

우리는 이미 데이터 유형과 불변성의 함수에 노출되었습니다. 해당 기사를 아직 읽지 않았다면 지금 돌아가서 읽어 보시기를 권합니다.

우리가 같은 차원에 있는지 확인하기 위해 간단한 함수 예를 살펴보겠습니다.

def cheer(volume=None):
    if volume is None:
        print("yay.")
    elif volume == "Louder!":
        print("yay!")
    elif volume == "LOUDER!":
        print("*deep breath*")
        print("yay!")


cheer()  # prints "yay."
cheer("Louder!")  # prints "yay!"
cheer("LOUDER!")  # prints "*deep breath* ...yay!"
로그인 후 복사

여기서는 놀랄 일이 아닙니다. cheer() 함수는 단일 매개변수 volume을 허용합니다. volume에 대한 매개변수를 전달하지 않으면 기본값은 None입니다. cheer()接受单个参数volume。如果我们不为volume传递参数,它将默认为None

什么是函数式编程?

我们这些来自面向对象编程语言的人已经学会了从类和对象的角度来思考一切。数据被组织成对象,以及负责访问和修改该数据的函数。有时这可行,但有时,类开始感觉像太多模板。

函数式编程几乎与此相反。我们围绕函数进行组织,我们通过这些函数传递数据。我们必须遵守一些规则:

  • 函数应该只接受输入,只产生输出。

  • 函数不应该有副作用;他们不应该修改任何外部的东西。

  • 函数应该(理想情况下)总是为相同的输入产生相同的输出。函数内部不应该有会破坏这种模式的状态。

现在,在你将所有 Python 代码重写为纯函数式之前,停止!不要忘记 Python 的一大优点是它是一种多范式语言。你不必选择一种范式并坚持下去;你可以在你的代码中混合搭配,这样是最好的。

事实上,我们已经这样做了!迭代器和生成器都是从函数式编程中参考而来的,它们与对象一起工作得很好。也可以随意合并 lambda、装饰器和闭包。这一切都是为了选择最适合这项工作的工具。

在实践中,我们很少能同时避免副作用。在将函数式编程的概念应用到 Python 代码中时,你应该更多地关注和慎重考虑副作用,而不是完全避免它们。将它们限制在没有更好方法解决问题的情况下。这里没有硬性规定可以依靠。你需要培养自己的洞察力。

递归

当一个函数调用自身时,这称为递归。当我们需要重复函数的整个逻辑,但循环不合适(或者感觉太混乱)时,这会很有帮助。

注意:我下面的示例被简化以突出递归本身。这实际上并不是递归是最佳方法的情况。当你需要对不同的数据块重复调用复杂的语言时,例如当你遍历树结构时,递归 会更好。

import random
random.seed()


class Villain:

    def __init__(self):
        self.defeated = False

    def confront(self):
        # Roll of the dice.
        if random.randint(0,10) == 10:
            self.defeated = True


def defeat(villain):
    villain.confront()
    if villain.defeated:
        print("Yay!")
        return True
    else:
        print("Keep trying...")
        return defeat(villain)


starlight = Villain()
victory = defeat(starlight)

if victory:
    print("YAY!")
로그인 후 복사

random相关的东西可能看起来很新。它与这个主题并没有真正相关,但简而言之,我们可以通过在程序开始时用随机数生成器生成随机数 (random.seed()),然后调用random.randint(min, max), 函数里面的minmax定义可能值的包含范围。

这里逻辑的重要部分是defeat()函数。只要villain 没有被打败,函数就会调用自己,传递villain变量,直到其中一个函数调用返回一个值。在这种情况下,该值在递归调用堆栈中返回,最终存储在victory.

不管花多长时间*

함수형 프로그래밍이란 무엇인가요?

객체 지향 프로그래밍 언어 출신인 우리는 모든 것을 클래스와 객체 측면에서 생각하는 법을 배웠습니다. 데이터는 개체와 해당 데이터에 대한 액세스 및 수정을 담당하는 기능으로 구성됩니다. 때로는 이것이 효과가 있지만 때로는 클래스가 너무 많은 템플릿처럼 느껴지기 시작합니다.

함수형 프로그래밍은 거의 그 반대입니다. 우리는 데이터를 전달하는 함수

를 중심으로 구성됩니다. 몇 가지 규칙을 따라야 합니다:

  • 함수는 입력만 허용하고 출력만 생성해야 합니다.

  • 함수에는 부작용이 있어서는 안 됩니다. 외부의 어떤 것도 수정해서는 안 됩니다.

  • 함수는 (이상적으로) 항상 동일한 입력에 대해 동일한 출력을 생성해야 합니다. 함수 내부에는 이 패턴을 깨는 상태가 있어서는 안 됩니다.

  • 이제 모든 Python 코드를 순전히 기능적으로 다시 작성하기 전에

    중지하세요!

    Python의 가장 큰 장점 중 하나는

    다중 패러다임 언어
    라는 점을 잊지 마세요. 하나의 패러다임을 선택하고 이를 고수할 필요는 없으며 코드에 가장 적합한 것을 혼합하여 사용할 수 있습니다.

    사실 우리는 이미 그렇게 하고 있습니다! 반복자와 생성기는 모두 함수형 프로그래밍에서 참조되며 객체와 잘 작동합니다. 람다, 데코레이터, 클로저도 자유롭게 결합해 보세요. 작업에 가장 적합한 도구를 선택하는 것이 중요합니다.

    실제로 부작용을 동시에 피하는 경우는 거의 없습니다. 함수형 프로그래밍 개념을 Python 코드에 적용할 때는 부작용을 완전히 피하기보다는 부작용에 더 주의를 기울이고 신중하게 고려해야 합니다. 문제를 해결하는 더 좋은 방법이 없는 상황으로 제한하십시오. 여기에 의존할 엄격하고 빠른 규칙은 없습니다. 당신은 자신의 분별력을 키워야 합니다.

    재귀

    함수가 자신을 호출하는 것을재귀라고 합니다. 이 기능은 함수의 전체 논리를 반복해야 하지만 루프가 적합하지 않거나 너무 혼란스러울 때 유용합니다.

    참고: 아래 예는 재귀 자체를 강조하기 위해 단순화되었습니다. 실제로 재귀가 최선의 접근 방식인 경우는 아닙니다. 트리 구조를 순회하는 경우와 같이 다양한 데이터 청크에서 복잡한 언어를 반복적으로 호출해야 하는 경우 재귀가 더 좋습니다. 🎜

    def mirror_pool(lookers):
        reflections = []
        for looker in lookers:
            reflections.append(looker)
        lookers.append(reflections)
    
        print(f"We have {len(lookers) - 1} duplicates.")
    
        return mirror_pool(lookers)
    
    
    duplicates = mirror_pool(["Pinkie Pie"])
    로그인 후 복사

    무작위와 관련된 것들이 새롭게 보일 수도 있습니다. 이 주제와는 실제로 관련이 없지만 간단히 말해서 프로그램 시작 부분에서 난수 생성기(random.seed())를 사용한 다음 random을 호출하여 난수를 생성할 수 있습니다. 함수의 .randint(min, max), minmax는 가능한 값의 범위를 정의합니다. 🎜

    여기서 로직의 중요한 부분은 defeat() 함수입니다. 악당이 패배하지 않는 한, 함수 호출 중 하나가 값을 반환할 때까지 함수는 villain 변수를 전달하여 자신을 호출합니다. 이 경우 값은 재귀 호출 스택에 반환되어 결국 victory에 저장됩니다.🎜

    얼마나 시간이 걸려도 *, 우리는 결국 그 악당을 물리칠 것입니다. 🎜🎜무한 재귀를 조심하세요🎜🎜재귀는 강력한 도구일 수 있지만 문제도 발생합니다. 🎜멈출 방법이 없다면 어떻게 될까요? 🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">try:     duplicates = mirror_pool([&quot;Pinkie Pie&quot;]) except RecursionError:     print(&quot;Time to watch paint dry.&quot;)</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div>🎜분명히 이것은 영원히 계속될 것입니다! 일부 언어에서는 이를 처리하는 깔끔한 방법을 제공하지 않습니다. 함수는 충돌이 발생할 때까지 무한히 반복됩니다. 🎜🎜Python은 이러한 광기를 더욱 우아하게 막아줍니다. 설정된 재귀 깊이에 도달하면(보통 997-1000회) 전체 프로그램이 중지되고 오류가 발생합니다. 🎜🎜🎜RecursionError: Python 객체를 호출하는 동안 최대 재귀 깊이가 초과되었습니다. 🎜🎜🎜 모든 오류와 마찬가지로 발견할 수 있습니다. 상황이 통제 불가능해지기 전에: 🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">try:     duplicates = mirror_pool([&quot;Pinkie Pie&quot;]) except RecursionError:     print(&quot;Time to watch paint dry.&quot;)</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div> <p data-id="p838747a-QN2iZZA8">值得庆幸的是,由于我编写这段代码的方式,我实际上不需要做任何特别的事情来清理 997 个重复项。递归函数从未返回,因此<code>duplicates在这种情况下保持未定义。

    但是,我们可能希望以另一种方式控制递归,因此我们不必使用 try-except来防止灾难。在我们的递归函数中,我们可以通过添加一个参数来跟踪它被调用的次数calls,并在它变得太大时立即中止。

    def mirror_pool(lookers, calls=0):
        calls += 1
    
        reflections = []
        for looker in lookers:
            reflections.append(looker)
        lookers.append(reflections)
    
        print(f"We have {len(lookers) - 1} duplicates.")
    
        if calls < 20:
            lookers = mirror_pool(lookers, calls)
    
        return lookers
    
    
    duplicates = mirror_pool(["Pinkie Pie"])
    print(f"Grand total: {len(duplicates)} Pinkie Pies!")
    로그인 후 복사

    我们仍然需要弄清楚如何在不丢失原始数据的情况下删除 20 个重复项,但至少程序没有崩溃。

    注意:你可以使用sys.setrecursionlimit(n)覆盖最大递归级别,其中n是你想要的最大值。

    嵌套函数

    有时,我们可能想要一个函数中重用一段逻辑,但我们不想通过创建另一个函数来弄乱我们的代码。

    def use_elements(target):
        elements = ["Honesty", "Kindness", "Laughter",
                    "Generosity", "Loyalty", "Magic"]
    
        def use(element, target):
            print(f"Using Element of {element} on {target}.")
    
        for element in elements:
            use(element, target)
    
    
    use_elements("Nightmare Moon")
    로그인 후 복사

    当然,这个简单的例子的问题在于它的用处不是很明显。当我们想要将大量逻辑抽象为函数以实现可重用性但又不想在主函数之外定义时,嵌套函数会变得很有帮助。如果use()函数要复杂得多,并且可能不仅仅是循环调用,那么这种设计将是合理的。

    尽管如此,该示例的简单性仍然体现了基本概念。这也带来了另一个困难。你会注意到,每次我们调用它时use(),我们都在传递target给内部函数,这感觉毫无意义。我们不能只使用已经在本地范围内的target变量吗?

    事实上,我们可以:

    def use_elements(target):
        elements = ["Honesty", "Kindness", "Laughter",
                    "Generosity", "Loyalty", "Magic"]
    
        def use(element):
            print(f"Using Element of {element} on {target}.")
    
        for element in elements:
            use(element)
    
    
    use_elements("Nightmare Moon")
    로그인 후 복사

    然而,一旦我们尝试修改该变量,我们就会遇到麻烦:

    def use_elements(target):
        elements = ["Honesty", "Kindness", "Laughter",
                    "Generosity", "Loyalty", "Magic"]
    
        def use(element):
            print(f"Using Element of {element} on {target}.")
            target = "Luna"
    
        for element in elements:
            use(element)
    
        print(target)
    
    
    use_elements("Nightmare Moon")
    로그인 후 복사

    运行该代码会引发错误:

    UnboundLocalError: local variable 'target' referenced before assignment

    显然,它不再认识我们的局部变量target。这是因为默认情况下,分配给变量时会覆盖封闭范围中的任何已有相同的变量。因此,该行target == "Luna"试图创建一个限制在use()范围内的新变量,并在use_elements()的封闭范围内隐藏已有的target变量。与Python 看到了这一点并假设,因为我们在 use()函数中定义了target,所以对该变量的所有引用都与该本地名称相关。这不是我们想要的!

    关键字nonlocal允许我们告诉内部函数我们正在使用来自封闭局部范围target变量。

    def use_elements(target):
        elements = ["Honesty", "Kindness", "Laughter",
                    "Generosity", "Loyalty", "Magic"]
    
        def use(element):
            nonlocal target
            print(f"Using Element of {element} on {target}.")
            target = "Luna"
    
        for element in elements:
            use(element)
    
        print(target)
    
    
    use_elements("Nightmare Moon")
    로그인 후 복사

    现在,运行结果,我们看到了打印出来的值Luna。我们在这里的工作完成了!

    注意:如果你希望函数能够修改定义为全局范围(在所有函数之外)的变量,请使用global关键字而不是nonlocal

    闭包

    基于嵌套函数的思想,我们可以创建一个函数,该函数实际上构建并返回另一个函数(称为闭包)。

    def harvester(pony):
        total_trees = 0
    
        def applebucking(trees):
            nonlocal pony, total_trees
            total_trees += trees
            print(f"{pony} harvested from {total_trees} trees so far.")
    
        return applebucking
    
    
    apple_jack = harvester("Apple Jack")
    big_mac = harvester("Big Macintosh")
    apple_bloom = harvester("Apple Bloom")
    
    north_orchard = 120
    west_orchard = 80  # watch out for fruit bats
    east_orchard = 135
    south_orchard = 95
    near_house = 20
    
    apple_jack(west_orchard)
    big_mac(east_orchard)
    apple_bloom(near_house)
    big_mac(north_orchard)
    apple_jack(south_orchard)
    로그인 후 복사

    在此示例中,applebucking()就是闭包,因为它关闭了非局部变量ponytotal_trees。即使在外部函数终止后,闭包仍保留对这些变量的引用。

    闭包从harvester()函数返回,并且可以像任何其他对象一样存储在变量中。正是因为它“关闭”了一个非局部变量,这使得它本身就是一个闭包。否则,它只是一个函数。

    在这个例子中,我使用闭包来有效地创建带有状态的对象。换句话说,每个收割机都记得他或她从多少棵树上收割过。这种特殊用法并不严格符合函数式编程,但如果你不想创建一个完整的类来存储一个函数的状态,它会非常有用!

    apple_jack, big_macintosh, 和apple_bloom现在是三个不同的函数,每个函数都有自己独立的状态;他们每个人都有不同的名字,并记住他们收获了多少棵树。在一个闭包状态中发生的事情对其他闭包状态没有影响,他们都是独立的个体。

    当我们运行代码时,我们看到了这个状态:

    Apple Jack harvested from 80 trees so far.
    Big Macintosh harvested from 135 trees so far.
    Apple Bloom harvested from 20 trees so far.
    Big Macintosh harvested from 255 trees so far.
    Apple Jack harvested from 175 trees so far.
    로그인 후 복사

    闭包的问题

    闭包本质上是“隐式类”,因为它们将功能及其持久信息(状态)放在同一个对象中。然而,闭包有几个独特的缺点:

    • 你不能按原样访问“成员变量”。在我们的示例中,我永远无法访问闭包apple_jack上的变量total_trees!我只能在闭包自己的代码的上下文中使用该变量。

    • 关闭状态是完全不透明的。除非你知道闭包是如何编写的,否则你不知道它记录了哪些信息。

    • 由于前面两点,根本不可能直接知道闭包何时具有任何状态

    使用闭包时,你需要准备好处理这些问题,以及它们带来的所有调试困难。我建议在你需要单个函数来存储调用之间的少量私有状态时才使用它们,并且仅在代码中如此有限的时间段内使用它们,以至于编写整个类并不合理。(另外,不要忘记生成器和协程,它们可能更适合许多此类场景。)

    闭包仍然可以成为 Python中有用的部分,只要你非常小心地使用它们。

    Lambdas

    lambda是由单个表达式组成的匿名函数(无名称)。

    仅此定义就是许多程序员无法想象他们为什么需要一个定义的原因。编写一个没有名称的函数有什么意义,基本上使重用完全不切实际?当然,你可以lambda 分配给一个变量,但此时,你不应该刚刚编写了一个函数吗?

    为了理解这一点,让我们先看一个没有lambdas 的例子:

    class Element:
    
        def __init__(self, element, color, pony):
            self.element = element
            self.color = color
            self.pony = pony
    
        def __repr__(self):
            return f"Element of {self.element} ({self.color}) is attuned to {self.pony}"
    
    
    elements = [
        Element("Honesty", "Orange", "Apple Jack"),
        Element("Kindness", "Pink", "Fluttershy"),
        Element("Laughter", "Blue", "Pinkie Pie"),
        Element("Generosity", "Violet", "Rarity"),
        Element("Loyalty", "Red", "Rainbow Dash"),
        Element("Magic", "Purple", "Twilight Sparkle")
    ]
    
    
    def sort_by_color(element):
        return element.color
    
    
    elements = sorted(elements, key=sort_by_color)
    print(elements)
    로그인 후 복사

    我希望你注意的主要事情是sort_by_color()函数,我必须编写该函数以明确按颜色对列表中的 Element 对象进行排序。实际上,这有点烦人,因为我再也不需要那个功能了。

    这就是 lambdas 的用武之地。我可以删除整个函数,并将elements = sorted(...)行更改为:

    elements = sorted(elements, key=lambda e: e.color)
    로그인 후 복사

    使用 lambda 可以让我准确地描述我的逻辑我在哪里使用它,而不是在其他任何地方。(这key=部分只是表明我将 lambda 传递给sorted()函数的key的参数。)

    一个 lambda 具有结构lamba <parameters>: <return expression></pre>。它可以收集任意数量的参数,用逗号分隔,但它只能有一个表达式,其值是隐式返回的。

    注意:与常规函数不同,Lambda 不支持类型注释(类型提示)。

    如果我想重写那个 lambda 以按元素的名称而不是颜色排序,我只需要更改表达式部分:

    elements = sorted(elements, key=lambda e: e.name)
    로그인 후 복사

    就这么简单。

    同样,lambda在需要将带有单个表达式的函数传递给另一个函数时非常有用。这是另一个示例,这次在 lambda 上使用了更多参数。

    为了设置这个示例,让我们从 Flyer 的类开始,它存储名称和最大速度,并返回 Flyer 的随机速度。

    import random
    random.seed()
    
    
    class Flyer:
    
        def __init__(self, name, top_speed):
            self.name = name
            self.top_speed = top_speed
    
        def get_speed(self):
            return random.randint(self.top_speed//2, self.top_speed)
    로그인 후 복사

    我们希望能够让任何给定的 Flyer 对象执行任何飞行技巧,但是将所有这些逻辑放入类本身是不切实际的……可能有成千上万的飞行技巧和变体!

    Lambdas是定义这些技巧的一种方式。我们将首先向该类添加一个函数,该函数可以接受函数作为参数。我们假设这个函数总是有一个参数:执行技巧的速度。

    def perform(self, trick):
            performed = trick(self.get_speed())
            print(f"{self.name} perfomed a {performed}")
    로그인 후 복사

    要使用它,我们创建一个 Flyer 对象,然后将函数传递给它的perform()方法。

    rd = Flyer("Rainbow Dash", 780)
    rd.perform(lambda s: f"barrel-roll at {s} mph.")
    rd.perform(lambda s: f"flip at {s} mph.")
    로그인 후 복사

    因为 lambda 的逻辑在函数调用中,所以更容易看到发生了什么。

    回想一下,你可以将 lambdas 存储在变量中。当你希望代码如此简短但需要一些可重用性时,这实际上会很有帮助。例如,假设我们有另一个 Flyer,我们希望他们两个都进行barrelroll。

    spitfire = Flyer("Spitfire", 650)
    barrelroll = lambda s: f"barrel-roll at {s} mph."
    
    spitfire.perform(barrelroll)
    rd.perform(barrelroll)
    로그인 후 복사

    当然,我们可以将barrelroll写成一个适当的单行函数,但是通过这种方式,我们为自己节省了一些样板文件。而且,由于在这段代码之后我们不会再次使用该逻辑,因此没有必要再使用一个成熟的函数。

    再一次,可读性很重要。Lambda 非常适合用于简短、清晰的逻辑片段,但如果你有更复杂的事情,你还是应该编写一个合适的函数。

    装饰器

    假设我们想要修改任何函数的行为,而不实际更改函数本身。

    让我们从一个相当基本的函数开始:

    def partial_transfiguration(target, combine_with):
        result = f"{target}-{combine_with}"
        print(f"Transfiguring {target} into {result}.")
        return result
    
    
    target = "frog"
    target = partial_transfiguration(target, "orange")
    print(f"Target is now a {target}.")
    로그인 후 복사

    运行给我们:

    Transfiguring frog into frog-orange.
    Target is now a frog-orange.
    로그인 후 복사

    很简单,对吧。但是,如果我们想为此添加一些额外的宣传呢?如你所知,我们真的不应该将这种逻辑放在我们的partial_transfiguration函数中。

    这就是装饰器的用武之地。装饰器“包装”了函数周围的附加逻辑,这样我们实际上不会修改原始函数本身。这使得代码更易于维护。

    让我们从为大张旗鼓创建一个装饰器开始。这里的语法一开始可能看起来有点过于复杂,但请放心,我会详细介绍。

    import functools
    
    
    def party_cannon(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print("Waaaaaaaait for it...")
            r = func(*args, **kwargs)
            print("YAAY! *Party cannon explosion*")
            return r
    
        return wrapper
    로그인 후 복사

    你可能已经认识到wrapper()它实际上是一个闭包,它是由我们的party_cannon()函数创建并返回的。我们传递我们正在“装饰”的函数,func

    然而,我们真的对我们装饰的函数一无所知!它可能有也可能没有参数。闭包的参数列表(*args, **kwargs)实际上可以接受任何数量的参数,从零到无穷大。调用func()时,我们以相同的方式将这些参数传递给func()

    当然,如果func()上的参数列表与通过装饰器传递给它的参数之间存在某种不匹配,则会引发通常和预期的错误(这显然是一件好事)。

    wrapper()内部,我们可以随时随地调用我们的函数func()。我选择在打印我的两条消息之间这样做。

    我不想丢弃func()返回的值,所以我将返回的值分配给r,并确保在装饰器的末尾用return r.

    请注意,对于在装饰器中调用函数的方式,或者即使调用它或调用多少次,实际上并没有硬性规定。你还可以以任何你认为合适的方式处理参数和返回值。关键是要确保装饰器实际上不会以某种意想不到的方式破坏它装饰的函数。

    装饰器前的奇数行,@functools.wraps(func),实际上是一个装饰器本身。没有它,被装饰的函数本质上会混淆它自己的身份,弄乱我们对__doc__(文档字符串)和__name__.。这个特殊的装饰器确保不会发生这种情况;被包装的函数保留自己的身份,可以从函数外部以所有常用方式访问。(要使用那个特殊的装饰器,我们必须首先import functools。)

    现在我们已经编写了party_cannon装饰器,我们可以使用它来添加我们想要的partial_transfiguration()函数。这样做很简单:

    @party_cannon
    def partial_transfiguration(target, combine_with):
        result = f"{target}-{combine_with}"
        print(f"Transfiguring {target} into {result}.")
        return result
    로그인 후 복사

    第一行,@party_cannon是我们做出的唯一改变!partial_transfiguration函数现在已装饰

    注意:你甚至可以将多个装饰器堆叠在一起,一个在下一个之上。只需确保每个装饰器紧接在它所包装的函数或装饰器之前。

    我们以前的用法根本没有改变:

    target = "frog"
    target = partial_transfiguration(target, "orange")
    print(f"Target is now a {target}.")
    로그인 후 복사

    然而输出确实发生了变化:

    Waaaaaaaait for it...
    Transfiguring frog into frog-orange.
    YAAY! *Party cannon explosion*
    Target is now a frog-orange.
    로그인 후 복사

    위 내용은 Python 함수, 재귀 및 클로저를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

    핫 AI 도구

    Undresser.AI Undress

    Undresser.AI Undress

    사실적인 누드 사진을 만들기 위한 AI 기반 앱

    AI Clothes Remover

    AI Clothes Remover

    사진에서 옷을 제거하는 온라인 AI 도구입니다.

    Undress AI Tool

    Undress AI Tool

    무료로 이미지를 벗다

    Clothoff.io

    Clothoff.io

    AI 옷 제거제

    AI Hentai Generator

    AI Hentai Generator

    AI Hentai를 무료로 생성하십시오.

    인기 기사

    R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
    3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. 최고의 그래픽 설정
    3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
    3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
    WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
    3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

    뜨거운 도구

    메모장++7.3.1

    메모장++7.3.1

    사용하기 쉬운 무료 코드 편집기

    SublimeText3 중국어 버전

    SublimeText3 중국어 버전

    중국어 버전, 사용하기 매우 쉽습니다.

    스튜디오 13.0.1 보내기

    스튜디오 13.0.1 보내기

    강력한 PHP 통합 개발 환경

    드림위버 CS6

    드림위버 CS6

    시각적 웹 개발 도구

    SublimeText3 Mac 버전

    SublimeText3 Mac 버전

    신 수준의 코드 편집 소프트웨어(SublimeText3)

    MySQL은 지불해야합니다 MySQL은 지불해야합니다 Apr 08, 2025 pm 05:36 PM

    MySQL에는 무료 커뮤니티 버전과 유료 엔터프라이즈 버전이 있습니다. 커뮤니티 버전은 무료로 사용 및 수정할 수 있지만 지원은 제한되어 있으며 안정성이 낮은 응용 프로그램에 적합하며 기술 기능이 강합니다. Enterprise Edition은 안정적이고 신뢰할 수있는 고성능 데이터베이스가 필요하고 지원 비용을 기꺼이 지불하는 응용 프로그램에 대한 포괄적 인 상업적 지원을 제공합니다. 버전을 선택할 때 고려 된 요소에는 응용 프로그램 중요도, 예산 책정 및 기술 기술이 포함됩니다. 완벽한 옵션은없고 가장 적합한 옵션 만 있으므로 특정 상황에 따라 신중하게 선택해야합니다.

    설치 후 MySQL을 사용하는 방법 설치 후 MySQL을 사용하는 방법 Apr 08, 2025 am 11:48 AM

    이 기사는 MySQL 데이터베이스의 작동을 소개합니다. 먼저 MySQLworkBench 또는 명령 줄 클라이언트와 같은 MySQL 클라이언트를 설치해야합니다. 1. MySQL-Uroot-P 명령을 사용하여 서버에 연결하고 루트 계정 암호로 로그인하십시오. 2. CreateABase를 사용하여 데이터베이스를 작성하고 데이터베이스를 선택하십시오. 3. CreateTable을 사용하여 테이블을 만들고 필드 및 데이터 유형을 정의하십시오. 4. InsertInto를 사용하여 데이터를 삽입하고 데이터를 쿼리하고 업데이트를 통해 데이터를 업데이트하고 DELETE를 통해 데이터를 삭제하십시오. 이러한 단계를 마스터하고 일반적인 문제를 처리하는 법을 배우고 데이터베이스 성능을 최적화하면 MySQL을 효율적으로 사용할 수 있습니다.

    다운로드 후 MySQL을 설치할 수 없습니다 다운로드 후 MySQL을 설치할 수 없습니다 Apr 08, 2025 am 11:24 AM

    MySQL 설치 실패의 주된 이유는 다음과 같습니다. 1. 권한 문제, 관리자로 실행하거나 Sudo 명령을 사용해야합니다. 2. 종속성이 누락되었으며 관련 개발 패키지를 설치해야합니다. 3. 포트 충돌, 포트 3306을 차지하는 프로그램을 닫거나 구성 파일을 수정해야합니다. 4. 설치 패키지가 손상되어 무결성을 다운로드하여 확인해야합니다. 5. 환경 변수가 잘못 구성되었으며 운영 체제에 따라 환경 변수를 올바르게 구성해야합니다. 이러한 문제를 해결하고 각 단계를 신중하게 확인하여 MySQL을 성공적으로 설치하십시오.

    MySQL 다운로드 파일이 손상되어 설치할 수 없습니다. 수리 솔루션 MySQL 다운로드 파일이 손상되어 설치할 수 없습니다. 수리 솔루션 Apr 08, 2025 am 11:21 AM

    MySQL 다운로드 파일은 손상되었습니다. 어떻게해야합니까? 아아, mySQL을 다운로드하면 파일 손상을 만날 수 있습니다. 요즘 정말 쉽지 않습니다! 이 기사는 모든 사람이 우회를 피할 수 있도록이 문제를 해결하는 방법에 대해 이야기합니다. 읽은 후 손상된 MySQL 설치 패키지를 복구 할 수있을뿐만 아니라 향후에 갇히지 않도록 다운로드 및 설치 프로세스에 대해 더 깊이 이해할 수 있습니다. 파일 다운로드가 손상된 이유에 대해 먼저 이야기합시다. 이에 대한 많은 이유가 있습니다. 네트워크 문제는 범인입니다. 네트워크의 다운로드 프로세스 및 불안정성의 중단으로 인해 파일 손상이 발생할 수 있습니다. 다운로드 소스 자체에도 문제가 있습니다. 서버 파일 자체가 고장 났으며 물론 다운로드하면 고장됩니다. 또한 일부 안티 바이러스 소프트웨어의 과도한 "열정적 인"스캔으로 인해 파일 손상이 발생할 수 있습니다. 진단 문제 : 파일이 실제로 손상되었는지 확인하십시오

    MySQL 설치 후 시작할 수없는 서비스에 대한 솔루션 MySQL 설치 후 시작할 수없는 서비스에 대한 솔루션 Apr 08, 2025 am 11:18 AM

    MySQL이 시작을 거부 했습니까? 당황하지 말고 확인합시다! 많은 친구들이 MySQL을 설치 한 후 서비스를 시작할 수 없다는 것을 알았으며 너무 불안했습니다! 걱정하지 마십시오.이 기사는 침착하게 다루고 그 뒤에있는 마스터 마인드를 찾을 수 있습니다! 그것을 읽은 후에는이 문제를 해결할뿐만 아니라 MySQL 서비스에 대한 이해와 문제 해결 문제에 대한 아이디어를 향상시키고보다 강력한 데이터베이스 관리자가 될 수 있습니다! MySQL 서비스는 시작되지 않았으며 간단한 구성 오류에서 복잡한 시스템 문제에 이르기까지 여러 가지 이유가 있습니다. 가장 일반적인 측면부터 시작하겠습니다. 기본 지식 : 서비스 시작 프로세스 MySQL 서비스 시작에 대한 간단한 설명. 간단히 말해서 운영 체제는 MySQL 관련 파일을로드 한 다음 MySQL 데몬을 시작합니다. 여기에는 구성이 포함됩니다

    MySQL은 인터넷이 필요합니까? MySQL은 인터넷이 필요합니까? Apr 08, 2025 pm 02:18 PM

    MySQL은 기본 데이터 저장 및 관리를위한 네트워크 연결없이 실행할 수 있습니다. 그러나 다른 시스템과의 상호 작용, 원격 액세스 또는 복제 및 클러스터링과 같은 고급 기능을 사용하려면 네트워크 연결이 필요합니다. 또한 보안 측정 (예 : 방화벽), 성능 최적화 (올바른 네트워크 연결 선택) 및 데이터 백업은 인터넷에 연결하는 데 중요합니다.

    고로드 애플리케이션의 MySQL 성능을 최적화하는 방법은 무엇입니까? 고로드 애플리케이션의 MySQL 성능을 최적화하는 방법은 무엇입니까? Apr 08, 2025 pm 06:03 PM

    MySQL 데이터베이스 성능 최적화 안내서 리소스 집약적 응용 프로그램에서 MySQL 데이터베이스는 중요한 역할을 수행하며 대규모 트랜잭션 관리를 담당합니다. 그러나 응용 프로그램 규모가 확장됨에 따라 데이터베이스 성능 병목 현상은 종종 제약이됩니다. 이 기사는 일련의 효과적인 MySQL 성능 최적화 전략을 탐색하여 응용 프로그램이 고 부하에서 효율적이고 반응이 유지되도록합니다. 실제 사례를 결합하여 인덱싱, 쿼리 최적화, 데이터베이스 설계 및 캐싱과 같은 심층적 인 주요 기술을 설명합니다. 1. 데이터베이스 아키텍처 설계 및 최적화 된 데이터베이스 아키텍처는 MySQL 성능 최적화의 초석입니다. 몇 가지 핵심 원칙은 다음과 같습니다. 올바른 데이터 유형을 선택하고 요구 사항을 충족하는 가장 작은 데이터 유형을 선택하면 저장 공간을 절약 할 수있을뿐만 아니라 데이터 처리 속도를 향상시킬 수 있습니다.

    MySQL 설치 후 데이터베이스 성능을 최적화하는 방법 MySQL 설치 후 데이터베이스 성능을 최적화하는 방법 Apr 08, 2025 am 11:36 AM

    MySQL 성능 최적화는 설치 구성, 인덱싱 및 쿼리 최적화, 모니터링 및 튜닝의 세 가지 측면에서 시작해야합니다. 1. 설치 후 innodb_buffer_pool_size 매개 변수와 같은 서버 구성에 따라 my.cnf 파일을 조정해야합니다. 2. 과도한 인덱스를 피하기 위해 적절한 색인을 작성하고 Execution 명령을 사용하여 실행 계획을 분석하는 것과 같은 쿼리 문을 최적화합니다. 3. MySQL의 자체 모니터링 도구 (showprocesslist, showstatus)를 사용하여 데이터베이스 건강을 모니터링하고 정기적으로 백업 및 데이터베이스를 구성하십시오. 이러한 단계를 지속적으로 최적화함으로써 MySQL 데이터베이스의 성능을 향상시킬 수 있습니다.

    See all articles