diff options
-rw-r--r-- | elixir.html.markdown | 6 | ||||
-rw-r--r-- | erlang.html.markdown | 39 | ||||
-rw-r--r-- | es-es/python-es.html.markdown | 4 | ||||
-rw-r--r-- | es-es/python3-es.html.markdown | 570 | ||||
-rw-r--r-- | python3.html.markdown | 10 | ||||
-rw-r--r-- | zh-cn/erlang-cn.html.markdown | 259 |
6 files changed, 878 insertions, 10 deletions
diff --git a/elixir.html.markdown b/elixir.html.markdown index 0892deb7..b27b2ee8 100644 --- a/elixir.html.markdown +++ b/elixir.html.markdown @@ -358,7 +358,7 @@ f = fn -> 2 * 2 end #=> #Function<erl_eval.20.80484245> spawn(f) #=> #PID<0.40.0> # `spawn` returns a pid (process identifier), you can use this pid to send -# messages to the process. To do message passing we use the `<-` operator. +# messages to the process. To do message passing we use the `send` operator. # For all of this to be useful we need to be able to receive messages. This is # achived with the `receive` mechanism: defmodule Geometry do @@ -378,11 +378,11 @@ end pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0> # Send a message to `pid` that will match a pattern in the receive statement -pid <- {:rectangle, 2, 3} +send pid, {:rectangle, 2, 3} #=> Area = 6 # {:rectangle,2,3} -pid <- {:circle, 2} +send pid, {:circle, 2} #=> Area = 12.56000000000000049738 # {:circle,2} diff --git a/erlang.html.markdown b/erlang.html.markdown index 065219ba..64b62f05 100644 --- a/erlang.html.markdown +++ b/erlang.html.markdown @@ -241,6 +241,45 @@ catcher(N) -> % exception, it is converted into a tuple that describes the error. catcher(N) -> catch generate_exception(N). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% 4. Concurrency +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Erlang relies on the actor model for concurrency. All we need to write +% concurrent programs in erlang are three primitives: spawning processes, +% sending messages and receiving messages. + +% To start a new process we use the `spawn` function, which takes a function +% as argument. + +F = fun() -> 2 + 2 end. % #Fun<erl_eval.20.67289768> +spawn(F). % <0.44.0> + +% `spawn` returns a pid (process identifier), you can use this pid to send +% messages to the process. To do message passing we use the `!` operator. +% For all of this to be useful we need to be able to receive messages. This is +% achieved with the `receive` mechanism: + +-module(caculateGeometry). +-compile(export_all). +caculateAera() -> + receive + {rectangle, W, H} -> + W * H; + {circle, R} -> + 3.14 * R * R; + _ -> + io:format("We can only caculate area of rectangles or circles.") + end. + +% Compile the module and create a process that evaluates `caculateAera` in the shell +c(caculateGeometry). +CaculateAera = spawn(caculateGeometry, caculateAera, []). +CaculateAera ! {circle, 2}. % 12.56000000000000049738 + +% The shell is also a process, you can use `self` to get the current pid +self(). % <0.41.0> + ``` ## References diff --git a/es-es/python-es.html.markdown b/es-es/python-es.html.markdown index f92f5cde..f7a0ec02 100644 --- a/es-es/python-es.html.markdown +++ b/es-es/python-es.html.markdown @@ -130,7 +130,7 @@ otra_variable # Levanta un error de nombre # 'if' puede ser usado como una expresión "yahoo!" if 3 > 2 else 2 #=> "yahoo!" -# Listas sobre secuencias +# Listas almacenan secuencias lista = [] # Puedes empezar con una lista prellenada otra_lista = [4, 5, 6] @@ -254,7 +254,7 @@ conjunto_lleno | otro_conjunto #=> {1, 2, 3, 4, 5, 6} # Haz diferencia de conjuntos con - {1,2,3,4} - {2,3,5} #=> {1, 4} -# CHequea la existencia en un conjunto con 'in' +# Chequea la existencia en un conjunto con 'in' 2 in conjunto_lleno #=> True 10 in conjunto_lleno #=> False diff --git a/es-es/python3-es.html.markdown b/es-es/python3-es.html.markdown new file mode 100644 index 00000000..1c69481a --- /dev/null +++ b/es-es/python3-es.html.markdown @@ -0,0 +1,570 @@ +--- +language: python3 +contributors: + - ["Louie Dinh", "http://pythonpracticeprojects.com"] +translators: + - ["Camilo Garrido", "http://twitter.com/hirohope"] +lang: es-es +filename: learnpython3-es.py +--- + +Python fue creado por Guido Van Rossum en el principio de los 90'. Ahora es uno +de los lenguajes más populares en existencia. Me enamoré de Python por su claridad sintáctica. +Es básicamente pseudocódigo ejecutable. + +¡Comentarios serán muy apreciados! Pueden contactarme en [@louiedinh](http://twitter.com/louiedinh) o louiedinh [at] [servicio de email de google] + +Nota: Este artículo aplica a Python 2.7 específicamente, pero debería ser aplicable a Python 2.x. ¡Pronto un recorrido por Python 3! + +```python + +# Comentarios de una línea comienzan con una almohadilla (o signo gato) + +""" Strings multilinea pueden escribirse + usando tres "'s, y comunmente son usados + como comentarios. +""" + +#################################################### +## 1. Tipos de datos primitivos y operadores. +#################################################### + +# Tienes números +3 #=> 3 + +# Matemática es lo que esperarías +1 + 1 #=> 2 +8 - 1 #=> 7 +10 * 2 #=> 20 + +# Excepto la división la cual por defecto retorna un número 'float' (número de coma flotante) +35 / 5 # => 7.0 + +# Cuando usas un float, los resultados son floats +3 * 2.0 # => 6.0 + +# Refuerza la precedencia con paréntesis +(1 + 3) * 2 # => 8 + + +# Valores 'boolean' (booleanos) son primitivos +True +False + +# Niega con 'not' +not True # => False +not False # => True + + +# Igualdad es == +1 == 1 # => True +2 == 1 # => False + +# Desigualdad es != +1 != 1 # => False +2 != 1 # => True + +# Más comparaciones +1 < 10 # => True +1 > 10 # => False +2 <= 2 # => True +2 >= 2 # => True + +# ¡Las comparaciones pueden ser concatenadas! +1 < 2 < 3 # => True +2 < 3 < 2 # => False + +# Strings se crean con " o ' +"Esto es un string." +'Esto también es un string' + +# ¡Strings también pueden ser sumados! +"Hola " + "mundo!" #=> "Hola mundo!" + +# Un string puede ser tratado como una lista de caracteres +"Esto es un string"[0] #=> 'E' + +# .format puede ser usaro para darle formato a los strings, así: +"{} pueden ser {}".format("strings", "interpolados") + +# Puedes repetir los argumentos de formateo para ahorrar tipeos. +"{0} sé ligero, {0} sé rápido, {0} brinca sobre la {1}".format("Jack", "vela") #=> "Jack sé ligero, Jack sé rápido, Jack brinca sobre la vela" +# Puedes usar palabras claves si no quieres contar. +"{nombre} quiere comer {comida}".format(nombre="Bob", food="lasaña") #=> "Bob quiere comer lasaña" + + +# None es un objeto +None # => None + +# No uses el símbolo de igualdad `==` para comparar objetos con None +# Usa `is` en lugar de +"etc" is None #=> False +None is None #=> True + +# None, 0, y strings/listas/diccionarios vacíos(as) todos se evalúan como False. +# Todos los otros valores son True +bool(0) # => False +bool("") # => False +bool([]) #=> False +bool({}) #=> False + + +#################################################### +## 2. Variables y Colecciones +#################################################### + +# Python tiene una función para imprimir +print("Soy Python. Encantado de conocerte") + +# No hay necesidad de declarar las variables antes de asignarlas. +una_variable = 5 # La convención es usar guiones_bajos_con_minúsculas +una_variable #=> 5 + +# Acceder a variables no asignadas previamente es una excepción. +# Ve Control de Flujo para aprender más sobre el manejo de excepciones. +otra_variable # Levanta un error de nombre + +# Listas almacena secuencias +lista = [] +# Puedes empezar con una lista prellenada +otra_lista = [4, 5, 6] + +# Añadir cosas al final de una lista con 'append' +lista.append(1) #lista ahora es [1] +lista.append(2) #lista ahora es [1, 2] +lista.append(4) #lista ahora es [1, 2, 4] +lista.append(3) #lista ahora es [1, 2, 4, 3] +# Remueve del final de la lista con 'pop' +lista.pop() #=> 3 y lista ahora es [1, 2, 4] +# Pongámoslo de vuelta +lista.append(3) # Nuevamente lista ahora es [1, 2, 4, 3]. + +# Accede a una lista como lo harías con cualquier arreglo +lista[0] #=> 1 +# Mira el último elemento +lista[-1] #=> 3 + +# Mirar fuera de los límites es un error 'IndexError' +lista[4] # Levanta la excepción IndexError + +# Puedes mirar por rango con la sintáxis de trozo. +# (Es un rango cerrado/abierto para ustedes los matemáticos.) +lista[1:3] #=> [2, 4] +# Omite el inicio +lista[2:] #=> [4, 3] +# Omite el final +lista[:3] #=> [1, 2, 4] +# Selecciona cada dos elementos +lista[::2] # =>[1, 4] +# Invierte la lista +lista[::-1] # => [3, 4, 2, 1] +# Usa cualquier combinación de estos para crear trozos avanzados +# lista[inicio:final:pasos] + +# Remueve elementos arbitrarios de una lista con 'del' +del lista[2] # lista ahora es [1, 2, 3] + +# Puedes sumar listas +lista + otra_lista #=> [1, 2, 3, 4, 5, 6] - Nota: lista y otra_lista no se tocan + +# Concatenar listas con 'extend' +lista.extend(otra_lista) # lista ahora es [1, 2, 3, 4, 5, 6] + +# Chequea la existencia en una lista con 'in' +1 in lista #=> True + +# Examina el largo de una lista con 'len' +len(lista) #=> 6 + + +# Tuplas son como listas pero son inmutables. +tupla = (1, 2, 3) +tupla[0] #=> 1 +tupla[0] = 3 # Levanta un error TypeError + +# También puedes hacer todas esas cosas que haces con listas +len(tupla) #=> 3 +tupla + (4, 5, 6) #=> (1, 2, 3, 4, 5, 6) +tupla[:2] #=> (1, 2) +2 in tupla #=> True + +# Puedes desempacar tuplas (o listas) en variables +a, b, c = (1, 2, 3) # a ahora es 1, b ahora es 2 y c ahora es 3 +# Tuplas son creadas por defecto si omites los paréntesis +d, e, f = 4, 5, 6 +# Ahora mira que fácil es intercambiar dos valores +e, d = d, e # d ahora es 5 y e ahora es 4 + + +# Diccionarios almacenan mapeos +dicc_vacio = {} +# Aquí está un diccionario prellenado +dicc_lleno = {"uno": 1, "dos": 2, "tres": 3} + +# Busca valores con [] +dicc_lleno["uno"] #=> 1 + +# Obtén todas las llaves como una lista con 'keys()'. Necesitamos envolver la llamada en 'list()' porque obtenemos un iterable. Hablaremos de eso luego. +list(dicc_lleno.keys()) #=> ["tres", "dos", "uno"] +# Nota - El orden de las llaves del diccionario no está garantizada. +# Tus resultados podrían no ser los mismos del ejemplo. + +# Obtén todos los valores como una lista. Nuevamente necesitamos envolverlas en una lista para sacarlas del iterable. +list(dicc_lleno.values()) #=> [3, 2, 1] +# Nota - Lo mismo que con las llaves, no se garantiza el orden. + +# Chequea la existencia de una llave en el diccionario con 'in' +"uno" in dicc_lleno #=> True +1 in dicc_lleno #=> False + +# Buscar una llave inexistente deriva en KeyError +dicc_lleno["cuatro"] # KeyError + +# Usa el método 'get' para evitar la excepción KeyError +dicc_lleno.get("uno") #=> 1 +dicc_lleno.get("cuatro") #=> None +# El método 'get' soporta un argumento por defecto cuando el valor no existe. +dicc_lleno.get("uno", 4) #=> 1 +dicc_lleno.get("cuatro", 4) #=> 4 + +# El método 'setdefault' inserta en un diccionario solo si la llave no está presente +dicc_lleno.setdefault("cinco", 5) #dicc_lleno["cinco"] es puesto con valor 5 +dicc_lleno.setdefault("cinco", 6) #dicc_lleno["cinco"] todavía es 5 + + +# Remueve llaves de un diccionario con 'del' +del dicc_lleno['uno'] # Remueve la llave 'uno' de dicc_lleno + +# Sets (conjuntos) almacenan ... bueno, conjuntos +conjunto_vacio = set() +# Inicializar un conjunto con montón de valores. Yeah, se ve un poco como un diccionario. Lo siento. +un_conjunto = {1,2,2,3,4} # un_conjunto ahora es {1, 2, 3, 4} + +# Añade más valores a un conjunto +conjunto_lleno.add(5) # conjunto_lleno ahora es {1, 2, 3, 4, 5} + +# Haz intersección de conjuntos con & +otro_conjunto = {3, 4, 5, 6} +conjunto_lleno & otro_conjunto #=> {3, 4, 5} + +# Haz unión de conjuntos con | +conjunto_lleno | otro_conjunto #=> {1, 2, 3, 4, 5, 6} + +# Haz diferencia de conjuntos con - +{1,2,3,4} - {2,3,5} #=> {1, 4} + +# Chequea la existencia en un conjunto con 'in' +2 in conjunto_lleno #=> True +10 in conjunto_lleno #=> False + + +#################################################### +## 3. Control de Flujo +#################################################### + +# Let's just make a variable +some_var = 5 + +# Aquí está una declaración de un 'if'. ¡La indentación es significativa en Python! +# imprime "una_variable es menor que 10" +if una_variable > 10: + print("una_variable es completamente mas grande que 10.") +elif una_variable < 10: # Este condición 'elif' es opcional. + print("una_variable es mas chica que 10.") +else: # Esto también es opcional. + print("una_variable es de hecho 10.") + +""" +For itera sobre listas +imprime: + perro es un mamifero + gato es un mamifero + raton es un mamifero +""" +for animal in ["perro", "gato", "raton"]: + # Puedes usar % para interpolar strings formateados + print("{} es un mamifero".format(animal)) + +""" +`range(número)` retorna una lista de números +desde cero hasta el número dado +imprime: + 0 + 1 + 2 + 3 +""" +for i in range(4): + print(i) + +""" +While itera hasta que una condición no se cumple. +imprime: + 0 + 1 + 2 + 3 +""" +x = 0 +while x < 4: + print(x) + x += 1 # versión corta de x = x + 1 + +# Maneja excepciones con un bloque try/except +try: + # Usa raise para levantar un error + raise IndexError("Este es un error de indice") +except IndexError as e: + pass # Pass no hace nada. Usualmente harias alguna recuperacion aqui. + +# Python oferce una abstracción fundamental llamada Iterable. +# Un iterable es un objeto que puede ser tratado como una sequencia. +# El objeto es retornado por la función 'range' es un iterable. + +dicc_lleno = {"uno": 1, "dos": 2, "tres": 3} +nuestro_iterable = dicc_lleno.keys() +print(nuestro_iterable) #=> range(1,10). Este es un objeto que implementa nuestra interfaz Iterable + +Podemos recorrerla. +for i in nuestro_iterable: + print(i) # Imprime uno, dos, tres + +# Aunque no podemos selecionar un elemento por su índice. +nuestro_iterable[1] # Genera un TypeError + +# Un iterable es un objeto que sabe como crear un iterador. +nuestro_iterator = iter(nuestro_iterable) + +# Nuestro iterador es un objeto que puede recordar el estado mientras lo recorremos. +# Obtenemos el siguiente objeto llamando la función __next__. +nuestro_iterator.__next__() #=> "uno" + +# Mantiene el estado mientras llamamos __next__. +nuestro_iterator.__next__() #=> "dos" +nuestro_iterator.__next__() #=> "tres" + +# Después que el iterador ha retornado todos sus datos, da una excepción StopIterator. +nuestro_iterator.__next__() # Genera StopIteration + +# Puedes obtener todos los elementos de un iterador llamando a list() en el. +list(dicc_lleno.keys()) #=> Retorna ["uno", "dos", "tres"] + + + +#################################################### +## 4. Funciones +#################################################### + +# Usa 'def' para crear nuevas funciones +def add(x, y): + print("x es {} y y es {}".format(x, y)) + return x + y # Retorna valores con una la declaración return + +# Llamando funciones con parámetros +add(5, 6) #=> imprime "x es 5 y y es 6" y retorna 11 + +# Otra forma de llamar funciones es con argumentos de palabras claves +add(y=6, x=5) # Argumentos de palabra clave pueden ir en cualquier orden. + + +# Puedes definir funciones que tomen un número variable de argumentos +def varargs(*args): + return args + +varargs(1, 2, 3) #=> (1,2,3) + + +# Puedes definir funciones que toman un número variable de argumentos +# de palabras claves +def keyword_args(**kwargs): + return kwargs + +# Llamémosla para ver que sucede +keyword_args(pie="grande", lago="ness") #=> {"pie": "grande", "lago": "ness"} + + +# You can do both at once, if you like# Puedes hacer ambas a la vez si quieres +def todos_los_argumentos(*args, **kwargs): + print args + print kwargs +""" +todos_los_argumentos(1, 2, a=3, b=4) imprime: + (1, 2) + {"a": 3, "b": 4} +""" + +# ¡Cuando llames funciones, puedes hacer lo opuesto a varargs/kwargs! +# Usa * para expandir tuplas y usa ** para expandir argumentos de palabras claves. +args = (1, 2, 3, 4) +kwargs = {"a": 3, "b": 4} +todos_los_argumentos(*args) # es equivalente a foo(1, 2, 3, 4) +todos_los_argumentos(**kwargs) # es equivalente a foo(a=3, b=4) +todos_los_argumentos(*args, **kwargs) # es equivalente a foo(1, 2, 3, 4, a=3, b=4) + +# Python tiene funciones de primera clase +def crear_suma(x): + def suma(y): + return x + y + return suma + +sumar_10 = crear_suma(10) +sumar_10(3) #=> 13 + +# También hay funciones anónimas +(lambda x: x > 2)(3) #=> True + +# Hay funciones integradas de orden superior +map(sumar_10, [1,2,3]) #=> [11, 12, 13] +filter(lambda x: x > 5, [3, 4, 5, 6, 7]) #=> [6, 7] + +# Podemos usar listas por comprensión para mapeos y filtros agradables +[add_10(i) for i in [1, 2, 3]] #=> [11, 12, 13] +[x for x in [3, 4, 5, 6, 7] if x > 5] #=> [6, 7] + +#################################################### +## 5. Classes +#################################################### + + +# Heredamos de object para obtener una clase. +class Humano(object): + + # Un atributo de clase es compartido por todas las instancias de esta clase + especie = "H. sapiens" + + # Constructor basico + def __init__(self, nombre): + # Asigna el argumento al atributo nombre de la instancia + self.nombre = nombre + + # Un metodo de instancia. Todos los metodos toman self como primer argumento + def decir(self, msg): + return "%s: %s" % (self.nombre, msg) + + # Un metodo de clase es compartido a través de todas las instancias + # Son llamados con la clase como primer argumento + @classmethod + def get_especie(cls): + return cls.especie + + # Un metodo estatico es llamado sin la clase o instancia como referencia + @staticmethod + def roncar(): + return "*roncar*" + + +# Instancia una clase +i = Humano(nombre="Ian") +print i.decir("hi") # imprime "Ian: hi" + +j = Humano("Joel") +print j.decir("hello") #imprime "Joel: hello" + +# Llama nuestro método de clase +i.get_especie() #=> "H. sapiens" + +# Cambia los atributos compartidos +Humano.especie = "H. neanderthalensis" +i.get_especie() #=> "H. neanderthalensis" +j.get_especie() #=> "H. neanderthalensis" + +# Llama al método estático +Humano.roncar() #=> "*roncar*" + + +#################################################### +## 6. Módulos +#################################################### + +# Puedes importar módulos +import math +print(math.sqrt(16)) #=> 4 + +# Puedes obtener funciones específicas desde un módulo +from math import ceil, floor +print(ceil(3.7)) #=> 4.0 +print(floor(3.7))#=> 3.0 + +# Puedes importar todas las funciones de un módulo +# Precaución: Esto no es recomendable +from math import * + +# Puedes acortar los nombres de los módulos +import math as m +math.sqrt(16) == m.sqrt(16) #=> True + +# Los módulos de Python son sólo archivos ordinarios de Python. +# Puedes escribir tus propios módulos e importarlos. El nombre del módulo +# es el mismo del nombre del archivo. + +# Puedes encontrar que funciones y atributos definen un módulo. +import math +dir(math) + + +#################################################### +## 7. Avanzado +#################################################### + +# Los generadores te ayudan a hacer un código perezoso (lazy) +def duplicar_numeros(iterable): + for i in iterable: + yield i + i + +# Un generador cera valores sobre la marcha. +# En vez de generar y retornar todos los valores de una vez, crea uno en cada iteración. +# Esto significa que valores más grandes que 15 no serán procesados en 'duplicar_numeros'. +# Fíjate que 'range' es un generador. Crear una lista 1-900000000 tomaría mucho tiempo en crearse. +_rango = range(1, 900000000) +# Duplicará todos los números hasta que un resultado >= se encuentre. +for i in duplicar_numeros(_rango): + print(i) + if i >= 30: + break + + +# Decoradores +# en este ejemplo 'pedir' envuelve a 'decir' +# Pedir llamará a 'decir'. Si decir_por_favor es True entonces cambiará el mensaje a retornar +from functools import wraps + + +def pedir(_decir): + @wraps(_decir) + def wrapper(*args, **kwargs): + mensaje, decir_por_favor = _decir(*args, **kwargs) + if decir_por_favor: + return "{} {}".format(mensaje, "¡Por favor! Soy pobre :(") + return mensaje + + return wrapper + + +@pedir +def say(decir_por_favor=False): + mensaje = "¿Puedes comprarme una cerveza?" + return mensaje, decir_por_favor + + +print(decir()) # ¿Puedes comprarme una cerveza? +print(decir(decir_por_favor=True)) # ¿Puedes comprarme una cerveza? ¡Por favor! Soy pobre :() +``` + +## ¿Listo para más? + +### Gratis y en línea + +* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/) +* [Dive Into Python](http://www.diveintopython.net/) +* [Ideas for Python Projects](http://pythonpracticeprojects.com) +* [The Official Docs](http://docs.python.org/3/) +* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/) +* [Python Module of the Week](http://pymotw.com/3/) +* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182) + +### Encuadernados + +* [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20) +* [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20) +* [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20) + diff --git a/python3.html.markdown b/python3.html.markdown index 54f425ed..77811535 100644 --- a/python3.html.markdown +++ b/python3.html.markdown @@ -318,7 +318,7 @@ except IndexError as e: # Python's offers a fundamental abstraction called the Iterable. -# An iterable is an object that can be treated as a sequence. +# An iterable is an object that can be treated as a sequence. # The object returned the range function, is an iterable. filled_dict = {"one": 1, "two": 2, "three": 3} @@ -336,7 +336,7 @@ our_iterable[1] # Raises a TypeError our_iterator = iter(our_iterable) # Our iterator is an object that can remember the state as we traverse through it. -# We get the next object by calling the __next__ function. +# We get the next object by calling the __next__ function. our_iterator.__next__() #=> "one" # It maintains state as we call __next__. @@ -357,7 +357,7 @@ list(filled_dict.keys()) #=> Returns ["one", "two", "three"] # Use "def" to create new functions def add(x, y): - print("x is %s and y is %s" % (x, y)) + print("x is {} and y is {}".format(x, y)) return x + y # Return values with a return statement # Calling functions with parameters @@ -565,9 +565,9 @@ print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( * [Dive Into Python](http://www.diveintopython.net/) * [Ideas for Python Projects](http://pythonpracticeprojects.com) -* [The Official Docs](http://docs.python.org/2.6/) +* [The Official Docs](http://docs.python.org/3/) * [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/) -* [Python Module of the Week](http://pymotw.com/2/) +* [Python Module of the Week](http://pymotw.com/3/) * [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182) ### Dead Tree diff --git a/zh-cn/erlang-cn.html.markdown b/zh-cn/erlang-cn.html.markdown new file mode 100644 index 00000000..32e84278 --- /dev/null +++ b/zh-cn/erlang-cn.html.markdown @@ -0,0 +1,259 @@ +--- +language: erlang +lang: zh-cn +contributors: + - ["Giovanni Cappellotto", "http://www.focustheweb.com/"] +translators: + - ["Jakukyo Friel", "http://weakish.github.io"] +filename: erlang-cn.erl +--- + +```erlang +% 百分比符号标明注释的开始。 + +%% 两个符号通常用于注释函数。 + +%%% 三个符号通常用于注释模块。 + +% Erlang 里使用三种标点符号: +% 逗号 (`,`) 分隔函数调用中的参数、数据构建和模式。 +% 句号 (`.`) (后跟空格)分隔函数和 shell 中的表达式。 +% 分号 (`;`) 分隔语句。以下环境中使用语句: +% 函数定义和`case`、`if`、`try..catch`、`receive`表达式。 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% 1. 变量和模式匹配 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Num = 42. % 变量必须以大写字母开头。 + +% Erlang 的变量只能赋值一次。如果给变量赋不同的值,会导致错误: +Num = 43. % ** exception error: no match of right hand side value 43 + +% 大多数语言中`=`表示赋值语句,在Erlang中,则表示模式匹配。 +% `Lhs = Rhs`实际上意味着: +% 演算右边(Rhs), 将结果与左边的模式匹配。 +Num = 7 * 6. + +% 浮点数 +Pi = 3.14159. + +% Atoms 用于表示非数字的常量。 +% Atom 以小写字母开始,包含字母、数字、`_`和`@`。 +Hello = hello. +OtherNode = example@node. + +% Atom 中如果包含特殊字符,可以用单引号括起。 +AtomWithSpace = 'some atom with space'. + +% Erlang 的元组类似 C 的 struct. +Point = {point, 10, 45}. + +% 使用模式匹配操作符`=`获取元组的值。 +{point, X, Y} = Point. % X = 10, Y = 45 + +% 我们可以使用`_`存放我们不感兴趣的变量。 +% `_`被称为匿名变量。和其他变量不同, +% 同一个模式中的多个`_`变量不必绑定到相同的值。 +Person = {person, {name, {first, joe}, {last, armstrong}}, {footsize, 42}}. +{_, {_, {_, Who}, _}, _} = Person. % Who = joe + +% 列表使用方括号,元素间使用逗号分隔。 +% 列表的元素可以是任意类型。 +% 列表的第一个元素称为列表的 head,其余元素称为列表的 tail。 +ThingsToBuy = [{apples, 10}, {pears, 6}, {milk, 3}]. + +% 若`T`是一个列表,那么`[H|T]`同样是一个列表,head为`H`,tail为`T`. +% `|`分隔列表的 head 和 tail. +% `[]`是空列表。 +% 我们可以使用模式匹配操作来抽取列表中的元素。 +% 如果我们有一个非空的列表`L`,那么`[X|Y] = L`则 +% 抽取 L 的 head 至 X,tail 至 Y (X、Y需为未定义的变量)。 +[FirstThing|OtherThingsToBuy] = ThingsToBuy. +% FirstThing = {apples, 10} +% OtherThingsToBuy = {pears, 6}, {milk, 3} + +% Erlang 中的字符串其实是由整数组成的数组。字符串使用双引号。 +Name = "Hello". +[72, 101, 108, 108, 111] = "Hello". + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% 2. 循序编程 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Module 是 Erlang 代码的基本单位。我们编写的所有函数都储存在 module 中。 +% Module 存储在后缀为 `.erl` 的文件中。 +% Module 必须事先编译。编译好的 module 以 `.beam` 结尾。 +-module(geometry). +-export([area/1]). % module 对外暴露的函数列表 + +% `area`函数包含两个分句,分句间以分号相隔。 +% 最后一个分句以句号加换行结尾。 +% 每个分句由头、体两部门组成。 +% 头部包含函数名称和用括号括起的模式, +% 体部包含一系列表达式,如果头部的模式和调用时的参数匹配,这些表达式会被演算。 +% 模式匹配依照定义时的顺序依次进行。 +area({rectangle, Width, Ht}) -> Width * Ht; +area({circle, R}) -> 3.14159 * R * R. + +% 编译文件为 geometry.erl. +c(geometry). % {ok,geometry} + +% 调用函数时必须使用 module 名和函数名。 +geometry:area({rectangle, 10, 5}). % 50 +geometry:area({circle, 1.4}). % 6.15752 + +% 在 Erlang 中,同一模块中,参数数目不同,名字相同的函数是完全不同的函数。 +-module(lib_misc). +-export([sum/1]). % 对外暴露的`sum`函数接受一个参数:由整数组成的列表。 +sum(L) -> sum(L, 0). +sum([], N) -> N; +sum([H|T], N) -> sum(T, H+N). + +% fun 是匿名函数。它们没有名字,不过可以赋值给变量。 +Double = fun(X) -> 2*X end. % `Double` 指向匿名函数 #Fun<erl_eval.6.17052888> +Double(2). % 4 + +% fun 可以作为函数的参数和返回值。 +Mult = fun(Times) -> ( fun(X) -> X * Times end ) end. +Triple = Mult(3). +Triple(5). % 15 + +% 列表解析是创建列表的表达式(不使用fun、map 或 filter)。 +% `[F(X) || X <- L]` 表示 "由 `F(X)` 组成的列表,其中 `X` 取自列表 `L`。 +L = [1,2,3,4,5]. +[2*X || X <- L]. % [2,4,6,8,10] +% 列表解析可以使用生成器,也可以使用过滤器,过滤器用于筛选列表的一部分。 +EvenNumbers = [N || N <- [1, 2, 3, 4], N rem 2 == 0]. % [2, 4] + +% Guard 是用于增强模式匹配的结构。 +% Guard 可用于简单的测试和比较。 +% Guard 可用于函数定义的头部,以`when`关键字开头,或者其他可以使用表达式的地方。 +max(X, Y) when X > Y -> X; +max(X, Y) -> Y. + +% guard 可以由一系列 guard 表达式组成,这些表达式以逗号分隔。 +% `GuardExpr1, GuardExpr2, ..., GuardExprN` 为真,当且仅当每个 guard 表达式均为真。 +is_cat(A) when is_atom(A), A =:= cat -> true; +is_cat(A) -> false. +is_dog(A) when is_atom(A), A =:= dog -> true; +is_dog(A) -> false. + +% guard 序列 `G1; G2; ...; Gn` 为真,当且仅当其中任意一个 guard 表达式为真。 +is_pet(A) when is_dog(A); is_cat(A) -> true; +is_pet(A) -> false. + +% Record 可以将元组中的元素绑定到特定的名称。 +% Record 定义可以包含在 Erlang 源代码中,也可以放在后缀为`.hrl`的文件中(Erlang 源代码中 include 这些文件)。 +-record(todo, { + status = reminder, % Default value + who = joe, + text +}). + +% 在定义某个 record 之前,我们需要在 shell 中导入 record 的定义。 +% 我们可以使用 shell 函数`rr` (read records 的简称)。 +rr("records.hrl"). % [todo] + +% 创建和更新 record。 +X = #todo{}. +% #todo{status = reminder, who = joe, text = undefined} +X1 = #todo{status = urgent, text = "Fix errata in book"}. +% #todo{status = urgent, who = joe, text = "Fix errata in book"} +X2 = X1#todo{status = done}. +% #todo{status = done,who = joe,text = "Fix errata in book"} + +% `case` 表达式。 +% `filter` 返回由列表`L`中所有满足`P(x)`为真的元素`X`组成的列表。 +filter(P, [H|T]) -> + case P(H) of + true -> [H|filter(P, T)]; + false -> filter(P, T) + end; +filter(P, []) -> []. +filter(fun(X) -> X rem 2 == 0 end, [1, 2, 3, 4]). % [2, 4] + +% `if` 表达式。 +max(X, Y) -> + if + X > Y -> X; + X < Y -> Y; + true -> nil; + end. + +% 警告: `if` 表达式里至少有一个 guard 为真,否则会触发异常。 + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% 3. 异常 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% 当遇到内部错误或显式调用时,会触发异常。 +% 显式调用包括 `throw(Exception)`, `exit(Exception)` 和 +% `erlang:error(Exception)`. +generate_exception(1) -> a; +generate_exception(2) -> throw(a); +generate_exception(3) -> exit(a); +generate_exception(4) -> {'EXIT', a}; +generate_exception(5) -> erlang:error(a). + +% Erlang 有两种捕获异常的方法。其一是将调用包裹在`try...catch`表达式中。 +catcher(N) -> + try generate_exception(N) of + Val -> {N, normal, Val} + catch + throw:X -> {N, caught, thrown, X}; + exit:X -> {N, caught, exited, X}; + error:X -> {N, caught, error, X} + end. + +% 另一种方式是将调用包裹在`catch`表达式中。 +% 此时异常会被转化为一个描述错误的元组。 +catcher(N) -> catch generate_exception(N). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% 4. 并发 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Erlang 依赖于 actor并发模型。在 Erlang 编写并发程序的三要素: +% 创建进程,发送消息,接收消息 + +% 启动一个新的进程使用`spawn`函数,接收一个函数作为参数 + +F = fun() -> 2 + 2 end. % #Fun<erl_eval.20.67289768> +spawn(F). % <0.44.0> + +% `spawn` 函数返回一个pid(进程标识符),你可以使用pid向进程发送消息。 +% 使用 `!` 操作符发送消息。 +% 我们需要在进程内接收消息,要用到 `receive` 机制。 + +-module(caculateGeometry). +-compile(export_all). +caculateAera() -> + receive + {rectangle, W, H} -> + W * H; + {circle, R} -> + 3.14 * R * R; + _ -> + io:format("We can only caculate area of rectangles or circles.") + end. + +% 编译这个模块,在 shell 中创建一个进程,并执行 `caculateArea` 函数。 +c(caculateGeometry). +CaculateAera = spawn(caculateGeometry, caculateAera, []). +CaculateAera ! {circle, 2}. % 12.56000000000000049738 + +% shell也是一个进程(process), 你可以使用`self`获取当前 pid + +self(). % <0.41.0> + +``` + +## References + +* ["Learn You Some Erlang for great good!"](http://learnyousomeerlang.com/) +* ["Programming Erlang: Software for a Concurrent World" by Joe Armstrong](http://pragprog.com/book/jaerlang/programming-erlang) +* [Erlang/OTP Reference Documentation](http://www.erlang.org/doc/) +* [Erlang - Programming Rules and Conventions](http://www.erlang.se/doc/programming_rules.shtml) |