Еще один удар по нему, от работы с обещаниями.
(Отказ от ответственности: JS noob, исходящий из мира Python. Даже там, currying не используется так много, но может прийти в удобном случае, поэтому я закрепил функцию currying - см. ссылки)
Во-первых, я начинаю с вызова ajax. У меня есть определенная обработка для успеха, но при отказе я просто хочу дать пользователю обратную связь, что вызов чего-то привел к некоторой ошибке . В моем фактическом коде я отображаю обратную связь с ошибками на панели начальной загрузки, но я просто использую запись здесь.
Я изменил свой живой URL-адрес, чтобы сделать это неудачным.
function ajax_batch(e){
var url = $(e.target).data("url");
//induce error
url = "x" + url;
var promise_details = $.ajax(
url,
{
headers: { Accept : "application/json" },
// accepts : "application/json",
beforeSend: function (request) {
if (!this.crossDomain) {
request.setRequestHeader("X-CSRFToken", csrf_token);
}
},
dataType : "json",
type : "POST"}
);
promise_details.then(notify_batch_success, fail_status_specific_to_batch);
}
Теперь, чтобы сообщить пользователю, что пакет завершился неудачно, мне нужно написать эту информацию в обработчике ошибок, потому что все, что он получает, является ответом от сервера.
У меня все еще есть информация доступна во время кодирования - в моем случае у меня есть несколько возможных партий, но я не знаю, какая из них была неудачной синтаксический анализ ответа сервера о неудавшемся URL-адресе.
function fail_status_specific_to_batch(d){
console.log("bad batch run, dude");
console.log("response.status:" + d.status);
}
Давайте сделаем это. Консольный выход:
console:
bad batch run, dude
utility.js (line 109)
response.status:404
Теперь, давайте немного изменим ситуацию и воспользуемся многократным обработчиком сбоев, но также и тот, который curried во время выполнения с использованием контекста вызова с известным в коде времени и информации о времени выполнения, доступной из события.
... rest is as before...
var target = $(e.target).text();
var context = {"user_msg": "bad batch run, dude. you were calling :" + target};
var contexted_fail_notification = curry(generic_fail, context);
promise_details.then(notify_batch_success, contexted_fail_notification);
}
function generic_fail(context, d){
console.log(context);
console.log("response.status:" + d.status);
}
function curry(fn) {
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function () {
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
};
}
console:
Object { user_msg="bad batch run, dude. you were calling :Run ACL now"}
utility.js (line 117)
response.status:404
utility.js (line 118)
В более общем плане, учитывая, насколько широкое использование обратного вызова в JS, каррирование кажется довольно полезным инструментом.
https: //javascriptweblog.wordpress .com / 2010/04/05 / curry-cooking-up-tastier-functions / http://www.drdobbs.com/open-source/currying-and-partial-functions-in- javasc / 231001821? PGNO = 2
В то время, когда x=10
выполняется в вашем примере, класс не существует, но класс тоже не существует.
Выполнение в Python идет сверху вниз. Если x=10
находится выше метода класса, вы не можете получить доступ к методу класса в этой точке, потому что он еще не определен.
Даже если вы можете запустить классный метод, это не будет потому что класс еще не существует, поэтому метод класса не мог ссылаться на него. Класс не создается до тех пор, пока не будет запущен весь блок класса, поэтому пока вы находитесь внутри блока класса, нет класса.
Если вы хотите разделить некоторую инициализацию класса, чтобы вы могли повторно запустить его позже, как вы описываете, используйте декоратор класса. Декоратор класса работает после создания класса, поэтому он может просто вызвать класс.
>>> def deco(cls):
... cls.initStuff()
... return cls
>>> @deco
... class Foo(object):
... x = 10
...
... @classmethod
... def initStuff(cls):
... cls.x = 88
>>> Foo.x
88
>>> Foo.x = 10
>>> Foo.x
10
>>> Foo.initStuff() # reinitialize
>>> Foo.x
88
Вы не можете вызывать classmethod
в определении class
, потому что класс еще не определен полностью, поэтому нет ничего, чтобы передать метод в качестве его первого аргумента cls
... классического цыпленка- и-яйца. Однако вы можете обойти это ограничение, перегрузив метод __new__()
в метаклассе и вызывая метод класса оттуда после создания класса, как показано ниже:
class Test(object):
# nested metaclass definition
class __metaclass__(type):
def __new__(mcl, classname, bases, classdict):
cls = type.__new__(mcl, classname, bases, classdict) # creates class
cls.static_init() # call the classmethod
return cls
x = None
@classmethod
def static_init(cls): # called by metaclass when class is defined
print("Hello")
cls.x = 10
print Test.x
Выход:
Hello
10
Вы вызываете метод класса, добавляя также имя класса:
class.method
. В вашем коде должно быть достаточно:
Test.static_init()
Вы также можете сделать это:
static_init(Test)
Чтобы вызвать его внутри вашего класса, выполните ваш код:
Test.static_init()
Мой рабочий код:
class Test(object):
@classmethod
def static_method(cls):
print("Hello")
def another_method(self):
Test.static_method()
и Test().another_method()
возвращает Hello
После повторного изучения вашего вопроса на этот раз я могу представить два решения. Первый - применить шаблон дизайна Borg. Второй способ - отбросить метод класса и вместо этого использовать функцию уровня модуля. Это, похоже, решает вашу проблему:
def _test_static_init(value):
return value, value * 2
class Test:
x, y = _test_static_init(20)
if __name__ == "__main__":
print Test.x, Test.y
Вот пример, я надеюсь, что это поможет:
class Test:
x = None
@classmethod
def set_x_class(cls, value):
Test.x = value
def set_x_self(self):
self.__class__.set_x_class(10)
if __name__ == "__main__":
obj = Test()
print Test.x
obj.set_x_self()
print Test.x
obj.__class__.set_x_class(15)
print Test.x
В любом случае, ответ NlightNFotis является лучшим: используйте имя класса при доступе к методам класса. Это делает ваш код менее неясным.