2010-12-31 2 views
4

У меня возникают некоторые проблемы с параметром self, а некоторые, казалось бы, непоследовательное поведение на Python раздражают меня, поэтому я считаю, что лучше спросить некоторых людей в курсе. У меня есть класс, Foo. Этот класс будет иметь множество методов, m1, до mN. Для некоторых из них я буду использовать стандартное определение, как в случае m1 ниже. Но для других, более удобно просто назначить имя метода напрямую, как я сделал с m2 и m3.Python и параметр self

import os 

def myfun(x, y): 
    return x + y 

class Foo(): 
    def m1(self, y, z): 
     return y + z + 42 

    m2 = os.access 
    m3 = myfun 

f = Foo() 
print f.m1(1, 2) 
print f.m2("/", os.R_OK) 
print f.m3(3, 4) 

Теперь я знаю, что os.access не принимает self параметр (на первый взгляд). И у этого до сих пор нет проблем с этим типом назначения. Однако я не могу сделать то же самое для своих собственных модулей (предположим, myfun определено в mymodule.myfun). Запуск выше код дает следующий результат:

3 
True 
Traceback (most recent call last): 
    File "foo.py", line 16, in <module> 
    print f.m3(3, 4) 
TypeError: myfun() takes exactly 2 arguments (3 given) 

Проблема заключается в том, что из-за рамки я работаю, я не могу не иметь класс Foo по крайней мере. Но я бы хотел, чтобы у меня не было mymodule вещей в фиктивном классе. Для того, чтобы сделать это, мне нужно сделать что-то аля

def m3(self,a1, a2): 
    return mymodule.myfun(a1,a2) 

Что является чрезвычайно избыточно, если у вас есть как 20 из них. Итак, вопрос в том, как я могу сделать это совершенно другим и, очевидно, гораздо более умным способом, или как я могу заставить свои собственные модули вести себя как встроенные, поэтому он не жалуется на то, что слишком много получает один аргумент.

ответ

2

Я просто хочу добавить, что поведение не противоречит, как уже намекал Люк.

Просто попробуйте следующее

print Foo.__dict__ 
    {'__doc__': None, 
    '__module__': '__main__', 
    'm1': <function m1 at 0x02861630>, 
    'm2': <built-in function access>, 
    'm3': <function myfun at 0x028616F0>} 

Здесь вы можете увидеть, что Python не может различать между m1 и m2. Вот почему оба метода оцениваются по методу bound.

Связанный метод является то, как метод с дополнительным первым аргументом указывает на объект: self.m(1, 2) -> m(self, 1, 2)

Это связывание поведение реализовано только для определенных пользователем методов. Это объясняет, почему self.m2("/", os.R_OK) не оценивается до m2(self, "/", os.R_OK).

последнее демо:

print Foo.m1 
    <unbound method Foo.m1> 
print Foo.m2 
    <built-in function access> 
print f.m1 
    <bound method Foo.m1 of <__main__.Foo instance at 0x02324418>> 
print f.m2 
    <built-in function access> 

Дополнительная информация о различных типах функций можно найти здесь:

http://docs.python.org/reference/datamodel.html

И, как упоминалось ранее этот механизм связывания также может быть предотвращено с помощью Дескриптор статического метода:

http://docs.python.org/library/functions.html#staticmethod

0

Один из способов будет вручную применить статический метод декоратора:

class Foo(object): 
    m3 = staticmethod(mymodule.myfun) 
4

os.access() является встроенной функцией, в том смысле, что она является частью модуля расширения написанной на C. Когда определяется класс , Python не распознает m2 как метод, потому что это неправильный тип. Методы - это функции Python, а не C-функции. m3, однако, является функцией Python, поэтому он распознается как метод и обрабатывается как таковой.

Иными словами, это m2, что является исключительным здесь, а не m3.

Один простой способ сделать то, что вы хотите бы сделать m3 статический метод:

m3 = staticmethod(myfun) 

Теперь интерпретатор не знает и не пытаться передать myfun() параметр self, когда его называют как m3 методом Foo.

+0

вашей общая точка имеет смысл, но я не вижу, как его отношение, является ли модуль написан на C, Python или Befunge –

+0

Точки заключается в том, что он запускается как * собственный код *, динамически связанный с интерпретатором. Вы правы, однако, это может быть на любом компилированном языке. –

+0

'staticmethod' заставляет все работать нормально. Но вещи не должны работать по-другому, когда встроенный или собственный код, или что-то вроде ИМО. Поэтому я предполагаю, что соглашусь на рабочий код, и понимание придет в какой-то другой момент. – Svend

2

Я думаю, что вы ищете staticmethod(). См. Документы here.

m2 = staticmethod(os.access) 
m3 = staticmethod(myfun) 

Что касается того, почему m2 работал в вашем примере и m3, это не явилось мне. Печать f.m2 и f.m3 в вашем исходном примере показывает, что f.m2 является прямой ссылкой на встроенную функцию os.access, тогда как f.m3 является связанным методом (привязанным к экземпляру f).

1

В этом случае вы должны использовать функцию staticmethod. При написании статических методов класса, вы можете использовать его в качестве декоратора:

class A: 
    def printValue(self,value): 
     print value 

    @staticmethod 
    def staticPrintValue(value): 
     print value 

>>> A.printValue(5) 
Traceback (most recent call last): 
    File "<pyshell#2>", line 1, in <module> 
    A.printValue(5) 
TypeError: unbound method printValue() must be called with A instance as first argument (got int instance instead) 

>>> A.staticPrintValue(5) 
5 
Смежные вопросы