Python: получить метод несвязанного класса

Как вы можете получить метод не связанного класса?

class Foo:
    @classmethod
    def bar(cls): pass

>>> Foo.bar
>

Изменить: Это python 3. Извините за путаницу.

8
nl ja de
Вы действительно имели в виду для Foo класс старинного стиля здесь?
добавлено автор abarnert, источник
На что вы на самом деле хотите эту вещь? Что вы планируете с этим делать? Если вы хотите совершать вызовы, передавая ему явный аргумент cls или создавая связанные с ним методы, или что-то еще, то, что вы хотите (в Python 3), является просто простой старой функцией. (И если вы хотите вызвать его напрямую, связанный метод уже есть то, что вы хотите.)
добавлено автор abarnert, источник
На что вы на самом деле хотите эту вещь? Что вы планируете с этим делать? Если вы хотите совершать вызовы, передавая ему явный аргумент cls или создавая связанные с ним методы, или что-то еще, то, что вы хотите (в Python 3), является просто простой старой функцией. (И если вы хотите вызвать его напрямую, связанный метод уже есть то, что вы хотите.)
добавлено автор abarnert, источник
Изменение фразы на «метод не связанного класса» не помогает. Такого еще не существует. Если вы хотите самой голой функции, мой ответ уже говорит, как это получить. Если вы хотите чего-то другого, то либо вы просите что-то, чего не существует, либо вам нужно объяснить, что именно вы просите.
добавлено автор abarnert, источник
Изменение фразы на «метод не связанного класса» не помогает. Такого еще не существует. Если вы хотите самой голой функции, мой ответ уже говорит, как это получить. Если вы хотите чего-то другого, то либо вы просите что-то, чего не существует, либо вам нужно объяснить, что именно вы просите.
добавлено автор abarnert, источник
Изменение фразы на «метод не связанного класса» не помогает. Такого еще не существует. Если вы хотите самой голой функции, мой ответ уже говорит, как это получить. Если вы хотите чего-то другого, то либо вы просите что-то, чего не существует, либо вам нужно объяснить, что именно вы просите.
добавлено автор abarnert, источник
В Python 3 нет такой вещи, как несвязанный метод. Я уточню свой ответ, но ... это не так интересно.
добавлено автор abarnert, источник
В Python 3 нет такой вещи, как несвязанный метод. Я уточню свой ответ, но ... это не так интересно.
добавлено автор abarnert, источник
В Python 3 нет такой вещи, как несвязанный метод. Я уточню свой ответ, но ... это не так интересно.
добавлено автор abarnert, источник
Вы действительно имели в виду для Foo класс старинного стиля здесь?
добавлено автор abarnert, источник
Вы действительно имели в виду для Foo класс старинного стиля здесь?
добавлено автор abarnert, источник

3 ответы

У Python 3 нет несвязанных методов. Забудьте о classmethod s на мгновение и посмотрите на это:

>>> class Foo:
...     def baz(self): pass
>>> Foo.baz

In 2.x, this would be , but 3.x does not have unbound methods.

Если вы хотите получить функцию из связанного метода, это легко:

>>> foo = Foo()
>>> foo.baz
<__main__.Foo object at 0x104da6850>>
>>> foo.baz.__func__

Точно так же:

>>> class Foo:
...     @classmethod
...     def bar(cls): pass
>>> Foo.bar
>
>>> Foo.bar.__func__

В 2.x гораздо интереснее, потому что на самом деле есть несвязанные методы для получения. Обычно вы не видите метод unbound class , потому что все дело в том, что они привязаны к классу во время создания класса, вместо того, чтобы оставаться несвязанным и затем привязаны к каждому экземпляру при создании экземпляра.

Но действительно, несвязанный метод - это всего лишь instancemethod , чей im_self - None. Итак, как вы можете это сделать:

class Foo(object):
    def baz(self): pass

foo = Foo()
bound_baz = foo.baz
unbound_baz = new.instancemethod(bound_baz.im_func, None, bound_baz.im_class)

Обратите внимание, что bound_baz.im_func - это 2.x версия bound_baz .__ func __ в 3.x, но что new.instancemethod не имеет 3.x эквивалент.

В документации указано, что new устарел в пользу types , для совместимости 3.x, и на самом деле вы можете сделать это в 2.x:

unbound_baz = types.MethodType(bound_baz.im_func, None, bound_baz.im_class)

Но это не работает в 3.x, потому что MethodType не принимает параметр class и не позволяет его параметру instance None . И лично, когда я делаю что-то явно 2.x-only и не переношу на 3.x, я думаю, что использование new более ясное.

В любом случае, учитывая класс в 2.x, вы можете сделать это:

class Foo(object):
    @classmethod
    def bar(cls): pass

bound_bar = Foo.bar
unbound_bar = new.instancemethod(bound_bar.im_func, None, bound_bar.im_class)

Если вы распечатаете его, вы увидите:


Или, используя ваш пример, с классом старого стиля:

class Foo:
    @classmethod
    def bar(cls): pass


И да, может быть, это немного обман, что im_class класса метод для класса старого стиля classobj , хотя это не < code> Foo .__ class __ , но это кажется самым разумным способом заставить классы старого стиля и нового стиля работать одинаково во всех обычных случаях использования.

13
добавлено
@darkfeline: Ну, я уже написал ответ 2.x, и мне было проще написать ответ 3.x, в котором говорилось о том, что было уже там, а не переписывать его, и нужно сказать половину того же материала в слегка другой путь.
добавлено автор abarnert, источник
@darkfeline: Это не совсем так. Наиболее серьезно, то, что у вас есть (экземпляр builtins.classmethod ), не является методом и даже не может быть вызвано. Но есть более мелкие проблемы, например, тот факт, что это, вероятно, не работает с наследованием так, как вы ожидаете. Почему Foo.bar .__ func __ не то, что вы ищете?
добавлено автор abarnert, источник
Спасибо за Ваш ответ. Извините, если моя терминология запуталась. Под «несвязанным» я имел в виду «не связан». Разбежавшись, я наткнулся на это решение: Foo .__ dict __ ['bar']
добавлено автор darkfeline, источник
Я понимаю, о чем вы говорите. Foo .__ dict __ ['bar'] казалось, что он получает функцию напрямую, но после некоторого тестирования и чтения дескрипторов я вижу, что это не так. Спасибо за ваш ответ, хотя он немного длинный =)
добавлено автор darkfeline, источник

У Python 3 нет несвязанных методов. Забудьте о classmethod s на мгновение и посмотрите на это:

>>> class Foo:
...     def baz(self): pass
>>> Foo.baz

In 2.x, this would be , but 3.x does not have unbound methods.

Если вы хотите получить функцию из связанного метода, это легко:

>>> foo = Foo()
>>> foo.baz
<__main__.Foo object at 0x104da6850>>
>>> foo.baz.__func__

Точно так же:

>>> class Foo:
...     @classmethod
...     def bar(cls): pass
>>> Foo.bar
>
>>> Foo.bar.__func__

В 2.x гораздо интереснее, потому что на самом деле есть несвязанные методы для получения. Обычно вы не видите метод unbound class , потому что все дело в том, что они привязаны к классу во время создания класса, вместо того, чтобы оставаться несвязанным и затем привязаны к каждому экземпляру при создании экземпляра.

Но действительно, несвязанный метод - это всего лишь instancemethod , чей im_self - None. Итак, как вы можете это сделать:

class Foo(object):
    def baz(self): pass

foo = Foo()
bound_baz = foo.baz
unbound_baz = new.instancemethod(bound_baz.im_func, None, bound_baz.im_class)

Обратите внимание, что bound_baz.im_func - это 2.x версия bound_baz .__ func __ в 3.x, но что new.instancemethod не имеет 3.x эквивалент.

В документации указано, что new устарел в пользу types , для совместимости 3.x, и на самом деле вы можете сделать это в 2.x:

unbound_baz = types.MethodType(bound_baz.im_func, None, bound_baz.im_class)

Но это не работает в 3.x, потому что MethodType не принимает параметр class и не позволяет его параметру instance None . И лично, когда я делаю что-то явно 2.x-only и не переношу на 3.x, я думаю, что использование new более ясное.

В любом случае, учитывая класс в 2.x, вы можете сделать это:

class Foo(object):
    @classmethod
    def bar(cls): pass

bound_bar = Foo.bar
unbound_bar = new.instancemethod(bound_bar.im_func, None, bound_bar.im_class)

Если вы распечатаете его, вы увидите:


Или, используя ваш пример, с классом старого стиля:

class Foo:
    @classmethod
    def bar(cls): pass


И да, может быть, это немного обман, что im_class класса метод для класса старого стиля classobj , хотя это не < code> Foo .__ class __ , но это кажется самым разумным способом заставить классы старого стиля и нового стиля работать одинаково во всех обычных случаях использования.

13
добавлено
@darkfeline: Ну, я уже написал ответ 2.x, и мне было проще написать ответ 3.x, в котором говорилось о том, что было уже там, а не переписывать его, и нужно сказать половину того же материала в слегка другой путь.
добавлено автор abarnert, источник
@darkfeline: Это не совсем так. Наиболее серьезно, то, что у вас есть (экземпляр builtins.classmethod ), не является методом и даже не может быть вызвано. Но есть более мелкие проблемы, например, тот факт, что это, вероятно, не работает с наследованием так, как вы ожидаете. Почему Foo.bar .__ func __ не то, что вы ищете?
добавлено автор abarnert, источник
Спасибо за Ваш ответ. Извините, если моя терминология запуталась. Под «несвязанным» я имел в виду «не связан». Разбежавшись, я наткнулся на это решение: Foo .__ dict __ ['bar']
добавлено автор darkfeline, источник
Я понимаю, о чем вы говорите. Foo .__ dict __ ['bar'] казалось, что он получает функцию напрямую, но после некоторого тестирования и чтения дескрипторов я вижу, что это не так. Спасибо за ваш ответ, хотя он немного длинный =)
добавлено автор darkfeline, источник

У Python 3 нет несвязанных методов. Забудьте о classmethod s на мгновение и посмотрите на это:

>>> class Foo:
...     def baz(self): pass
>>> Foo.baz

In 2.x, this would be , but 3.x does not have unbound methods.

Если вы хотите получить функцию из связанного метода, это легко:

>>> foo = Foo()
>>> foo.baz
<__main__.Foo object at 0x104da6850>>
>>> foo.baz.__func__

Точно так же:

>>> class Foo:
...     @classmethod
...     def bar(cls): pass
>>> Foo.bar
>
>>> Foo.bar.__func__

В 2.x гораздо интереснее, потому что на самом деле есть несвязанные методы для получения. Обычно вы не видите метод unbound class , потому что все дело в том, что они привязаны к классу во время создания класса, вместо того, чтобы оставаться несвязанным и затем привязаны к каждому экземпляру при создании экземпляра.

Но действительно, несвязанный метод - это всего лишь instancemethod , чей im_self - None. Итак, как вы можете это сделать:

class Foo(object):
    def baz(self): pass

foo = Foo()
bound_baz = foo.baz
unbound_baz = new.instancemethod(bound_baz.im_func, None, bound_baz.im_class)

Обратите внимание, что bound_baz.im_func - это 2.x версия bound_baz .__ func __ в 3.x, но что new.instancemethod не имеет 3.x эквивалент.

В документации указано, что new устарел в пользу types , для совместимости 3.x, и на самом деле вы можете сделать это в 2.x:

unbound_baz = types.MethodType(bound_baz.im_func, None, bound_baz.im_class)

Но это не работает в 3.x, потому что MethodType не принимает параметр class и не позволяет его параметру instance None . И лично, когда я делаю что-то явно 2.x-only и не переношу на 3.x, я думаю, что использование new более ясное.

В любом случае, учитывая класс в 2.x, вы можете сделать это:

class Foo(object):
    @classmethod
    def bar(cls): pass

bound_bar = Foo.bar
unbound_bar = new.instancemethod(bound_bar.im_func, None, bound_bar.im_class)

Если вы распечатаете его, вы увидите:


Или, используя ваш пример, с классом старого стиля:

class Foo:
    @classmethod
    def bar(cls): pass


И да, может быть, это немного обман, что im_class класса метод для класса старого стиля classobj , хотя это не < code> Foo .__ class __ , но это кажется самым разумным способом заставить классы старого стиля и нового стиля работать одинаково во всех обычных случаях использования.

13
добавлено
@darkfeline: Ну, я уже написал ответ 2.x, и мне было проще написать ответ 3.x, в котором говорилось о том, что было уже там, а не переписывать его, и нужно сказать половину того же материала в слегка другой путь.
добавлено автор abarnert, источник
@darkfeline: Это не совсем так. Наиболее серьезно, то, что у вас есть (экземпляр builtins.classmethod ), не является методом и даже не может быть вызвано. Но есть более мелкие проблемы, например, тот факт, что это, вероятно, не работает с наследованием так, как вы ожидаете. Почему Foo.bar .__ func __ не то, что вы ищете?
добавлено автор abarnert, источник
Спасибо за Ваш ответ. Извините, если моя терминология запуталась. Под «несвязанным» я имел в виду «не связан». Разбежавшись, я наткнулся на это решение: Foo .__ dict __ ['bar']
добавлено автор darkfeline, источник
Я понимаю, о чем вы говорите. Foo .__ dict __ ['bar'] казалось, что он получает функцию напрямую, но после некоторого тестирования и чтения дескрипторов я вижу, что это не так. Спасибо за ваш ответ, хотя он немного длинный =)
добавлено автор darkfeline, источник
Python
Python
7 654 участник(ов)

Уютный чат для профессионалов, занимающихся поиском питоньих мудростей. Как не получить бан: https://t.me/ru_python/577926

Python beginners
Python beginners
4 449 участник(ов)

Вопросы про Python для чайников. Cпам и троллинг неприемлем. Не злоупотребляйте стикерами. Частозадаваемые вопросы: https://github.com/ru-python-beginners/faq/blob/master/README.md Статистика тут: https://grstats.me/chat/x4qym2k5uvfkr3al6at7

pro.python
pro.python
1 090 участник(ов)

Сообщество разработчиков под Python Создатель: @rodgelius

Rude Python
Rude Python
971 участник(ов)

Python без „девочек”, здесь матерятся и унижают Django. Not gay friendly. Правила: t.me/rudepython/114107 @rudepython | t.me/rudepython

rupython
rupython
509 участник(ов)

Группа создана с целью оперативного получения ответов на возникающие вопросы по разработке на яп python, смежные темы, а также человеческого общения. Приветствую!

Python-programming
Python-programming
266 участник(ов)

Чат группы вконтакте https://vk.com/python_community