Функция в классе без декоратора или `self` - PullRequest
0 голосов
/ 17 февраля 2019

У меня есть следующий класс с функцией:

class A: 
    def myfn():
        print("In myfn method.")

Здесь функция не имеет self в качестве аргумента.Он также не имеет @classmethod или @staticmethod в качестве декоратора.Однако он работает, если вызывается с классом:

A.myfn()

Вывод:

In myfn method.

Но выдает ошибку при вызове из любого экземпляра:

a = A()
a.myfn()

Вывод ошибки:

Traceback (most recent call last):
  File "testing.py", line 16, in <module>
    a.myfn()
TypeError: myfn() takes 0 positional arguments but 1 was given

возможно, потому что self также был отправлен в качестве аргумента.

Какую функцию это будет вызывать?Это будет статическая функция?Желательно ли использовать такую ​​функцию в классах?В чем недостаток?

Редактировать: эта функция работает только при вызове с классом, а не с объектом / экземпляром.Мой главный вопрос: как называется такая функция?

Edit2: Из ответов видно, что этот тип функций, несмотря на простейшую форму, не считается законным.Однако, поскольку ни в одном из многих ответов не упоминается ни о каком серьезном недостатке, я считаю, что это может быть полезной конструкцией, особенно для группировки моих собственных статических функций в классе, который я могу вызывать по мере необходимости.Мне не нужно создавать какой-либо экземпляр этого класса.По крайней мере, это избавляет меня от ввода @staticmethod каждый раз и делает код менее сложным.Кроме того, это получается аккуратно для кого-то, чтобы расширить мой класс.Хотя все такие функции могут храниться на верхнем / глобальном уровне, их хранение в классе является более модульным.Тем не менее, я считаю, что должно быть определенное имя для такой простой конструкции, которая работает именно таким образом, и она должна быть признана законной.Это также может помочь новичкам понять, почему аргумент self необходим для обычных функций в классе Python.Это только увеличит простоту этого великого языка.

Ответы [ 4 ]

0 голосов
/ 17 февраля 2019

в дополнение к ответу @ chepnet, если вы определяете класс, чьи объекты реализуют протокол дескриптора , например:

class Descr:
    def __get__(self, obj, type=None):
        print('get', obj, type)
    def __set__(self, obj, value):
        print('set', obj, value)
    def __delete__(self, obj):
        print('delete', obj)

, вы можете встраивать его экземпляр в класс и вызывать различныеоперации над ним:

class Foo:
    foo = Descr()

Foo.foo
obj = Foo()
obj.foo

, который выводит:

get None <class '__main__.Foo'>
get <__main__.Foo object at 0x106d4f9b0> <class '__main__.Foo'>

, поскольку функции также реализуют протокол дескриптора, мы можем воспроизвести это, выполнив:

def bar():
    pass

print(bar)
print(bar.__get__(None, Foo))
print(bar.__get__(obj, Foo))

, которыйвывод:

<function bar at 0x1062da730>
<function bar at 0x1062da730>
<bound method bar of <__main__.Foo object at 0x106d4f9b0>>

надеюсь, что это дополняет ответ Чепнета, который я нашел немного кратким / непрозрачным

0 голосов
/ 17 февраля 2019

Такая функция отличается от той, которую предоставляет @staticmethod, но на самом деле это своего рода статический метод.

С помощью @staticmethod вы также можете вызывать статический метод в экземпляре класса,Если A - это класс, а A.a - это static method, вы сможете использовать A.a() и A().a().Без этого декоратора будет работать только первый пример, потому что для второго, как вы правильно заметили, «self [будет] также [отправлено] в качестве аргумента»:

class A:
    @staticmethod
    def a():
        return 1

Запуск этого:

>>> A.a()  # `A` is the class itself
1
>>> A().a()  # `A()` is an instance of the class `A`
1

С другой стороны:

class B:
    def b():
        return 2

Теперь вторая версия не работает:

>>> B.b()
2
>>> B().b()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: b() takes 0 positional arguments but 1 was given
0 голосов
/ 17 февраля 2019

Это не настоящий метод.Правильно объявленные методы экземпляра должны иметь аргумент self (имя является всего лишь соглашением и может быть изменено, если вы хотите трудно читать код), а методы класса и методы static должны быть представлены их соответствующим декоратором.

Нона более низком уровне def в объявлении класса просто создает функцию и назначает ее члену класса.Это именно то, что происходит здесь: A.my_fn является функцией и может успешно вызываться как A.my_fn().

Но так как она не была объявлена ​​с @staticmethod, это не настоящий статический метод, и он не можетприменяться к экземпляру A.Python видит член с таким именем, который оказывается функцией, которая не является ни статическим, ни методом класса, поэтому он добавляет текущий экземпляр в список аргументов и пытается выполнить его.

Чтобы ответить на ваш точный ответвопрос, это не метод, а просто функция, которая назначается члену класса.

0 голосов
/ 17 февраля 2019

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

A.myfn == A.myfn.__get__(None, A)

Здесь myfn - это метод экземпляра, хотя он не был определен должным образом для использования в качестве такового.Однако при доступе через класс возвращаемое значение __get__ представляет собой просто сам объект функции, и функция может вызываться так же, как статический метод.

Доступ через экземпляр приводит к другому вызову __get__.Если a является экземпляром A, то

a.myfn() == A.myfn.__get__(a, A)

Здесь __get__ пытается, по сути, вернуть частичное применение myfn в a, но потому что myfnне принимает никаких аргументов, что не получается.

Вы можете спросить, что является статическим методом?staticmethod - это тип, который упаковывает функцию и определяет свой собственный метод __get__.Этот метод возвращает базовую функцию независимо от того, осуществляется ли доступ к атрибуту через класс или экземпляр.В противном случае разница между статическим методом и обычной функцией очень мала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...