¿Cómo escribir un módulo / paquete Python?

375

He estado creando scripts de Python para tareas simples en el trabajo y nunca me molesté en empaquetarlos para que otros los usen. Ahora me han asignado hacer un contenedor Python para una API REST. No tengo ni idea de cómo empezar y necesito ayuda.

Lo que tengo:

(Solo quiero ser lo más específico posible) Tengo el virtualenv listo, también está en github , el archivo .gitignore para python también está allí, además, la biblioteca de solicitudes para interactuar con la API REST. Eso es.

Aquí está el árbol de directorios actual

.
├── bin
   └── /the usual stuff/
├── include
   └── /the usual stuff/
├── lib
   └── python2.7
       └── /the usual stuff/
├── local
   └── /the usual stuff/
└── README.md

27 directories, 280 files

Ni siquiera sé dónde poner los archivos .py, si alguna vez hago uno.

Lo que quería hacer:

Haga que un módulo de Python sea instalable con "pip install ..."

Si es posible, quiero un proceso general paso a paso para escribir módulos de Python.

yowmamasita
fuente
15
Comenzaría con el capítulo 6 del tutorial (2.7) , o aquí para 3.x Busque en Internet el tutorial del módulo de Python y encontrará muchos otros.
Roland Smith
66
Nadie respondió la parte de pip
whackamadoodle3000
github.com/MacHu-GWU/pygitrepo-project esta biblioteca lo ayuda a crear esqueletos de proyectos desde cero, y la función que necesita está lista para usar.
MacSanhe

Respuestas:

424

Un módulo es un archivo que contiene definiciones y declaraciones de Python. El nombre del archivo es el nombre del módulo con el sufijo.py

cree y hello.pyluego escriba la siguiente función como su contenido:

def helloworld():
   print "hello"

Entonces puedes importar hello:

>>> import hello
>>> hello.helloworld()
'hello'
>>>

Para agrupar muchos .pyarchivos, colóquelos en una carpeta. __init__.pyPython considera cualquier carpeta con un módulo y puede llamarlos paquete

|-HelloModule
  |_ __init__.py
  |_ hellomodule.py

Puede continuar con la declaración de importación en su módulo de la manera habitual.

Para más información, ver 6.4. Paquetes .

Anuj
fuente
77
¿sería el último: de HellowModule import hellomodule? ¿Podría ser hola en la carpeta del módulo, por lo que sería de HelloModule import hello?
nycynik
Actualmente estoy jugando con Python y esta respuesta tiene que ser una de las más útiles que he encontrado. Lo explica muy bien, gracias.
Darren Wainwright
el comando "pip install" no funcionará, también debe estar en el mismo directorio para usarlo
Math Coder 101
234

Python 3 - ACTUALIZADO el 18 de noviembre de 2015

Encontré útil la respuesta aceptada, pero deseaba expandirme en varios puntos para el beneficio de otros basados ​​en mis propias experiencias.

Módulo: Un módulo es un archivo que contiene definiciones y declaraciones de Python. El nombre del archivo es el nombre del módulo con el sufijo .py agregado.

Ejemplo de módulo : supongamos que tenemos un solo script de Python en el directorio actual, aquí lo llamo mymodule.py

El archivo mymodule.py contiene el siguiente código:

def myfunc():
    print("Hello!")

Si ejecutamos el intérprete de python3 desde el directorio actual, podemos importar y ejecutar la función myfunc de las siguientes maneras diferentes (normalmente solo elegiría uno de los siguientes):

>>> import mymodule
>>> mymodule.myfunc()
Hello!
>>> from mymodule import myfunc
>>> myfunc()
Hello!
>>> from mymodule import *
>>> myfunc()
Hello!

Ok, eso fue bastante fácil.

Ahora suponga que tiene la necesidad de colocar este módulo en su propia carpeta dedicada para proporcionar un espacio de nombres de módulo, en lugar de ejecutarlo ad-hoc desde el directorio de trabajo actual. Aquí es donde vale la pena explicar el concepto de un paquete .

Paquete : los paquetes son una forma de estructurar el espacio de nombres de módulos de Python mediante el uso de "nombres de módulos con puntos". Por ejemplo, el nombre del módulo AB designa un submódulo llamado B en un paquete llamado A. Al igual que el uso de módulos evita que los autores de diferentes módulos tengan que preocuparse por los nombres de variables globales de cada uno, el uso de nombres de módulos con puntos salva a los autores de paquetes de módulos múltiples como NumPy o la Biblioteca de imágenes de Python por tener que preocuparse por los nombres de los módulos del otro.

Ejemplo de paquete : supongamos ahora que tenemos la siguiente carpeta y archivos. Aquí, mymodule.py es idéntico a antes, y __init__.py es un archivo vacío:

.
└── mypackage
    ├── __init__.py
    └── mymodule.py

Los archivos __init__.py son necesarios para que Python trate los directorios como paquetes. Para obtener más información, consulte el enlace de documentación de Módulos que se proporciona más adelante.

Nuestro directorio de trabajo actual está un nivel por encima de la carpeta ordinaria llamada mypackage

$ ls
mypackage

Si ejecutamos el intérprete python3 ahora, podemos importar y ejecutar el módulo mymodule.py que contiene la función requerida myfunc de las siguientes maneras diferentes (normalmente, solo elegiría uno de los siguientes):

>>> import mypackage
>>> from mypackage import mymodule
>>> mymodule.myfunc()
Hello!
>>> import mypackage.mymodule
>>> mypackage.mymodule.myfunc()
Hello!
>>> from mypackage import mymodule
>>> mymodule.myfunc()
Hello!
>>> from mypackage.mymodule import myfunc
>>> myfunc()
Hello!
>>> from mypackage.mymodule import *
>>> myfunc()
Hello!

Suponiendo Python 3, hay una excelente documentación en: Módulos

En términos de convenciones de nomenclatura para paquetes y módulos, las pautas generales se dan en PEP-0008; consulte los nombres de paquetes y módulos

Los módulos deben tener nombres cortos, todo en minúsculas. Los guiones bajos se pueden usar en el nombre del módulo si mejora la legibilidad. Los paquetes de Python también deben tener nombres cortos, todo en minúsculas, aunque se desaconseja el uso de guiones bajos.

arcseldon
fuente
55
Buena explicación simple. ¿Qué sucede si desea mantener otra carpeta dentro de mypackage?
Anuj Gupta
3
La inclusión depende totalmente de lo que escribiste. En el caso de que coloque cosas fuera de una función en su módulo, lo activará cuando llame como import mypackage. En el caso de que desee importar solo una función de un módulo (incluso un archivo) es mejor usar from module import function. En el caso de una subcarpeta from subfolder.module import function, simplemente puede llamar function()sin disparar otras partes del código. Además, no lo use from module import *si realmente no lo necesita.
m3nda
55
La única pregunta que queda es ¿cómo puedo obtener el paquete para importar todo import mypackage? Agregar import mymodulea __init__.pyno funciona ..
576i
¡Buena explicación! sin embargo, tengo una pregunta si numpy es un paquete, ¿cómo puedo ejecutar numpy.cos (1) en mi intérprete porque parece ser el nombre de un módulo que falta? ¿No?
user1935724
3
¿Qué tal pip?
whackamadoodle3000
199

Como nadie cubrió esta pregunta del OP todavía:

Lo que quería hacer:

Haga que un módulo de Python sea instalable con "pip install ..."

Aquí hay un ejemplo mínimo absoluto, que muestra los pasos básicos de preparación y carga de su paquete a PyPI usando setuptoolsy twine.

Esto de ninguna manera es un sustituto para leer al menos el tutorial , hay mucho más de lo que se cubre en este ejemplo muy básico.

Crear el paquete en sí ya está cubierto por otras respuestas aquí, así que supongamos que tenemos ese paso cubierto y nuestra estructura de proyecto de esta manera:

.
└── hellostackoverflow/
    ├── __init__.py
    └── hellostackoverflow.py

Para usar setuptoolspara empaquetar, necesitamos agregar un archivo setup.py, esto va a la carpeta raíz de nuestro proyecto:

.
├── setup.py
└── hellostackoverflow/
    ├── __init__.py
    └── hellostackoverflow.py

Como mínimo, especificamos los metadatos para nuestro paquete, nuestro setup.pyse vería así:

from setuptools import setup

setup(
    name='hellostackoverflow',
    version='0.0.1',
    description='a pip-installable package example',
    license='MIT',
    packages=['hellostackoverflow'],
    author='Benjamin Gerfelder',
    author_email='[email protected]',
    keywords=['example'],
    url='https://github.com/bgse/hellostackoverflow'
)

Como lo hemos configurado license='MIT', incluimos una copia en nuestro proyecto como LICENCE.txt, junto con un archivo Léame en reStructuredText como README.rst:

.
├── LICENCE.txt
├── README.rst
├── setup.py
└── hellostackoverflow/
    ├── __init__.py
    └── hellostackoverflow.py

En este punto, estamos listos para comenzar a usar el empaque setuptools, si no lo tenemos instalado, podemos instalarlo con pip:

pip install setuptools

Para hacer eso y crear un source distribution, en nuestra carpeta raíz del proyecto llamamos a nuestro setup.pydesde la línea de comandos, especificando que queremos sdist:

python setup.py sdist

Esto creará nuestro paquete de distribución e información de huevo, y dará como resultado una estructura de carpetas como esta, con nuestro paquete en dist:

.
├── dist/
├── hellostackoverflow.egg-info/
├── LICENCE.txt
├── README.rst
├── setup.py
└── hellostackoverflow/
    ├── __init__.py
    └── hellostackoverflow.py

En este punto, tenemos un paquete que podemos instalar usando pip, así que desde la raíz de nuestro proyecto (suponiendo que tenga todos los nombres como en este ejemplo):

pip install ./dist/hellostackoverflow-0.0.1.tar.gz

Si todo va bien, ahora podemos abrir un intérprete de Python, diría que en algún lugar fuera de nuestro directorio de proyectos para evitar confusiones, y tratar de usar nuestro nuevo paquete brillante:

Python 3.5.2 (default, Sep 14 2017, 22:51:06) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from hellostackoverflow import hellostackoverflow
>>> hellostackoverflow.greeting()
'Hello Stack Overflow!'

Ahora que hemos confirmado que el paquete se instala y funciona, podemos subirlo a PyPI.

Dado que no queremos contaminar el repositorio en vivo con nuestros experimentos, creamos una cuenta para el repositorio de prueba e instalamos twinepara el proceso de carga:

pip install twine

Ahora estamos casi allí, con nuestra cuenta creada, simplemente le pedimos twineque cargue nuestro paquete, solicitará nuestras credenciales y cargará nuestro paquete en el repositorio especificado:

twine upload --repository-url https://test.pypi.org/legacy/ dist/*

Ahora podemos iniciar sesión en nuestra cuenta en el repositorio de prueba de PyPI y maravillarnos con nuestro paquete recién cargado por un tiempo, y luego tomarlo usando pip:

pip install --index-url https://test.pypi.org/simple/ hellostackoverflow

Como podemos ver, el proceso básico no es muy complicado. Como dije antes, hay mucho más de lo que se trata aquí, así que continúe y lea el tutorial para obtener una explicación más detallada.

bgse
fuente
¿Se publicará mi paquete inmediatamente después setuptools?
U10-Forward
@ U9-Forward No, la publicación ha finalizado twine, pero puede probar su paquete localmente antes de publicarlo después de haberlo creado setuptools.
bgse
9

Una vez que haya definido sus comandos elegidos, simplemente puede arrastrar y soltar el archivo guardado en la carpeta Lib en sus archivos de programa de Python.

>>> import mymodule 
>>> mymodule.myfunc()
Dreamatronix
fuente
2

Haga un archivo llamado "hello.py"

Si está utilizando Python 2.x

def func():
    print "Hello"

Si está utilizando Python 3.x

def func():
    print("Hello")

Ejecute el archivo Luego, puedes probar lo siguiente:

>>> import hello
>>> hello.func()
Hello

Si quieres un poco duro, puedes usar lo siguiente:

Si está utilizando Python 2.x

def say(text):
    print text

Si está utilizando Python 3.x

def say(text):
    print(text)

¿Ves el que está en el paréntesis al lado del define? Eso es importante. Es el que puede usar dentro de la definición.

Texto: puede usarlo cuando desee que el programa diga lo que quiere. Según su nombre, es texto. Espero que sepas lo que significa el texto. Significa "palabras" u "oraciones".

Ejecute el archivo Luego, puede intentar lo siguiente si está utilizando Python 3.x:

>>> import hello
>>> hello.say("hi")
hi
>>> from hello import say
>>> say("test")
test

Para Python 2.x: ¿supongo que lo mismo con Python 3? Ni idea. Corrígeme si cometí un error en Python 2.x (conozco Python 2 pero estoy acostumbrado a Python 3)

Kakkoiikun
fuente
2

Creé un proyecto para iniciar fácilmente un esqueleto de proyecto desde cero . https://github.com/MacHu-GWU/pygitrepo-project .

Además, puede crear un proyecto de prueba, por ejemplo de let, learn_creating_py_package.

Puede aprender qué componente debe tener para diferentes propósitos, como :

  • crear virtualenv
  • instalarse
  • ejecutar unittest
  • ejecutar código de cobertura
  • documento de compilación
  • desplegar documento
  • ejecutar unittest en diferentes versiones de python
  • implementar en PYPI

La ventaja de usar pygitrepoes que esos tediosos se crean automáticamente y se adaptan a su package_name, project_name, github_account, document host service, windows or macos or linux.

Es un buen lugar para aprender a desarrollar un proyecto de Python como un profesional.

Espero que esto pueda ayudar.

Gracias.

MacSanhe
fuente