Как расширить модуль python? Добавление новых функций в пакет "python-twitter"

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

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

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

5 ответов


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

самый простой способ:

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

exttwitter.py

import twitter

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

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

сложнее (возможно, ООН-подходящие для Python) способ:

импорт * из 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 - вы можете удалить его, но тогда вы не обрабатываете usecase желания расширить функцию, которая была в пространстве имен basemodule.

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


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


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

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 dict, где (если вы правильно intrepid) вы можете заменить существующие модули, а также добавить новые.


скажем, у вас есть более старый модуль под названием 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"""

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


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

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

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

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

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

эта вещь unittestetd гарантированно разбирает твиты так же, как Twitter.com делает это.