Из эмпирического тестирования кажется, что max()
и min()
в списке вернут первое в списке, которое соответствует max()
/ min()
в случае связи:
>>> test = [(1, "a"), (1, "b"), (2, "c"), (2, "d")]
>>> max(test, key=lambda x: x[0])
(2, 'c')
>>> test = [(1, "a"), (1, "b"), (2, "d"), (2, "c")]
>>> max(test, key=lambda x: x[0])
(2, 'd')
>>> min(test, key=lambda x: x[0])
(1, 'a')
>>> test = [(1, "b"), (1, "a"), (2, "d"), (2, "c")]
>>> min(test, key=lambda x: x[0])
(1, 'b')
И Отличное слежение Джереми подтверждает, что это действительно так.
Моя любимая странность на C - это 5["Hello World"], но так как это уже было размещено, моя следующая любимая странность - это Windows versioned-structure initialization hack:
void someWindowsFunction() {
BITMAPINFOHEADER header = {sizeof header};
/* do stuff with header */
}
Этот, тонкая линия выполняет следующее:
Не столько странная особенность, сколько действительно раздражающая с точки зрения типовой безопасности: ковариативность массива на C#.
class Foo { }
class Bar : Foo { }
class Baz : Foo { }
Foo[] foo = new Bar[1];
foo[0] = new Baz(); // Oh snap!
Полагаю, это было унаследовано (pun intentional) от Java.
.В JavaScript можно использовать двойное битовое отрицание (~~~n
) в качестве замены для Math.floor(n)
(если n
является положительным числом) или parseInt(n, 10)
(даже если n
является отрицательным числом). n|n
и n&n
всегда дают те же результаты, что и ~~n
.
var n = Math.PI;
n; // 3.141592653589793
Math.floor(n); // 3
parseInt(n, 10); // 3
~~n; // 3
n|n; // 3
n&n; // 3
// ~~n works as a replacement for parseInt() with negative numbers…
~~(-n); // -3
(-n)|(-n); // -3
(-n)&(-n); // -3
parseInt(-n, 10); // -3
// …although it doesn’t replace Math.floor() for negative numbers
Math.floor(-n); // -4
Однобитовое отрицание (~
) вычисляет -(parseInt(n, 10) + 1)
, таким образом, два битовых отрицания возвращают -(-(parseInt(n, 10) + 1) + 1)
.
Обновление: Вот тестовый пример jsPerf, сравнивающий производительность этих альтернатив.
.В рубине/питоне/c можно конкатенировать строки вот так:
a = "foo" "bar"
print a # => "foobar"
Я бы не осмелился утверждать, что XML - это язык программирования, но не близок ли он нашему сердцу? :-)
Самая странная особенность, на мой взгляд, в XML заключается в том, что это хорошо оформленный документ:
<_....>
</_....>
Вот лексическое определение NT-Name, которое допускает наличие последовательных точек.
.Некоторые ранние динамические языки (включая, если я правильно помню, ранние версии Perl) не поняли, что такое хорошая динамика, а что - плохая. Так что некоторые из них разрешили это:
1 = 2;
После этого утверждения было бы верно:
if(1 + 1 == 4)
В fortran (77, конечно, может быть и в 95), необъявленные переменные и аргументы, начиная с I
и заканчивая N
(группа "in"), будут INTEGER
, а все остальные необъявленные переменные и аргументы будут REAL
(source). Это, в сочетании с "белой пробельной опцией в некоторых случаях", привело к одной из самых известных ошибок.
Как сказал Фред Вебб в alt.folklore.computers
в 1990 году:
Я работал в НАСАЕ летом 1963 года. Группа, в которой я работал. занимался предварительной работой над компьютером Центра управления полетами. системы и программы. Мой приятель по работе с офисами занимался тестированием программа вычисления орбиты, которая использовалась во время Меркурия. перелёты. Проводя некоторые тестовые данные с известными ответами через него, он был получать ответы, которые были близки, но недостаточно точны. Итак, он начал искать числовые проблемы в алгоритме, проверяя, чтобы убедиться, что данные его тестов действительно верны и т.д.
Через пару недель без результатов он наткнулся на
DO
. заявление по форме:DO 10 I=1.10
Это утверждение интерпретировалось компилятором (правильно) как:
DO10I = 1.10
Программист явно имел в виду:
DO 10 I = 1, 10
После изменения
.
на,
результаты программы были корректны и составили желаемая точность. Очевидно, что ответы программы были "достаточно хорошо" для суборбитальных рейсов "Меркурий", так что никто не подозревал. жучок, пока они не попытались получить большую точность, в ожидании... поздние орбитальные и лунные полеты. Насколько я знаю, именно этот жучок... никогда не обвиняли в фактическом провале космического полета, но другие детали здесь кажутся достаточно близкими, что я уверен, что этот инцидент - Источник историиDO
.
Я думаю, что это большая WTF, если DO 10 I
принять за DO10I
, и что, в свою очередь, из-за неявных деклараций принимается за тип REAL
. И это отличная история.
На Java есть целая причудливая книга о них.
Python 2.x
>>>True = False
>>>True
False
Вы действительно можете заставить кого-то сойти с ума с помощью этого.
.В C
a[i++] = i;
Он компилирует, но редко делает то, что, по вашему мнению, должен делать. Изменение оптимизации приводит к дико разным результатам. И на разных платформах она работает по-разному.
Тем не менее, компилятор вполне доволен этим.
.В JavaScript:
alert(111111111111111111111) // alerts 111111111111111110000
Это сильно повредило некоторым 64-битным ключам, которые я передавал туда и обратно в JSON.
.В Форте все, что не содержит пробелов, может быть идентификатором (вещи, которые содержат пробелы, требуют немного работы). Сначала синтаксический анализатор проверяет, определена ли вещь, и в этом случае она называется словом , и если нет, то проверяет, является ли это числом. Ключевых слов нет.
Во всяком случае, это означает, что можно переопределить число, чтобы оно означало что-то другое:
: 0 1 ;
Что создает слово 0
, состоящее из 1
, что бы ни было , что было в момент его выполнения. В свою очередь, это может привести к следующему:
0 0 + .
2 Ok
С другой стороны, определение может взять на себя сам синтаксический анализатор - то, что сделано. комментарием слов . Это означает, что программа Форта на самом деле может стать программой на совершенно другом языке посередине. И, по сути, это и есть рекомендуемый способ программирования на Форте: сначала пишите на том языке, на котором хотите решить проблему, а затем решаете ее.
.Наследование от случайного класса в Ruby:
class RandomSubclass < [Array, Hash, String, Fixnum, Float, TrueClass].sample
...
end
(впервые увиденное в Скрытые черты Ruby)
В Python "compile time" (или время объявления) оценка аргументов функции может быть запутанной:
def append(v, l = []):
l.append(v)
return l
print append(1)
print append(2)
>>> [1]
>>> [1,2]
Намерением могло быть:
def append(v, l = None):
if l is None:
l = []
l.append(v)
return l
print append(1)
print append(2)
>>> [1]
>>> [2]
Это поведение полезно для таких вещей, как кэширование, но оно может быть опасным.
Бонусная функция: кортежи с изменяемым содержимым:
a = (1,2,[3])
a[2][:] = [4] # OK
a[2] = [2] # crashes
] В JavaScript [] неопределенная [
] является глобальной переменной, значением по умолчанию является примитивное значение [] неопределенное [
]. Вы можете изменить значение []undefined[
]:[
var a = {};
a.b === undefined; // true because property b is not set
undefined = 42;
a.b === undefined; // false
]
[] Из-за мутируемости [] undefined[
], как правило, лучше проверять неопределенность через []typeof[
]: [
var a = {};
typeof a.b == "undefined"; // always true
] ]Я всегда был большим поклонником ошибки PHP, возникавшей при использовании двух двоеточий подряд из контекста:[
] [] [] []Ошибка при разборе: синтаксическая ошибка, неожиданный T_PAAMAYIM_NEKUDOTAYIM в /path/to/file/error.php на строке 3[
] [
]В первый раз, когда я столкнулся с этим, я был абсолютно запутался.[
]. Меня застало врасплох, что можно изменить цепочку наследования класса в Perl, изменив его массив @ISA
@ISA .
package Employee;
our @ISA = qw(Person);
# somwhere far far away in a package long ago
@Employee::ISA = qw(Shape);
# Now all Employee objects no longer inherit from 'Person' but from 'Shape'
Мне нравится тот факт, что в JavaScript все в порядке:
var futureDate = new Date(2010,77,154);
alert(futureDate);
, и в результате получается дата 77 месяцев и 154 дня с 0-го числа 0-го месяца 2010 г., т.е. 1 ноября 2016 г.
Забавный побочный эффект от всего, что есть у Python - это действительно ссылка:
>>> a = [[1]] * 7
>>> a
[[1], [1], [1], [1], [1], [1], [1]]
>>> a[0][0] = 2
>>> a
[[2], [2], [2], [2], [2], [2], [2]]
МАМПЫ. Есть много функций WTF, я выбрал одну, оператор if
. (Обратите внимание, что ниже я использую довольно подробный стиль кодирования, чтобы учесть тех, кто не знает языка; настоящий код MUMPS обычно более непостижим для непосвященных.)
if x>10 do myTag(x) ; in MUMPS "tag" means procedure/function
else do otherTag(x)
Это похоже на высказывание в Java:
if (x > 10) {
myMethod(x);
} else {
otherMethod(x);
}
За исключением того, что в MUMPS оператор else
синтаксически не является частью блока if, это отдельный оператор, который работает, проверяя встроенную переменную $ TEST
. Каждый раз, когда вы выполняете оператор if
, он устанавливает $ TEST
равным результату оператора if
. Оператор else
фактически означает «выполнить оставшуюся часть строки, если $ TEST
ложно, в противном случае перейти к следующей строке».
Это означает, что если x
было больше 10 и, следовательно, первая строка с именем myTag
, а myTag
содержит операторы if
, то поведение else
зависит не от if
в строке над ним, а от последнего if
, вычисленного внутри myTag
! Из-за этой «особенности» кодировщиков MUMPS обычно учат писать приведенный выше код, чтобы быть в безопасности:
if x>10 do myTag(x) if 1
else do otherTag(x)
if 1
в конце первой строки гарантирует, что $ TEST
] установлен правильно, прежде чем управление перейдет к следующей строке. (Кстати, интервал здесь должен быть именно таким, с двумя пробелами после else
и одним пробелом во всех остальных местах. Интервал нечетный, но, по крайней мере, он очень ортогонален, если вы понимаете шаблон.)
Perl имеет оператор yada yada ( ...
).
Так называемый оператор «yada yada» наследия Perl 6 - это ярлык для обозначения нереализованного кода:
if ($condition) { ... }
то же самое, что
if ($condition) { die "not yet implemented" }
Моя любимая маленькая синтаксическая уловка C ++ заключается в том, что вы можете помещать URL (с некоторыми ограничениями) прямо в код:
int main( int argc, char *argv[] )
{
int i=10;
http://www.stackoverflow.com
return 1;
}
Это прекрасно компилируется.
Подсветка синтаксиса вроде как портит шутку, но все же весело.
Я добавил функцию "формат" в Lisp примерно в 1977 году, еще до того, как существовал «printf» (я копировал из того же источника, что и Unix: Multics). Это началось достаточно невинно, но постепенно добавляло новые функции. Ситуация вышла из-под контроля, когда Гай Стил ввел итерацию и связанные с ней функции, которые были приняты в стандарт Common Lisp X3J13 ANSI. Следующий пример можно найти в Таблице 22-8 в разделе 22.3.3 Common Lisp the Language, 2nd Edition :
(defun print-xapping (xapping stream depth)
(declare (ignore depth))
(format stream
"~:[{~;[~]~:{~S~:[->~S~;~*~]~:^ ~}~:[~; ~]~ ~{~S->~^ ~}~:[~; ~]~[~*~;->~S~;->~*~]~:[}~;]~]"
(xectorp xapping)
(do ((vp (xectorp xapping))
(sp (finite-part-is-xetp xapping))
(d (xapping-domain xapping) (cdr d))
(r (xapping-range xapping) (cdr r))
(z '() (cons (list (if vp (car r) (car d)) (or vp sp) (car r)) z)))
((null d) (reverse z)))
(and (xapping-domain xapping)
(or (xapping-exceptions xapping)
(xapping-infinite xapping)))
(xapping-exceptions xapping)
(and (xapping-exceptions xapping)
(xapping-infinite xapping))
(ecase (xapping-infinite xapping)
((nil) 0)
(:constant 1)
(:universal 2))
(xapping-default xapping)
(xectorp xapping)))
В Scala нет операторов, только методы. Так что a + b - c
на самом деле то же самое, что a.+(b).-(c)
. В этом она равна Smalltalk. Однако, в отличие от Smalltalk, учитывается приоритет. Правила основаны на первом символе, поэтому гипотетический метод, называемый *+
, будет иметь приоритет над методом, называемым +*
. Исключение сделано таким образом, что любой метод, заканчивающийся на =
, будет иметь тот же самый приоритет, что и ==
-- имея в виду !
и !=
(не гипотетические методы) имеют разный приоритет.
Все буквы ASCII имеют наименьший приоритет, но все не-ASCII (уникодовые) символы имеют наибольший приоритет. Поэтому, если написать метод is
, сравнивающий два дюйма, то 2 + 2 равно 1 + 3
будет скомпилирован и верен. Если бы Вы написали его на португальском языке, é
, то 2 + 2 é 1 + 3
привело бы к ошибке, так как было бы видно, что 2 + (2 é 1) + 3
.
И, просто чтобы пополнить WTF операторов в Scala, все методы, заканчивающиеся на :
, являются право-ассоциативными, а не лево-ассоциативными. Это означает, что 1 ::: 2 :: Ноль
эквивалентно Ноль::(2):(1)
вместо 1.::(2):(Ноль)
.
Возможно, это уже было сказано (и, возможно, некоторым это не так уж и странно), но я подумал, что это довольно круто:
В Javascript объявление параметров, которые принимает функция, - это только удобство для программиста. Все переменные, передаваемые при вызове функции, доступны по ключевому слову "аргументы". Таким образом, "мир" будет предупрежден:
<script type="text/javascript">
function blah(){
alert(arguments[1]);
}
blah("hello", "world");
</script>
Обратите внимание, что хотя может показаться, что эти аргументы хранятся в массиве (так как доступ к свойствам объекта можно получить точно так же, как и к элементам массива), это не так. Аргументы arguments
являются Объектом, - не - Массивом (таким образом, это свойства Объекта, хранящиеся с числовыми индексами), как показано в следующем примере (функция typeOf, взятая из Crockford's remedial JavaScript page):
argumentsExample = function(){
console.log(typeOf(arguments));
anArray = [];
console.log(typeOf(anArray));
anObject = {};
console.log(typeOf(anObject));
}
function typeOf(value) {
var s = typeof value;
if (s === 'object') {
if (value) {
if (typeof value.length === 'number' &&
!(value.propertyIsEnumerable('length')) &&
typeof value.splice === 'function') {
s = 'array';
}
} else {
s = 'null';
}
}
return s;
}
argumentsExample("a", "b");
В C оператор sizeof
не оценивает свой аргумент. Это позволяет написать код, который выглядит неправильно, но является корректным. Например, идиоматическим способом вызова malloc()
, при типе T
является:
#include <stdlib.h>
T *data = NULL;
data = malloc(sizeof *data);
Здесь *данные
не вычисляются, когда в операторе sizeof
(data
is NULL
, то есть, если бы они вычислялись, то произошло бы Плохо! ).
Это позволяет писать удивительный код, во всяком случае, новичкам. Обратите внимание, что никто в здравом уме на самом деле не стал бы этого делать:
#include <stdio.h>
int main()
{
int x = 1;
size_t sz = sizeof(x++);
printf("%d\n", x);
return 0;
}
Это печатает 1
, а не 2
, потому что x
никогда не увеличивается.
Для некоторых реальных веселья/путаницы с размером
:
#include <stdio.h>
int main(void)
{
char a[] = "Hello";
size_t s1 = sizeof a;
size_t s2 = sizeof ("Hi", a);
printf("%zu %zu\n", s1, s2);
return 0;
}
(Путаница возникает только в том случае, если путать массивы, указатели и операторы)
.Функция Common Lisp's format
имеет возможность печатать числа в виде римских цифр.
В INTERCAL'е это единственная форма вывода.
В FoxPro, если я правильно помню, каждая команда может быть сокращена до 4 символов, а все остальное игнорируется, поэтому READ, READY, READINESS все равно - что бы ни было после первых 4 символов, оно игнорируется. Парню, который мне это объяснил, понравилась эта функция, но мне она показалась жуткой
.