Как делает присвоение функции, поскольку атрибут класса становится методом в Python?

>>> class A(object): pass
>>> def func(cls): pass
>>> A.func = func
>>> A.func
<unbound method A.func>

Как это присвоение создает метод? Это кажется неинтуитивным, что присвоение делает следующее для классов:

  • Превратите функции в несвязанные методы экземпляра
  • Функции поворота, перенесенные в classmethod() в методы класса (на самом деле, это довольно интуитивно),
  • Функции поворота, перенесенные в staticmethod() в функции

Кажется, что для первого, должно быть instancemethod(), и для последнего, не должно быть функции обертки вообще. Я понимаю, что это для использования в a class блок, но почему они должны применяться за пределами него?

Но что еще более важно, как точно делает присвоение функции в работу класса? Какое волшебство происходит, который разрешает те 3 вещи?

Еще более сбивающий с толку с этим:

>>> A.func
<unbound method A.func>
>>> A.__dict__['func']
<function func at 0x...>

Но я думаю, что это - что-то, чтобы сделать с дескрипторами при получении атрибутов. Я не думаю, что это имеет непосредственное отношение к установке атрибутов здесь.

10
задан JasonMArcher 23 May 2015 в 21:23
поделиться

5 ответов

Вы правы, что это имеет отношение к протоколу дескрипторов. Дескрипторы - это то, как в Python реализована передача объекта-приемника в качестве первого параметра метода. Более подробно о поиске атрибутов в Python вы можете прочитать здесь. Ниже показано на более низком уровне, что происходит, когда вы делаете A.func = func; A.func:

# A.func = func
A.__dict__['func'] = func # This just sets the attribute
# A.func
#   The __getattribute__ method of a type object calls the __get__ method with
#   None as the first parameter and the type as the second.
A.__dict__['func'].__get__(None, A) # The __get__ method of a function object
                                    # returns an unbound method object if the
                                    # first parameter is None.
a = A()
# a.func()
#   The __getattribute__ method of object finds an attribute on the type object
#   and calls the __get__ method of it with the instance as its first parameter.
a.__class__.__dict__['func'].__get__(a, a.__class__)
#   This returns a bound method object that is actually just a proxy for
#   inserting the object as the first parameter to the function call.

Таким образом, именно поиск функции в классе или экземпляре превращает ее в метод, а не присвоение ее атрибуту класса.

classmethod и staticmethod - это просто немного разные дескрипторы, classmethod возвращает связанный объект метода, привязанный к объекту типа, а staticmethod просто возвращает исходную функцию.

4
ответ дан 4 December 2019 в 01:00
поделиться

Пункт 1: Функция func, которую вы определили, существует как объект первого класса в Python.

Пункт 2: Классы в Python хранят свои атрибуты в __dict__.

Что же происходит, когда вы передаете функцию в качестве значения атрибута класса в Python? Эта функция хранится в __dict__ класса, что делает ее методом класса, доступ к которому осуществляется вызовом имени атрибута, которому вы ее присвоили.

0
ответ дан 4 December 2019 в 01:00
поделиться

Нужно учитывать, что в Python все является объектом. Установив это, легче понять, что происходит. Если у вас есть функция def foo(bar): print bar, вы можете сделать spam = foo и вызвать spam(1), получив, конечно, 1.

Объекты в Python хранят свои атрибуты экземпляра в словаре под названием __dict__ с "указателем" на другие объекты. Поскольку функции в Python также являются объектами, их можно присваивать и манипулировать ими как простыми переменными, передавать другим функциям и т. д. Реализация объектной ориентации в Python использует это преимущество и рассматривает методы как атрибуты, как функции, которые находятся в __dict__ объекта.

Первым параметром методов экземпляра всегда является сам объект экземпляра, обычно называемый self (но он может называться this или banana). Когда метод вызывается непосредственно на классе, он не связан ни с каким экземпляром, поэтому в качестве первого параметра вы должны передать ему объект экземпляра (A.func(A())). Когда вы вызываете связанную функцию (A().func()), первый параметр метода, self, является неявным, но за шторами Python делает точно так же, как и при прямом вызове несвязанной функции и передаче объекта экземпляра в качестве первого параметра.

