Как расширить модуль Python? Добавление новой функциональности в пакет `python-twitter` - PullRequest
18 голосов
/ 25 апреля 2010

Каковы рекомендации по расширению существующего модуля Python - в этом случае я хочу расширить пакет python-twitter, добавив новые методы в базовый класс API.

Я посмотрел на tweepy, и мне это тоже нравится; Я просто нахожу python-twitter проще для понимания и расширяю с помощью нужной мне функциональности.

У меня уже есть методы написанные - я пытаюсь найти наиболее питонский и наименее разрушительный способ добавить их в модуль пакета python-twitter, не меняя ядро ​​этих модулей.

Ответы [ 5 ]

21 голосов
/ 25 апреля 2010

Несколько способов.

Простой способ:

Не расширять модуль, расширять классы.

exttwitter.py

import twitter

class Api(twitter.Api):
    pass 
    # override/add any functions here.

Недостаток: каждый класс в твиттере должен быть в exttwitter.py, даже если это просто заглушка (как указано выше)

Более сложный (возможно, непитонический) путь:

Импорт * из python-twitter в модуль, который вы затем расширяете.

Например:

basemodule.py

 class Ball():
    def __init__(self,a):
        self.a=a
    def __repr__(self):
        return "Ball(%s)" % self.a

def makeBall(a):
    return Ball(a)

def override():
    print "OVERRIDE ONE"

def dontoverride():
    print "THIS WILL BE PRESERVED"

extmodule.py

from basemodule import *
import basemodule

def makeBalls(a,b):
    foo = makeBall(a)
    bar = makeBall(b)
    print foo,bar

def override():
    print "OVERRIDE TWO"

def dontoverride():
    basemodule.dontoverride()
    print "THIS WAS PRESERVED"

runscript.py

import extmodule

#code is in extended module
print extmodule.makeBalls(1,2)
#returns Ball(1) Ball(2)

#code is in base module
print extmodule.makeBall(1)
#returns Ball(1)

#function from extended module overwrites base module
extmodule.override()
#returns OVERRIDE TWO

#function from extended module calls base module first
extmodule.dontoverride()
#returns THIS WILL BE PRESERVED\nTHIS WAS PRESERVED

Я не уверен, что двойной импорт в extmodule.py является pythonic - вы можете удалить его, но тогда вы не обработаете сценарий необходимости расширения функции, которая была в пространстве имен basemodule.

Что касается расширенных классов, просто создайте новый класс API (basemodule.API) для расширения модуля API Twitter.

5 голосов
/ 25 апреля 2010

Не добавляйте их в модуль. Подклассы классов, которые вы хотите расширить и использовать ваши подклассы в вашем собственном модуле, не меняя оригинальных вещей вообще.

4 голосов
/ 05 сентября 2018

Вот как вы можете напрямую манипулировать списком модулей во время выполнения - предупреждение о спойлере: вы получаете тип модуля из types module:

from __future__ import print_function
import sys
import types
import typing as tx

def modulize(namespace: tx.Dict[str, tx.Any],
             modulename: str,
             moduledocs: tx.Optional[str] = None) -> types.ModuleType:

    """ Convert a dictionary mapping into a legit Python module """

    # Create a new module with a trivially namespaced name:
    namespacedname: str = f'__dynamic_modules__.{modulename}'
    module = types.ModuleType(namespacedname, moduledocs)
    module.__dict__.update(namespace)

    # Inspect the new module:
    name: str = module.__name__
    doc: tx.Optional[str] = module.__doc__
    contents: str = ", ".join(sorted(module.__dict__.keys()))
    print(f"Module name:      {name}")
    print(f"Module contents:  {contents}")
    if doc:
        print(f"Module docstring: {doc}")

    # Add to sys.modules, as per import machinery:
    sys.modules.update({ modulename : module })

    # Return the new module instance:
    return module

… тогда вы могли бы использовать такую ​​функцию как:

ns = {
         'func' : lambda: print("Yo Dogg"), # these can also be normal non-lambda funcs
    'otherfunc' : lambda string=None: print(string or 'no dogg.'),
      '__all__' : ('func', 'otherfunc'),
      '__dir__' : lambda: ['func', 'otherfunc'] # usually this’d reference __all__
}

