Псевдоним для метода рассматривается как функция-член - PullRequest
0 голосов
/ 22 марта 2020

Я пытаюсь создать псевдоним функции, не являющейся членом внутри класса, но я считаю, Python рассматривает ее как функцию-член.

def bar(a, b):
    print(a, b)

class Foo:

    baz = bar

f = Foo()
f.baz(1, 2)

TypeError: bar() takes 2 positional arguments but 3 were given

Поэтому я отбрасываю один аргумент и получаю:

f.baz(1)

<__main__.Foo object at 0x0000026CD8279DD8> 1

Почему экземпляр передается в качестве аргумента a?

Если бы я использовал псевдоним другого метода, скажем из модуля:

class Foo:

    baz = bar.bar

Где bar.bar определен точно так же, но в модуле bar он работает без проблем.

1 Ответ

1 голос
/ 22 марта 2020

Все function -значимые атрибуты класса являются методами экземпляра, независимо от того, определена ли функция внутри или вне оператора class.

И a.baz, и a.bar запускают протокол дескриптора, который возвращает результат bar.__get__(a, A), который вызывается, который пытается вызвать bar с двумя аргументами.

Если это так, вы можете явно запустить это поведение метода без определения каких-либо атрибутов класса.

def bar(a, b):
    print(f'"Object": {a}')
    print(f'Argument: {b}')

class Foo:
    pass

f = Foo()
bar.__get__(f, Foo)(2)

производит вывод

Object: <__main__.Foo object at 0x108cb5e80>
Argument: 2

То, что вы хотите, это метод stati c, так что при его вызове базовой функции не даются никакие неявные аргументы, только те аргументы, которые передаются самому методу.

class Foo:
    baz = staticmethod(bar)

f = Foo()
f.baz(1, 2)  # bar gets arguments 1 and 2, not f, 1, and 2.

staticmethod.__get__ просто возвращают саму базовую функцию, а не method объект, который оборачивает функцию.


Относительно отличается от поведения os.open, вы должны признать, что os.open не имеет тот же тип, что и значение, созданное оператором def:

>>> import os
>>> def bar(): pass
...
>>> type(os.open)
<class 'builtin_function_or_method'>
>>> type(bar)
<class 'function'>

Тип builtin_function_or_method не имеет реализовать __get__, поэтому при доступе к такому значению через поиск атрибутов ничего не происходит.

...