Если это понятно, то тот факт, что присваивание A.func = func (которое за занавесками делает A.__dict__["func"] = func) оставляет вас с несвязанным методом, неудивителен.

В вашем примере cls в def func(cls): pass на самом деле будет передан экземпляр (self) типа A. При применении classmethod или staticmethod декораторы делают не что иное, как берут первый аргумент, полученный при вызове функции/метода, и преобразуют его во что-то другое перед вызовом функции.

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

3
ответ дан 4 December 2019 в 01:00
поделиться

Невозможно «подделать» HTTP-запросы. Вы отправляете запрос на сервер, и сервер отвечает соответствующим образом.

Я думаю, что вы пытаетесь предотвратить это спуфинг печенья. Учитывая, что файлы cookie хранятся на стороне клиента, вы ничего не можете сделать, чтобы запретить пользователям изменять их содержимое.

Не храните конфиденциальную информацию в файлах cookie. Они не защищены и легко читаются и изменяются клиентом.

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

По существу, защита сеансов выполняется на двух фронтах:

  • Предотвращение фиксации сеанса
    Регенерация нового session _ id каждые X запросов, чтобы уменьшить время, в течение которого злоумышленник должен украсть идентификатор.

  • Уникальная идентификация клиента
    Использование IP и/или агента пользователя для Это действительно единственный два выборе, которые вы должны однозначно определить клиента.

Даже с тем, что на месте, ни одно решение не является дурацким, и как только ваш session _ id скомпрометирован, вы в значительной степени сделали для.

Для более подробного объяснения см. мой предыдущий ответ .

-121--4779931-

(NB, я даю вам два отдельных ответа. Этот вопрос стоит как можно ближе к вашему вопросу.)

Ваш вопрос говорит

while{ count >= mAllPositions.Count )
{
    //Run my code here
}

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

while( count < mAllPositions.Count )
   ; // do nothing -- busy wait until the count has been incremented enough
// Now run my code here

??

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

Semaphore TheSemaphore = new Semaphore( 0, mAllPositions.Count );

По мере завершения каждого асинхронного вызова, освободить семафор.

TheSemaphore.Release();

Перед выполнением окончательного кода убедитесь, что семафор был освобожден необходимое количество раз:

 for( int i=0; i<mAllPositions.Count; i++ )
    TheSemaphore.WaitOne();
 // Now run follow-on code.

Ваш код будет заблокирован до завершения всех асинхронных операций.

-121--4518350-

Дескрипторы - это магические 1 , которые превращают обычную функцию в связанный или несвязанный метод при извлечении ее из экземпляра или класса, поскольку все они являются просто функциями, которые нуждаются в различных стратегиях связывания. Декораторы classmethod и staticmethod реализуют другие стратегии связывания, и staticmethod фактически просто возвращает сырую функцию, которая является тем же поведением, которое вы получаете от объекта, не являющегося функцией вызываемого .

Для получения дополнительной информации см. «Пользовательские методы» , но обратите внимание на следующее:

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

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

Вот статический метод декоратора в действии,возврат базовой функции при обращении к ней.

>>> @staticmethod
... def f(): pass
>>> class A(object): pass
>>> A.f = f
>>> A.f
<function f at 0x100479398>
>>> f
<staticmethod object at 0x100492750>

Если обычный объект с методом __ call __ не преобразуется:

>>> class C(object):
...         def __call__(self): pass
>>> c = C() 
>>> A.c = c 
>>> A.c
<__main__.C object at 0x10048b890>
>>> c
<__main__.C object at 0x10048b890>

1 Специфическая функция func _ descr _ get в Objects/funcobject.c .

4
ответ дан 4 December 2019 в 01:00
поделиться

Относительно комментария MTsoul к ответу Gabriel Hurley:

Разница в том, что func имеет метод __call__(), что делает его "вызываемым", т.е. к нему можно применить оператор (). Посмотрите документацию Python (поиск по __call__ на этой странице).

0
ответ дан 4 December 2019 в 01:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: