Python: взломать вызов метода для объекта, который не принадлежит к его классу - PullRequest
1 голос
/ 06 мая 2010

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

class A(object):
    def my_method(self):
        # Some complicated processing is done here
        return self

И теперь вы хотите полностью использовать этот метод для какого-либо объекта из другого класса. Мол, хочешь сделать A.my_method(7).

Вот что вы получите: TypeError: unbound method my_method() must be called with A instance as first argument (got int instance instead).

Теперь, есть ли возможность взломать что-нибудь, чтобы вы могли вызвать этот метод на 7? Я хотел бы избежать перемещения функции или переписывания ее. (Обратите внимание, что логика метода зависит от self.)

Одно примечание: я знаю, что некоторые люди захотят сказать: «Вы делаете это неправильно! Вы злоупотребляете Python! Вы не должны этого делать!» Так что да, я знаю, это ужасно, ужасно, что я хочу сделать. Я спрашиваю, знает ли кто-нибудь, как это сделать, а не как мне проповедовать, что я не должен этого делать.

Ответы [ 8 ]

6 голосов
/ 06 мая 2010

Конечно, я бы не рекомендовал делать это в реальном коде, но да, конечно, вы можете обращаться к классам и использовать их методы как функции:

class A(object):
    def my_method(self):
        # Some complicated processing is done here
        return 'Hi'

print(A.__dict__['my_method'](7))
# Hi
2 голосов
/ 06 мая 2010
def some_method(self):
    # Some complicated processing is done here
    return self

class A(object):
    my_method = some_method
a = A()

print some_method
print a.my_method
print A.my_method
print A.my_method.im_func
print A.__dict__['my_method']

печать:

<function some_method at 0x719f0>
<bound method A.some_method of <__main__.A object at 0x757b0>>
<unbound method A.some_method>
<function some_method at 0x719f0>
<function some_method at 0x719f0>

Звучит так, будто вы ищете метод в классе и получаете unbound method. unbound method ожидает объект соответствующего типа в качестве первого аргумента.

Если вы хотите применить функцию как функцию, вам нужно получить указатель на версию функции вместо нее.

2 голосов
/ 06 мая 2010

Вы не можете. На самом деле ограничение было снято в Python 3000, но я предполагаю, что вы не используете это.

Однако, почему вы не можете сделать что-то вроде:

def method_implementation(self, x,y):
   # do whatever

class A():
   def method(self, x, y):
        return method_implementation(self, x, y)

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

class Hack:
   def __init__(self, fn):
       self.fn = fn
   def __get__(self, obj, cls):
       if obj is None: # called staticly
            return self.fn
       else:
            def inner(*args, **kwargs):
                 return self.fn(obj, *args, **kwargs)
            return inner

Обратите внимание, что это полностью не проверено, вероятно, сломает некоторые угловые случаи, и все вокруг зло.

0 голосов
/ 06 мая 2010

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

def my_function(object):
    # Some complicated processing is done here
    return object

my_function(7)
my_function("Seven")

Пока ваша обработка использует методы и атрибуты, доступные для всех объектов, которые вы передаете в my_function через магиюиз утка, набрав все будет хорошо.

0 голосов
/ 06 мая 2010

Почему вы не можете сделать это

class A(object):
    def my_method(self,arg=None):
        if (arg!=None):
           #Do Some Complicated Processing with both objects and return something 
        else:
               # Some complicated processing is done here
        return self
0 голосов
/ 06 мая 2010
>>> class A():
...     me = 'i am A'
... 
>>> class B():
...     me = 'i am B'
... 
>>> def get_name(self):
...     print self.me
... 
>>> A.name = get_name
>>> a=A()
>>> a.name()
i am A
>>> 
>>> B.name = get_name
>>> b=B()
>>> b.name()
i am B
>>> 
0 голосов
/ 06 мая 2010

Вы могли бы просто поместить этот метод в суперкласс двух объектов, которые должны вызывать его, не так ли? Если это настолько критично, что вы не можете скопировать его, и вы не можете изменить его, чтобы не использовать self, это единственный другой вариант, который я вижу.

0 голосов
/ 06 мая 2010

Вот что называется staticmethod:

class A(object):
    @staticmethod
    def my_method(a, b, c):
        return a, b, c

Однако в статических методах вы не получите ссылку на self.

Если вам нужна ссылка на class, а не instance (экземпляр подразумевает ссылку на self), вы можете использовать метод класса:

class A(object):
    classvar = "var"

    @classmethod
    def my_method(cls, a, b, c):
        print cls.classvar
        return a, b, c

Но вы получите доступ только к переменным класса, а не к переменным экземпляра (которые обычно создаются / определяются внутри конструктора __init__).

Если этого недостаточно, вам нужно каким-то образом передать «связанный» метод или передать «я» в метод следующим образом:

class A(object):
    def my_method(self):
        # use self and manipulate the object

inst = A()
A.my_method(inst)

Как уже говорили некоторые люди, неплохо просто наследовать один класс от другого:

class A(object):
    ... methods ...

class B(A):
    def my_method(self):
        ... use self

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