Detaillierte Einführung in Flusskontrollanweisungen in Python

零下一度
Freigeben: 2017-07-18 10:30:48
Original
2337 Leute haben es durchsucht

Python übernimmt neben der gerade eingeführten while-Anweisung auch andere Flusskontrollanweisungen aus anderen Sprachen und nimmt entsprechende Änderungen vor. Detaillierte Einführung in Flusskontrollanweisungen in Python

4.1 if-Anweisungen

Die vielleicht bekannteste Anweisung ist die if-Anweisung. Beispiel:

x = int(input("Please enter an integer: "))if x < 0:
    x = 0print(&#39;Negative changed to zero&#39;)elif x == 0:print(&#39;Zero&#39;)elif x == 1:print(&#39;Single&#39;)else:print(&#39;More&#39;)
Nach dem Login kopieren

kann null oder mehr elif-Klauseln haben, und die else-Klauseln sind optional. Das Schlüsselwort elif ist eine intermittierende Form von else if, wodurch eine übermäßige Einrückung vermieden werden kann. Die if ... elif ... elif ...-Sequenz ist ein Ersatz für die switch- oder case-Anweisungen in anderen Sprachen.

4.2 for-Anweisungen

Die for-Anweisung in Python unterscheidet sich geringfügig von der for-Anweisung in C oder Pacsal. Python verwendet weder die Methode zum Iterieren arithmetischer Folgezahlen (in Pascal), um Schleifen zu implementieren, noch verwendet es die Methode zum Definieren der Anzahl von Iterationsschritten und Stoppbedingungen wie die C-Sprache, um Schleifen zu implementieren in beliebiger Reihenfolge durchläuft die Elemente (Liste oder Zeichenfolge) in der Reihenfolge, in der sie in der Reihenfolge erscheinen. Beispiel (keine andere Bedeutung): for

# Measure some strings:words = [&#39;cat&#39;, &#39;window&#39;, &#39;defenestrate&#39;]for w in words:print(w, len(w))
Nach dem Login kopieren
Wenn Sie die Sequenz ändern müssen, die innerhalb der Schleife durchlaufen wird (z. B. das ausgewählte Element kopieren), wird empfohlen, das zu kopieren Reihenfolge zuerst. Beim Durchlaufen der Sequenz werden implizit keine Backups erstellt. Slicing-Anweisungen eignen sich besonders zum Kopieren von Sequenzen:

for w in words[:]:  # Loop over a slice copy of the entire list.if len(w) > 6:
        words.insert(0, w)
words
Nach dem Login kopieren
Mit

versucht die Instanz, eine unendliche Liste zu erstellen, indem sie ständig die Zeichenfolge for w in words:O einfügt. defenestrate

4.3 Die

-Funktionrange()

Wenn Sie wirklich über eine Zahlenfolge iterieren müssen, kann die integrierte Funktion

nützlich sein. Diese Funktion generiert eine arithmetische Sequenz: range()

>>> for i in range(5):
...     print(i)
...01234
Nach dem Login kopieren

Die Parameter werden nicht in die generierte Sequenz einbezogen. end generiert 10 Werte, die zulässige Indexlänge der Sequenz Artikel ist 10. Sie können den Bereich bei einer anderen Zahl beginnen oder ein anderes Inkrement angeben (sogar eine negative Zahl; manchmal wird das Inkrement als „Schritt“ bezeichnet): range(10)

range(5, 10)   5 through 9range(0, 10, 3)   0, 3, 6, 9range(-10, -100, -30)  -10, -40, -70
Nach dem Login kopieren
erforderlich Beim Iterieren B. den Index einer Sequenz, können Sie die Funktionen

und range() wie folgt kombinieren: len()

>>> a = [&#39;Mary&#39;, &#39;had&#39;, &#39;a&#39;, &#39;little&#39;, &#39;lamb&#39;]>>> for i in range(len(a)):
...     print(i, a[i])
...0 Mary1 had2 a3 little4 lamb
Nach dem Login kopieren
In den meisten Fällen verwenden Sie jedoch

Die Funktion ist Sehr praktisch. Weitere Informationen finden Sie unter Looping-Techniken. enumerate()

Es wäre seltsam, das Ergebnis von range() direkt auszudrucken:

>>> print(range(10))range(0, 10)
Nach dem Login kopieren
In vielen Fällen ist das zurückgegebene Objekt nur wie eine Liste, aber tatsächlich Darauf liegt es nicht. Wenn dieses Objekt iteriert wird, werden aufeinanderfolgende Elemente in der Zielsequenz zurückgegeben. Aus Platzgründen wird jedoch keine Liste erstellt.

range() Diese Art von Objekt wird

(iterierbar) genannt. Das heißt, wenn einige Funktionen oder Strukturen erwarten, bis zum Ende aufeinanderfolgende Elemente von etwas zu erhalten, kann das

-Objekt diesen Bedarf erfüllen. Die iterable-Anweisung ist ein solches iteratives Programm. iterableFunktion ist eine weitere Funktion, die eine Liste mit iterierbaren Objekten erstellt:forlist()

>>> list(range(5))
[0, 1, 2, 3, 4]
Nach dem Login kopieren
Weitere Funktionen, die iterierbare Objekte zurückgeben und iterierbare Objekte als Parameter verwenden, werden als Nächstes vorgestellt.

4.4

- und

-Anweisungen und break-Klauseln für SchleifencontinueelseWie bei der C-Sprache springt die

-Anweisung aus der innersten Ebene von

oder break Zyklus. forwhile-Schleifenanweisungen können

-Klauseln haben; wenn die

-Schleife das Durchlaufen der Schleifensequenz abschließt oder sich die Schleifenbedingung der else-Schleife in for ändert, wird die while-Klausel ausgeführt . Wenn die Schleife jedoch durch die False-Anweisung beendet wird, wird die else-Klausel nicht ausgeführt. Dies wird durch das folgende Beispiel zum Finden von Primzahlen demonstriert: breakelse

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, &#39;equals&#39;, x, &#39;*&#39;, n//x)
...             break...     else:
...         # loop fell through without finding a factor...         print(n, &#39;is a prime number&#39;)
...2 is a prime number3 is a prime number4 equals 2 * 25 is a prime number6 equals 2 * 37 is a prime number8 equals 2 * 49 equals 3 * 3
Nach dem Login kopieren
(Der Code ist korrekt. Schauen Sie genauer hin: Die
-Klausel gehört zur

-Schleife, nicht zur else-Anweisung )forif Bei Verwendung mit einer Schleife ähnelt die

-Klausel eher der

-Klausel in der else-Anweisung als der try-Klausel der else-Anweisung ist unterschiedlich: Wenn keine Ausnahme auftritt, wird die if-Klausel der else-Anweisung ausgeführt. Wenn in der Schleife keine try-Klausel auftritt, wird die else-Klausel ausgeführt. Weitere Informationen zu break-Anweisungen und Ausnahmen finden Sie unter Umgang mit Ausnahmen. Die elsetry

-Anweisung ist ebenfalls der C-Sprache entlehnt und wird verwendet, um direkt zur nächsten Iteration der Schleife zu springen:

continue

>>> for num in range(2, 10):
...     if num % 2 == 0:
...         print("Found an even number", num)
...         continue...     print("Found a number", num)
Found an even number 2Found a number 3Found an even number 4Found a number 5Found an even number 6Found a number 7Found an even number 8Found a number 9
Nach dem Login kopieren
4.5
Anweisungen Die

pass

-Anweisung bewirkt nichts. Wenn eine Aussage grammatikalisch korrekt sein muss, ohne etwas zu tun, kann die

-Anweisung verwendet werden. Zum Beispiel: passpass

pass语句可以用来创建最小类:

>>> class MyEmptyClass:
...     pass...
Nach dem Login kopieren

pass语句的另一个用处是,当需要编写新的代码时,使用它作为函数或者条件体的位置占位符,这为作者在更加抽象的层次思考问题提供了便利。pass被默默地忽视:

>>> def initlog(*args):
...     pass   # Remember to implement this!...
Nach dem Login kopieren

4.6 Defining Functions

以下是打印任意边界斐波那契额数列的函数:

>>> def fib(n):    # write Fibonacci series up to n...     """Print a Fibonacci series up to n."""...     a, b = 0, 1...     while a < n:
...         print(a, end=&#39; &#39;)
...         a, b = b, a+b
...     print()
...>>> # Now call the function we just defined:... fib(2000)0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
Nach dem Login kopieren

关键字def引入函数定义,必须在后面跟上函数名字和形参列表。构成函数体的语句另起一行,必须缩进。

函数体的第一条语句可以选择性使用字符串作为函数的文档字符串,或者docstring。(更多关于文档字符串参见 Documentation Strings) 有许多工具使用文档字符串自动生成在线或者打印文档,或者允许使用者交互地浏览代码;在代码中写文档字符串是一个好的实践,因此需要将其作为习惯。

函数的执行引入了函数局部变量使用的新符号表。更准确的说,所有在函数中赋值变量都将值存储在局部符号表中;变量引用首先在局部符号表中查找,然后是封闭函数的局部符号表,然后是全局符号表,最后是built-in符号表。因此,在函数中全局变量可以被引用,但是不能直接赋予新值(除非使用global语句声明)。

但函数被调用时,实参也被引入被调用函数的局部符号表中。因此,参数按照按值调用的方式传递(这里的值总是对象引用,而不是对象的值。)[1] 当函数调用其他函数时,为调用会产生新的局部符号表。

函数定义在当前符号表中引入函数名。函数名引用的值拥有一个被解释器识别为“用户自定义函数”的类型。这个值也可以赋值给其他名字,然后使用这个名字来调用函数。这种方式是函数重命名机制:

>>> fib<function fib at 10042ed0>>>> f = fib>>> f(100)0 1 1 2 3 5 8 13 21 34 55 89
Nach dem Login kopieren

拥有其他语言经验的程序员,可能会认为fib不是一个方法而是一个过程,因为它没有返回值。事实上,没有返回语句的函数确实返回了值,而且是相当烦人的值,这个值被称为None(built-in名字)。如果None值是唯一要写的值,那么写的时候通常会被解释器忽视。使用print()可以看到打印的None值:

>>> fib(0)>>> print(fib(0))None
Nach dem Login kopieren

想要定义返回斐波那契数列数字而不是打印数字的函数非常简单:

>>> def fib2(n):  # return Fibonacci series up to n...     """Return a list containing the Fibonacci series up to n."""...     result = []
...     a, b = 0, 1...     while a < n:
...         result.append(a)    # see below...         a, b = b, a+b
...     return result
...>>> f100 = fib2(100)    # call it>>> f100                # write the result[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
Nach dem Login kopieren

这个例子也示范了Python的一些新特性:

  • return语句从函数中返回一个值。不带任何表达式的return语句返回None。函数结束时也会返回`None。

  • 语句result.append(a)调用列表对象result的方法。方法是属于对象的函数,并且以obj.methodname命名,这里obj是一个对象(或许是返回对象的表达式),methodname是定义在obj所属类型中的函数名。不容的类型定义了不同的函数。不同类型中的函数可以拥有相同的名字而不会导致二义(使用类,自定义新的对象类型和函数是可行的,参见Classes) 这个例子中的方法append()定义在列表对象中;该方法在列表末尾添加新元素。这个例子中等同于result = result + [a],但是append()方法更加高效。

4.7 More on Defining Functions

定义函数可以使用许多参数,有三种形式,可以将其结合使用。

4.7.1 Default Argument Values

为一个或者更多参数指定默认值是最有用的。这种方式创建的函数,可以使用比定义所需更少的参数来调用。例如:

def ask_ok(prompt, retries=4, reminder=&#39;Please try again!&#39;):while True:
        ok = input(prompt)if ok in (&#39;y&#39;, &#39;ye&#39;, &#39;yes&#39;):return Trueif ok in (&#39;n&#39;, &#39;no&#39;, &#39;nop&#39;, &#39;nope&#39;):return Falseretries = retries - 1if retries < 0:raise ValueError(&#39;invalid user response&#39;)print(reminder)
Nach dem Login kopieren

这个函数可以用以下方式调用:

  • 指定唯一的强制参数:ask_ok(&#39;Do you really want to quit?&#39;)

  • 指定其中一个可选参数:ask_ok(&#39;OK to overwrite the file?&#39;, 2)

  • 或者指定所有参数:ask_ok(&#39;OK to overwrite the file?&#39;, 2, &#39;Come on, only yes or no!&#39;)

这个例子也介绍了关键字in,用来测试序列是否包含具体的值。

参数的默认值在函数定义时求值,因此:

i = 5def f(arg=i):print(arg)

i = 6f()
Nach dem Login kopieren

会打印5。

重要提示: 参数默认值只被求值一次。当默认参数是诸如列表,字典或者其他大多数对象的可变对象时,会有很大不同。例如,以下函数累积后续调用传递的实参:

def f(a, L=[]):
    L.append(a)return Lprint(f(1))print(f(2))print(f(3))
Nach dem Login kopieren

会打印:

[1]
[1, 2]
[1, 2, 3]
Nach dem Login kopieren

如果不希望默认参数被随后的调用共享,可以使用如下的函数代替:

def f(a, L=None):if L is None:
        L = []
    L.append(a)return L
Nach dem Login kopieren

4.7.2 Keyword Arguments

也可以使用如kwarg = value形式的关键字参数调用函数。例如如下函数:

def parrot(voltage, state=&#39;a stiff&#39;, action=&#39;voom&#39;, type=&#39;Norwegian Blue&#39;):print("-- This parrot wouldn&#39;t", action, end=&#39; &#39;)print("if you put", voltage, "volts through it.")print("-- Lovely plumage, the", type)print("-- It&#39;s", state, "!")
Nach dem Login kopieren

接受一个必须参数(voltage)以及三个可选参数(state, actiontype)。这个函数可以使用以下的任意方式调用:

parrot(1000)                                          # 1 positional argumentparrot(voltage=1000)                                  # 1 keyword argumentparrot(voltage=1000000, action=&#39;VOOOOOM&#39;)             # 2 keyword argumentsparrot(action=&#39;VOOOOOM&#39;, voltage=1000000)             # 2 keyword argumentsparrot(&#39;a million&#39;, &#39;bereft of life&#39;, &#39;jump&#39;)         # 3 positional argumentsparrot(&#39;a thousand&#39;, state=&#39;pushing up the daisies&#39;)  # 1 positional, 1 keyword
Nach dem Login kopieren

但是下面的调用方式都是非法的:

parrot()                     # required argument missingparrot(voltage=5.0, &#39;dead&#39;)  # non-keyword argument after a keyword argumentparrot(110, voltage=220)     # duplicate value for the same argumentparrot(actor=&#39;John Cleese&#39;)  # unknown keyword argument
Nach dem Login kopieren

函数调用中,关键字参数必须在位置参数之后。所有传递的关键字实参必须匹配函数接受的其中一个形参(例如,actor对于函数parrot来说就不是一个合法的关键字参数),其顺序不是重要的。也包括非可选形参(例如parrot(voltage = 1000)也是合法的)。任意形参都不会接受两次实参值。以下示例就是由于这条限制而调用失败的:

>>> def function(a):
...     pass...>>> function(0, a=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>TypeError: function() got multiple values for keyword argument &#39;a&#39;
Nach dem Login kopieren

当最一个的形参是**name形式时,这个参数接收字典(参见 Mapping Types-dict),这个字典包含不能能与形参对应的关键字实参。关键字参数可以与形如*name的形式参数结合,这种形式参数以元组接收不能与形参匹配的位置参数。(*name必须在**name之前)。例如,以下函数:

def cheeseshop(kind, *arguments, **keywords):print("-- Do you have any", kind, "?")print("-- I&#39;m sorry, we&#39;re all out of", kind)for arg in arguments:print(arg)print("-" * 40)for kw in keywords:print(kw, ":", keywords[kw])
Nach dem Login kopieren

可以像下面一样调用:

cheeseshop("Limburger", "It&#39;s very runny, sir.",           "It&#39;s really very, VERY runny, sir.",
           shopkeeper="Michael Palin",
           client="John Cleese",
           sketch="Cheese Shop Sketch")
Nach dem Login kopieren

当然会如下打印:

-- Do you have any Limburger ?-- I&#39;m sorry, we&#39;re all out of Limburger
It&#39;s very runny, sir.It&#39;s really very, VERY runny, sir.----------------------------------------shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch
Nach dem Login kopieren

注意关键字参数打印的顺序保证是与其在函数调用时提供的顺序相同的。

4.7.3 Arbitrary Argument Lists

最后,最不常用的是让函数可以使用任意数量的参数调用。这些参数会被包装在元组中(参见 Tuples and Sequences)。在可变数量形参之前,可以有零个或者更多普通参数:

def write_multiple_items(file, separator, *args):file.write(separator.join(args))
Nach dem Login kopieren

通常,可变参数是形参列表中的最后一个,因为可变参数接收了传递给函数的所有剩余实参。出现在*args后面的任意任意形参都是keyword-only参数(强制关键字参数),意味着他们只能作为关键字参数使用,而不能用作位置参数。

>>> def concat(*args, sep="/"):
...     return sep.join(args)
...>>> concat("earth", "mars", "venus")&#39;earth/mars/venus&#39;>>> concat("earth", "mars", "venus", sep=".")&#39;earth.mars.venus&#39;
Nach dem Login kopieren

4.7.4 Unpacking Argument Lists

参数已经封装在列表或者元组中,但是当调用需要分离的位置参数的函数时,需要拆包元组或者列表。例如,built-in函数range()需要分离的startstop参数。如果它们不是分离的,可以在函数调用时使用*操作符来从列表或者元组中拆包(译注:事实证明,字符串也是可以被拆包的):

>>> list(range(3, 6))            # normal call with separate arguments[3, 4, 5]>>> args = [3, 6]>>> list(range(*args))            # call with arguments unpacked from a list[3, 4, 5]
Nach dem Login kopieren

以同样的方式,使用**操作符,字典可以传递关键字参数:

>>> def parrot(voltage, state=&#39;a stiff&#39;, action=&#39;voom&#39;):
...     print("-- This parrot wouldn&#39;t", action, end=&#39; &#39;)
...     print("if you put", voltage, "volts through it.", end=&#39; &#39;)
...     print("E&#39;s", state, "!")
...>>> d = {"voltage": "four million", "state": "bleedin&#39; demised", "action": "VOOM"}>>> parrot(**d)-- This parrot wouldn&#39;t VOOM if you put four million volts through it. E&#39;s bleedin&#39; demised !
Nach dem Login kopieren

4.7.5 Lambda Expressions

可以使用关键字lambda创建小的匿名方法。这个函数返回其两个参数之和:lambda a, b: a + b。Lambda方法可以在所有需要函数对象的地方使用。句法上,它们在被限制在一个单个表达式中。语法上,它们只是正常函数定义的语法糖而已。像内嵌函数定义一样,lambda方法也可以引用外部作用域的变量:

>>> def make_incrementor(n):
...     return lambda x: x + n
...>>> f = make_incrementor(42)>>> f(0)42>>> f(1)43
Nach dem Login kopieren

上面的例子使用lambda表达式来返回一个函数。其他的用法是将这个小函数为参数传递:

>>> pairs = [(1, &#39;one&#39;), (2, &#39;two&#39;), (3, &#39;three&#39;), (4, &#39;four&#39;)]>>> pairs.sort(key=lambda pair: pair[1])>>> pairs
[(4, &#39;four&#39;), (1, &#39;one&#39;), (3, &#39;three&#39;), (2, &#39;two&#39;)]
Nach dem Login kopieren

4.7.6 Documentation Strings

这里有一些关于文档字符串的内容和格式的约定。

第一行应该是对象用途短小而简明地总结。简洁起见,不应该详细描述对象的名字和类型,因为可以通过其他途径了解(除非名字恰好是描述方法操作的动词)。这一行应该以大写字母开始并以句号结束。

如果文档字符串有多行,第二行应该空出来,从视觉上把总结和其他的描述分开来。剩余行应是一个或者多个描述对象的调用约定及其副作用的段落。

Python分析程序不会去掉多行字符串中的缩排,因此如果必要的话,文档处理工具自己必须去掉缩排,这遵循以下约定:第一行字符串后面的第一个非空行决定整个文档字符串缩排的数量。(因为第一行紧挨着它的起始引号,因此表面上看不出其缩排,所以不能使用第一行作为标准)留白“相当于”是字符串的起始缩排。每一行都不应该有缩排,如果有缩排的话,所有的留白都应该清除掉。留白的长度应当等于扩展制表符的宽度(通常是8个空格)。

以下是多行文档字符串的示例:

>>> def my_function():
...     """Do nothing, but document it.......     No, really, it doesn&#39;t do anything....     """...     pass...>>> print(my_function.__doc__)
Do nothing, but document it.

    No, really, it doesn&#39;t do anything.
Nach dem Login kopieren

4.7.7 Documentation Strings

方法注解 是描述用户自定义方法使用的类型的元信息,是完全可选的(参见PEP 484获取更多信息)。

注解作为字典存储在方法属性__annotations__中,并且对方法的其他部分没有任何影响。参数注解定义在参数名字后的冒号后面,紧跟计算注解值得表达式。返回注解使用->定义,紧跟表达式,在参数列表和指示def语句结束的冒号中间。下面的例子有一个位置参数,关键字参数以及返回值得注解:

>>> def f(ham: str, eggs: str = &#39;eggs&#39;) -> str:
...     print("Annotations:", f.__annotations__)
...     print("Arguments:", ham, eggs)
...     return ham + &#39; and &#39; + eggs
...>>> f(&#39;spam&#39;)
Annotations: {&#39;ham&#39;: <class &#39;str&#39;>, &#39;return&#39;: <class &#39;str&#39;>, &#39;eggs&#39;: <class &#39;str&#39;>}
Arguments: spam eggs&#39;spam and eggs&#39;
Nach dem Login kopieren

4.7.8 Intermezzo: Coding Style

现在需要写更长更复杂的Python程序,是时候谈论编码风格了。大多数语言可以以不同的风格编写(更简洁的说是格式化),一些编码风格比其他的更加可读。让其他人更容易读懂你的代码一直都是很重要的,养成良好的编码风格很重要。

对于Python来说,PEP 8被作为风格规范指导,许多项目都在使用这种规范。这个规范促成了一种非常易读和养眼的代码风格。在某种程度上每一个Python开发者都应该阅读它,以下是从这个规范中提取的重要内容:

  • 使用4个空格作为缩进,而不是tab
    4个空格是小的缩进(允许更深的嵌套深度)和大缩进(更易读)之间的良好折中方案。Tabs会导致困扰,最好弃用

  • 换行以保证每一行不会超过79个字符
    这在小的显示器上非常有用,也可在打的显示器中分屏显示多个文件

  • 使用空行分开方法和类,以及函数中的大代码块

  • 如果可能,注释独占一行

  • 使用文档字符串

  • 在操作符的两端以及顿号后面使用空格,但是不要在括号内侧使用:a = f(1, 2) + g(3, 4)

  • 统一命名类以及函数;约定使用CamelCase(驼峰)命名类,使用lower_case_with_underscores(小写带下划线)命名方法和函数。总是使用self作为方法的第一个参数名(参见A first Look at Classes了解更多关于类和方法的genggd)

  • 如果代码要在国际环境中使用,不要使用自己喜爱的编码方式。Python的默认编码UTF-8或者甚至普通的ASCII编码都能在任何情况下起作用。

  • 同样的,不要在标识符中使用非ASCII字符,除非是不同语种的人会阅读和维护代码。

Footnotes

[1] 事实上,使用引用传递会更好,因为如果传递的是可变对象,变调用者对对象做的改变对调用者可见(如在列表中插入新的项)

Das obige ist der detaillierte Inhalt vonDetaillierte Einführung in Flusskontrollanweisungen in Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!