Лучший способ вызвать методы в объявлениях классов Python?

StackOverflow https://stackoverflow.com/questions/304655

Вопрос

Допустим, я объявляю класс C и некоторые из этих заявлений очень похожи.Я бы хотел использовать функцию f чтобы уменьшить повторение кода для этих объявлений.Это можно просто объявить и использовать f как обычно:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     w = f(42)
... 
>>> C.v
'<9>'
>>> C.w
'<42>'
>>> C.f(4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with C instance as first argument (got int instance instead)

Упс!Я непреднамеренно разоблачил f к внешнему миру, но для этого не требуется self аргумент (и не может по очевидным причинам).Одной из возможностей было бы del функция после того, как я ее использую:

>>> class C(object):
...     def f(num):
...             return '<' + str(num) + '>'
...     v = f(9)
...     del f
... 
>>> C.v
'<9>'
>>> C.f
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'C' has no attribute 'f'

Но что, если я хочу использовать f опять позже, после объявления?Удалять функцию не годится.Я мог бы сделать его "приватным" (т.е. добавить к его имени префикс __) и дайте ему @staticmethod лечение, но призывающее staticmethod объекты, проходящие по аномальным каналам, становятся очень пугающими:

>>> class C(object):
...     @staticmethod
...     def __f(num):
...             return '<' + str(num) + '>'
...     v = __f.__get__(1)(9)   # argument to __get__ is ignored...
... 
>>> C.v
'<9>'

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

Должен быть лучший способ сделать это.Как я могу чисто объявить функцию в классе, использовать ее во время ее объявления, а также использовать ее позже из класса?Должен ли я вообще это делать?

Это было полезно?

Решение

Проще говоря, решение заключается в том, что f не обязательно должен быть членом класса.Я предполагаю, что ваш мыслительный процесс прошел через языковой фильтр Javaish, вызывающий ментальный блок.Это звучит примерно так:

def f(n):
    return '<' + str(num) + '>'

class C(object):

    v = f(9)
    w = f(42)

Затем, когда вы захотите использовать f снова, просто используйте его

>>> f(4)
'<4>'

Я думаю, мораль этой истории такова: "В Python вы не иметь загнать все в класс".

Другие советы

Расширяющийся Али Аответ, если вы действительно хотите избежать f в пространстве имен модуля (и использования неэкспортируемого имени, такого как _f, или установки __all__ недостаточно), то вы могли бы достичь этого, создав класс внутри замыкания.

def create_C():
    def f(num):
        return '<' + str(num) + '>'

    class C(object):
        v = f(9)
        def method_using_f(self, x):  return f(x*2)
    return C

C=create_C()
del create_C

Таким образом, C имеет доступ к f в рамках своего определения и методов, но больше ничего не делает (за исключением довольно сложного самоанализа его методов (C.method_using_f.im_func.func_closure))

Это, вероятно, излишне для большинства целей, хотя - документирование того, что f является внутренним, с использованием соглашения о присвоении имен с префиксом "_" должно в целом быть достаточным.

[Править] Еще один вариант - хранить ссылку на предварительно обернутый объект функции в методах, в которых вы хотите его использовать.Например, установив его в качестве аргумента по умолчанию:

class C(object):
    def f(num):
        return '<' + str(num) + '>'

    v = f(9)
    def method_using_f(self, x, f=f):  return f(x*2)

    del f

(Хотя я думаю, что подход закрытия, вероятно, лучше)

Это одна из возможностей:

class _C:
    # Do most of the function definitions in here
    @classmethod
    def f(cls):
        return 'boo'

class C(_C):
    # Do the subsequent decoration in here
    v = _C.f()

Я верю, что вы пытаетесь это сделать:

class C():
...     class F():
...         def __call__(self,num):
...             return "<"+str(num)+">"
...     f=F()
...     v=f(9)
>>> C.v
'<9>'
>>> C.f(25)
'<25>'
>>> 

Может быть, есть лучшее или более питоническое решение...

"объявите функцию в классе, используйте ее во время ее объявления, а также используйте ее позже из класса"

Извините.Это невозможно сделать.

"Не может быть сделано", похоже, не уживается с Python

Один из вариантов:напишите лучше staticmethod:

class staticfunc(object):
    def __init__(self, func):
        self.func = func
    def __call__(self, *args, **kw):
        return self.func(*args, **kw)
    def __repr__(self):
        return 'staticfunc(%r)' % self.func

Давайте начнем с самого начала.

"объявите функцию в классе, используйте ее во время ее объявления, а также используйте ее позже из класса"

Извините.Это невозможно сделать."В классе" противоречит "используется при объявлении".

  • В классе означает, созданный как часть объявления.
  • Используемый во время объявления означает, что он существует вне класса.Часто как метакласс.Однако есть и другие способы.

Неясно, какими должны быть C.w и C.v.Это просто струны?Если да, то внешняя функция f это лучшее решение."не загромождать пространство имен" немного надуманно.В конце концов, вы хотите использовать его снова.

Он находится в том же модуле , что и C.Вот почему в Python есть модули.Он связывает функцию и класс воедино.

import myCmod

myCmod.C.w
myCmod.C.v
myCmod.f(42)

Если w и v не являются простыми строками, есть действительно хорошее решение, которое дает большую гибкость.

Как правило, для переменных уровня класса ("статических"), подобных этой, мы можем использовать другие классы.Полностью достичь желаемого API невозможно, но это близко.

>>> class F(object):
    def __init__( self, num ):
        self.value= num
        self.format= "<%d>" % ( num, )

>>> class C(object):
    w= F(42)
    v= F(9)

>>> C.w
<__main__.F object at 0x00C58C30>
>>> C.w.format
'<42>'
>>> C.v.format
'<9>'

Преимущество этого в том, что F - это правильная, первоклассная вещь, которую можно расширить.Не "скрытая" вещь, которую мы пытаемся избежать разоблачения.Это факт жизни, поэтому мы могли бы с таким же успехом следовать принципу "Открыто / закрыто" и сделать его открытым для расширения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top