modulize(ns, 'wat', "WHAT THE HELL PEOPLE")
import wat

# Call module functions:
wat.func()
wat.otherfunc("Oh, Dogg!")

# Inspect module:
contents = ", ".join(sorted(wat.__dict__.keys()))
print(f"Imported module name:      {wat.__name__}")
print(f"Imported module contents:  {contents}")
print(f"Imported module docstring: {wat.__doc__}")

… Вы также можете создать свой собственный подкласс модуля, указав types.ModuleType в качестве предка вашего недавно объявленного class, конечно; Я никогда не считал это необходимым.

(Кроме того, у вас нет для получения типа модуля из модуля types - вы всегда можете просто сделать что-то вроде ModuleType = type(os) после импорта os - я специально указал на это один источник типа, потому что он неочевиден; в отличие от многих других встроенных типов, Python не предоставляет доступа к типу модуля в глобальном пространстве имен.)

Реальное действие заключается в диктовке sys.modules, где (если вы соответственно отважны) вы можете заменить существующие модули, а также добавить свои новые.

3 голосов
/ 26 октября 2015

Скажем, у вас есть старый модуль с именем mod, который вы используете следующим образом:

import mod

obj = mod.Object()
obj.method()
mod.function()
# and so on...

И вы хотите расширить его, не заменяя его для своих пользователей. Легко сделано. Вы можете дать вашему новому модулю другое имя, newmod.py или поместить его с тем же именем в более глубокий путь и оставить то же имя, например. /path/to/mod.py. Затем ваши пользователи могут импортировать его одним из следующих способов:

import newmod as mod       # e.g. import unittest2 as unittest idiom from Python 2.6

или

from path.to import mod    # useful in a large code-base

В вашем модуле вы захотите сделать доступными все старые имена:

from mod import *

или явно назовите каждое импортируемое имя:

from mod import Object, function, name2, name3, name4, name5, name6, name7, name8, name9, name10, name11, name12, name13, name14, name15, name16, name17, name18, name19, name20, name21, name22, name23, name24, name25, name26, name27, name28, name29, name30, name31, name32, name33, name34, name35, name36, name37, name38, name39

Я думаю, что import * будет более понятным для этого варианта использования - если базовый модуль расширяет функциональность, вы будете в курсе всех событий (хотя вы можете затенять новые объекты с тем же именем).

Если mod, который вы расширяете, имеет приличную __all__, это ограничит импортируемые имена.

Вы должны также объявить __all__ и расширить его с помощью расширенного модуля __all__.

import mod
__all__ = ['NewObject', 'newfunction']
__all__ += mod.__all__   
# if it doesn't have an __all__, maybe it's not good enough to extend
# but it could be relying on the convention of import * not importing
# names prefixed with underscores, (_like _this)

Затем расширяйте объекты и функциональность, как обычно.

class NewObject(object):
    def newmethod(self):
        """this method extends Object"""

def newfunction():
    """this function builds on mod's functionality"""

Если новые объекты предоставляют функциональность, которую вы собираетесь заменить (или, возможно, вы переносите новую функциональность в более старую базу кода), вы можете перезаписать имена

2 голосов
/ 25 апреля 2010

Могу ли я предложить не изобретать Колесо здесь? Я создаю> 6k-линию Twitter Client уже 2 месяца, сначала я тоже проверил python-twitter, но он сильно отстает от недавних изменений API, Разработка тоже не слишком активна, также было (по крайней мере, когда я последний раз проверял) нет поддержки OAuth / xAuth).

Так что, обыскав немного больше, я обнаружил твипи:
http://github.com/joshthecoder/tweepy

Плюсы: Активная разработка, OAauth / xAuth и последние обновления API.
Скорее всего, то, что вам нужно, уже есть.

Так что я предлагаю пойти с этим, это работает для меня, единственное, что я должен был добавить, это xAuth (который получил слияние с tweepy:)

О, бесстыдный плагин, если вам нужно разобрать твиты и / или отформатировать их в HTML, используйте мою python-версию библиотеки twitter-text- *:
http://github.com/BonsaiDen/twitter-text-python

Эта штука является unittestetd гарантированно для анализа твитов, как это делает Twitter.com.

...