Bluetooth в Mac OS из Python

Я тут учусь работать с Блютузом из Пайтона на «Маке», пока сделал сканирование всех видимых в эфире устройств:
import objc
import time
from Foundation import NSDate, NSDefaultRunLoopMode
from AppKit import NSApplication, NSAnyEventMask

objc.loadBundle('IOBluetooth', globals(), bundle_path=u'/System/Library/Frameworks/IOBluetooth.framework')

class DeviceInquiry(NSObject): 
    def init(self):
        self = super(DeviceInquiry, self).init()
        self._inquiry = IOBluetoothDeviceInquiry.inquiryWithDelegate_(self)    
        self._stop = False
        
        return self
        
    def getfounddevices(self):
        self._inquiry.start()

        app = NSApplication.sharedApplication()
        app.setActivationPolicy_(2)        
        while not self._stop:
            time.sleep(.01)
            app.nextEventMatchingMask_untilDate_inMode_dequeue_(NSAnyEventMask,\
            NSDate.dateWithTimeIntervalSinceNow_(1), NSDefaultRunLoopMode, True)

        return tuple((dev.getName(), dev.getAddressString()) for dev in self._inquiry.foundDevices())

    @objc.typedSelector("v@:@@")
    def deviceInquiryDeviceFound_device_(self, inquiry, device):
        self._stop = True 

    @objc.typedSelector("v@:@iB")
    def deviceInquiryComplete_error_aborted_(self, inquiry, err, aborted):
        self._stop = True

print DeviceInquiry.new().getfounddevices()
Модуль pyobjc (в маковском Пайтоне он уже есть) — это мост между Пайтоном и Обжектив-Си, т.е. в реальности вызывается «кокосовое» АПИ «Мака».

Последняя строчка — пример использования, выдаётся список списков, состоящих из двух элементов — имени устройства и его «адреса» (это шесть шестнадцатеричных чисел, разделённые минусом).
Комментировать
15 марта 2013 19:12

Магические методы

Что мне никогда не нравилось в Пайтоне, так это «магические» методы и свойства. Сейчас их существует за сотню:
bolk@Bolk ~  $ wget -O- http://docs.python.org/reference/datamodel.html 2>&- | egrep -o '__(\w+)__' | sort -u | wc -l
     108
Я, даже если очень постараюсь, вряд ли вспомню хотя бы половину. Всё «магическое» в Пайтоне начинается и заканчивается двумя подчёркиваниями, например, если сменить знак у объекта (сделать „-something“), то Пайтон попытается вызвать магический метод «__neg__». В более распространнённом ПХП всё примерно так же, но «магических» методов сильно меньше, их я уже помню на память все, но и возможности гораздо уже.

Запомнить все эти методы, наверное, реально при помощи тщательной зубрёжки, но сделать это естетственно, во время изучения языка, нереально, по моему мнению. Причина — неинтуитивность. Я давно высказывался на тему, почему хотя бы не расширить синтаксис и некоторые методы не разрешить называть как операции, то есть «/», «+», «[]» и так далее, смутно вспоминая, что в Си++, кажется, так и сделано.

Оказывается, так в точности сделано в языке «Скала»:
trait Ord{
    def < (that:Any):Boolean
    def<=(that:Any):Boolean = (this < that) || (this == that)
    def> (that:Any):Boolean = !(this <= that)
    def>=(that:Any):Boolean = !(this < that)
}
Это гораздо проще выучить, изучая язык, чем «__lt__», «__le__», «__gt__», «__ge__» (впрочем, когда перечисляешь в ряд несколько конструкций, кажется что ничего страшного в этом нет, но надо держать в голове, что их больше сотни).

У некоторых методов название упрощать не нужно, например «__unicode__» (преобразование к юникодной строке) всё равно дёргается стоит вызвать unicode(something) или «__del__» (деструктор) вызывается, в частности, если сделать «del something» (если ссылок больше нет). Они уже содержат название операции, просто оно буквенное. Есть методы, которые вряд ли вообще можно как-то проще назвать, например «__new__» и «__init__» — названия конструкторов для «новых» и «старых» объектов Пайтона.

Наверняка есть часть, которую понятнее не назовёшь. На ум сразу приходит метод «__hash__», думаю есть и ещё.

Но, бо́льшую часть, мне бы хотелось именовать как-то понятнее. Причём, вполне можно предложить синтаксис для левостоящих и правостоящих объектов, что-то вроде «def self+» и «def +self».
16 комментариев
12 марта 2012 07:16

Банкоматы «Ак Барс Банка»

У меня зарплатная карточка «Ак Барс Банка», он вряд ли известен за пределами нашей республики, но в Татарстане широко распространён. Этот банк входит в организацию «Объединённая расчётная система», в которую входят ещё несколько банков, в банкоматах которых карты «Ак Барса» обслуживаются на льготных условиях.

Список банков-участников есть на сайте, но там их много, а банкоматы в нашем городе установлены далеко не у всех. Чтобы смотреть какие банкоматы «ОРСа» есть в Казани, я написал простую консольную программу на «Пайтоне», может кому-то ещё пригодится.
# coding: utf-8

import urllib
import re
import sys
import codecs
from itertools import ifilter

# Чтобы при перенаправлении в файл была кодировка UTF-8
sys.stdin = codecs.getreader('utf-8')(sys.stdin)
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)

# Конфигурация
ORS_URL    = 'http://ors.ru/cashpoints/print.asp'
ORS_CITY   = u'Казань'
ORS_REGION = u'Республика Татарстан'

# Данные для оправления через POST
postdata = urllib.urlencode({
    'CITY': ORS_CITY.encode('cp1251'),
    'REGION': ORS_REGION.encode('cp1251'),
    'CURRENCY': 'RUR',
    'OPERATION': 'cash-out',
})

content = urllib.urlopen(ORS_URL, postdata).read().decode('cp1251')

# Ищем все ячейки таблицы и выбираем каждую вторую из шести
tds = re.finditer('<td[^>]*>(.+?)</td>', content, re.S | re.I)
tds = ifilter(lambda x: x[0] % 6 == 1, enumerate(tds))

# Берём только уникальные значения и рубим лишние символы   
for x in set(x[1].group(1) for x in tds):
    print(x.replace('&nbsp;', ' '))
Выводится список банков (регион и город задаётся в коде в очевидном месте), например, на настоящий момент список выглядит вот так:
ОАО Банк ЗЕНИТ 
ОАО "РГС Банк" 
АКБ "Абсолют Банк" (ЗАО) 
Быстробанк ОАО 
ОАО "АК БАРС" БАНК 
АКБ "РОСБАНК" (ОАО) 
НОМОС-БАНК (ОАО) 
АКБ МБРР (ОАО) 
ЗАО АИБ "Ипотека-Инвест" 
ОАО "АИКБ "Татфондбанк" 
АКБ "БТА-Казань" (ОАО) 
КБ "Юниаструм Банк" (ООО) 
ОАО АКБ «Авангард» 
ОАО КБ "Восточный" 
2 комментария
22 февраля 2012 08:50

ChinesePython

А вы знали, что существует ChinesePython? Выглядит как настоящий, но не радует.

Язык полностью переведён на китайский, включая ключевые слова, встроенные типы и так далее, код основан на Пайтоне 2.1.3. Вот пример того как смотрится программа на этом языке:
載入 系統
文件名 = 系統.參數[1:]

定義 修正行尾(文件):
    內文 = 打開(文件名).讀入()
    內文 = 內文.替換('\n\r','\n')
    傳回 內文

取 文件 自 文件名:
    寫 修正行尾(文件)
«載入 系統» — это «import sys». Эта же программа на традиционном Пайтоне выглядит вот так:
import sys
filenames = sys.argv[1:]

def fixline(filename):
    text = open(filename).read()
    text = text.replace('\n\r','\n')
    return text

for file in filenames:
    print fixline(file)
Основная цель создания интерпретатора на китайском, по словам автора — популяризация программирования. Начинающий китайский программист, вместо того, чтобы учить недоанглийский, который всё равно не позволит ему говорить на этом языке, но позволит понимать слова Пайтона и называть переменные на корявеньком английском, может сосредоточиться на концепциях, алгоритмах и тому подобном.
22 комментария
29 января 2012 08:37

Ерунда на itertools и генераторах

Я люблю itertools и генераторы в Пайтоне, но как-то по работе пока не удаётся их применить, поэтому, чтобы не завять, приходится время от времени писать всякую ерунду.

Прочитал тут на «Хабре», что дробь 1/998001 даёт последовательность из чисел от нуля до 997. Вот я и написал код с использованием генераторов и itertools, который берёт эту дробь и выводит из неё все числа последовательно, пока не попадутся числа с разницей не равной единице.
from decimal import Decimal, getcontext
from itertools import groupby, islice, izip, takewhile, chain, imap

getcontext().prec = 3000

n = (
    groupby(
        enumerate(
            islice(str(1 / Decimal(998001)), 2, None)
        ),
        lambda n: n[0] // 3)
    )

n = (int(''.join(n[1] for n in n[1])) for n in n)

n = chain(*takewhile(lambda n: n[1] - n[0] == 1, izip(n, n)))

print ', '.join(imap(str, n))
Кстати, для вычисления дроби с точностью до трёхтысячного знака, используется модуль decimal.

Подумалось, что многим, наверное, было интересно сравнить как выглядит эквивалентный код на Пайтоне без всех этих страшных (на взгляд большинства) ленивых выражений. А то некоторые ребята по моей вине уже думают, что Пайтон какой-то адский язык. Ничего подобного. Вот, посмотрите, более традиционное решение:
from decimal import Decimal, getcontext

getcontext().prec = 3000

number, prev, out = str(1 / Decimal(998001)), -1, []

for i in xrange(2, len(number), 3):
    curr = int(number[i:i+3])

    if curr - prev != 1: break

    prev = curr
    out.append(str(curr))

print ', '.join(out)
17 комментариев
28 января 2012 16:14

Стеганография и пробел нулевой длины

Болею, не спится мне. Вспомнил старую свою идею.

В Юникоде есть такой символ замечательный — пробел нулевой длины (код 0x200B), на печать не выводится, понимается всеми современными браузерами и большинством редакторов. Интервала между буквами, как следует из названия, не даёт.

Идея простая, позволяет прятать в текст другой текст, так, чтобы первый не менялся, а второй всегда копировался вместе с первым. Основная мысль — пользуясь буквами исходного текста, как разделителем, ставим между ними столько пробелов нулевой длины, чтобы их число равнялось коду скрываемого символа.

Например. Дан текст: «Болк», в нём надо скрыть короткий текст: «yes». Я взял английские символы, чтобы не заморачиватсья с кодировкой.

Коды символов «yes» — 121, 101, 115. Значит текст приобретает следующий вид:

[121 символ пробела нулевой длины]Б[101 символ пробела нулевой длины]о[115 символов пробела нулевой длины]лк

Можно, кстати, вычитать из кода символа 31, если мы не планируем использовать символы перевода строки и табуляции в скрываемом тексте. Небольшой код на Пайтоне, приведённый ниже, иллюстрирует идею.
​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​#​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​E​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​x​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​a​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​m​p​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​l​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​e​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​b​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​y​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ ​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​E​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​v​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​g​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​e​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​n​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​y Stepanischev
from itertools import groupby, izip_longest
import sys
import codecs

sys.stdin = codecs.getreader('utf-8')(sys.stdin)
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)

toenc = 'Evgeny Stepanischev'
input = sys.stdin.read()

def decode(input):
    return ''.join(chr(31+len(list(x[1])))
            for x in groupby(input, lambda x: x == u"\u200b") if x[0])

def encode(input):
    if len(input) < len(toenc):
        raise ValueError()

    return ''.join(x[0] + x[1]
            for x in izip_longest((u"\u200b" * (ord(x)-31)
            for x in toenc), input, fillvalue=''))


print(encode(input) if input.find(u"\u200b") == -1 else decode(input))
Если на вход ему подать текст без пробелов нулевой длины, он добавит в него скрытый текст, иначе попытается его оттуда извлечь.

В принципе, этот подход можно применять в вебе для маркировки своих текстов — браузеры, кроме вымирающих, нормально относятся к этому символу и отображают его адекватно.

Конечно, важна длина текста — таким способом не скрыть текст, длина которого много больше исходной, но способ можно и улучшить в этом смысле. Например, в качестве прерывающего символа выбрать что-то другое, что не выводится на экран как символ. Например, управляющий символ смены направления текста или что-то в этом роде.
14 комментариев
23 января 2012 01:11

Кодировка rot13 в Пайтоне

В стандартном интерпретаторе Пайтона есть много такого, что иначе как «пасхальным яйцом» не назовёшь. Например, можно попробовать импортировать модули «__hello__», «this» или сделать «from __future__ import braces» (попробуйте), но следующее просто гениально, хотя, видимо, получилось случайно.

В файле программы на Пайтоне в специальном коментарии принято указывать кодировку файла. В случае с латиницей работает и без этого, если применяется UTF-8, то это делать обязательно. Интерпретатор поддерживает множество кодировок (честно сказать, я не знаю сколько именно) и одна из них — rot13. Используются те же самые кодировки, что и в методах encode и decode у строки. Я думаю после считывания файла программы именно они и вызываются.

Вот вполне валидная программа, которая выполняется и делает нечто осмысленное:
# coding: rot13

vzcbeg __uryyb__
cevag "Zl anzr vf Ritral Fgrcnavfpuri nxn Obyx!".rapbqr("rot13")
Кодируется только текст программы, поэтому-то мне и пришлось «rot13» написать как есть.
8 комментариев
21 июля 2011 10:34

Сравнение объектов встроенных типов в Пайтоне

Некоторым ребятам показалось, что в заметке про «goatse operator» в Перле я поругал этот язык. Это не так, можно прочитать заметку от и до, чтобы в этом убедиться. Мне очень нравится Перл, но это язык не для современного продакшна. Давайте я что-нибудь забавное расскажу и о языке, на котором больше всего сейчас программирую — про Пайтон.

В Пайтоне всё что только можно — объект и нет примитивных типов. С объектами можно делать всё что хочется — сравнивать, умножать, производить битовые операции. Чтобы программист мог указать как объекту следует себя вести рядом с каким-то оператором, следует определить некоторые «магические» методы, например, «__cmp__», «__mul__» и какой-нибудь «__xor__».

Где-то внутри какие-то «магические» методы определены и для встроенных типов (которые тоже являются объектами, напоминаю), ведь надо же как-то сравнивать две строки или строку и число:
In [26]: "Это строка".__eq__
Out[26]: <method-wrapper '__eq__' of str object at 0x10136f770>

In [27]: "Это строка".__ne__
Out[27]: <method-wrapper '__ne__' of str object at 0x10139cf70>
Сравнивать между собой можно большинство встроенных типов — список с со словарём, строку с кортежем и так далее. Есть исключения (например, set нельзя сравнить ни с чем, кроме set и frozenset), но их мало. Какой же будет результат сравнения? Давайте попробуем:
In [44]: "">()
Out[44]: False

In [45]: ""<()
Out[45]: True

In [46]: []>()
Out[46]: False

In [47]: []<()
Out[47]: True

In [48]: []<{}
Out[48]: False

In [49]: []>{}
Out[49]: True
Даже пустые объекты разных типов не равны между собой, но какое-то правило определённо есть, не случайным же образом создатели языка выбирали что больше чего. Добавление значений в объекты ситуацию не меняет, не играет роли их число и значение. Я намеренно оставляю в стороне числа (типы int, float и complex) и лишь походя затрагиваю строки (str и unicode), там как там правила немного другие, но это неважно.
In [52]: [1,2,3,4,5,6]<(0,)>[100000]
Out[52]: True
Не знаю где это написано в документации, не искал, но я совершенно случайно, из какой-то книги знаю, что на самом деле сравниваются первые буквы типов. Зная эта правило, легко сформировать длинное сравнение, которое будет истиной:
True < {} < [] < object() < "" < () < u""
# b < d < l < o < s < t < u
Решение мне кажется, мягко говоря, неудачным, но уж какое выбрали. Я не вижу ничего страшного в том, чтобы сравнение встроенных типов всегда выдавало False (попробуйте сравнить между собой два None) или выдавать исключение при попытке их сравнения (кажется в 3-й версии Пайтона так и сделали).
2 комментария
19 июля 2011 10:53

Одно из различий Python и JavaScript

Чем дальше, тем между большим количеством языков программирования мне приходится переключаться. Одно из различий объектной модели Пайтона и ДжаваСкрипта мне портит кровь (у них парадигмы ООП вообще сильно различаются), если я вовремя не соображу, что надо переключиться с одного языка на другой.

Суть в том, что в Пайтоне метод ходит в гости со своим контекстом:
class A:
	test = 'A'
	def show(self): print self.test

class B: test = 'B'

a, b = A(), B()

show = a.show
b.show = a.show

show() # A
b.show() # A
Тогда как в JavaScript такой код будет работать совершенно иначе, там методы в чужой монастырь со своим уставом не ходят (если их не попросить):
var test = 'global';

A = function () {
	this.test = 'A',
	this.show = function () { alert(this.test) }
};

B = function () { this.test = 'B'; }

a = new A(); b = new B();

b.show =  a.show
show = a.show

show() // global
b.show() // B
b.show.apply(a) // A
Появление «global» наверное надо разъяснить тем, кто JS знает плохо. На самом деле первая строчка (в данном случае) может читаться как «window.test = 'global'», а «show = a.show» как «window.show = a.show», тогда, должно быть, всё более-менее встаёт на свои места.

Пайтон: замкнувшее замыкание

Есть немало вещей, которые мне не нравятся в Пайтоне. Не так давно мы на работе наткнулись ещё на одну.

У нас есть код, который выглядит примерно так (можно написать и одну функцию, но так нагляднее):
def outer(useless = None):
	def inner():
		if useless is None:
			print "Pichal'ka"

	return inner

outer()()
Ничего необычного, одна функция определяется внутри другой, использует переменную используя переменную из внешней функции. Всё логично, всё работает.

Теперь меняем код:
def outer(useless = None):
	def inner():
		if useless is None:
			print "Pichal'ka"

		# тут много кода, начало мы уже потеряли
		if False: useless = None

	return inner

outer()()
Запускаем код и видим (Пайтон 2.6.5):
Traceback (most recent call last):
  File "sample.py", line 10, in <module>
    outer()()
  File "sample.py", line 3, in inner
    if useless is None:
UnboundLocalError: local variable 'useless' referenced before assignment
Какими бы благородными мотивами не руководствовались создатели Пайтона, мне такое поведение не нравится. Вдруг я забыл как переменная попадает в функцию, присвоил ей что-нибудь и получай ошибку в каком-нибудь редком случае.

Избавиться от эффекта можно, изменив прототип внутренней функции на «inner(useless=useless)».

То же, кстати, происходит при импорте модуля:
import random

def outer():
	print random.choice
	#import random

outer()
Раскомментируйте строчку со вторым импортом и получите ошибку.

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

Я не придумал хороших причин так делать с точки зрения языка (может их кто-то из читателей тут меня поправит?), поэтому считаю, что так сделали для упрощения интерпретатора.
42 комментария
4 марта 2011 00:23

Небольшая задача на Пайтоне

Вот вам небольшая задача на Пайтоне, для того, чтобы понять как у вас с функциональным программированием. Выполнить надо в уме (я смог, значит это возможно). Что вернёт следующее выражение:
(lambda x:x(x))(lambda z: lambda y:z)(1)(2)(3)
Добавлено позднее: если кому-то проще JavaScript, вот тот же код на JavaScript 1.8:
(function (x) x(x))(function (z) function (y) z)(1)(2)(3)
16 комментариев
27 января 2011 14:27

Epic War 4

EpicWar4 (51.74КиБ) Подсел на флеш-игрушку Epic War 4.

Но медленно наращивать мощность очень уж скучно, сделал патч, который увеличивает количество денег до двух миллионов, применив его 2-3 раза, можно купить всё что только есть в игре.

Для того, чтобы применить патч, найдите SOL-файл игры (где такие файлы обычно лежат в разных операционных системах можно посмотреть в «Википедии») — там содержится её сохранённое состояние. И укажите программе при запуске полный путь и имя этого файла.

Программа написана сразу на трёх языках — PowerShell (для Windows) и PHP с Python (для всех), запускайте любым из этих трёх интерпретаторов:
#!/usr/bin/env python
########################################################
# Written by Evgeny Stepanischev (http://bolknote.ru)  #
# Epic War 4 money patch (for PowerShell, Python, PHP)  #
#<?/*
"""*/
echo str_repeat('#', 55), chr(10);

if ($_SERVER['argc'] > 1) {
    
    $fp = @fopen($_SERVER['argv'][1], 'r+b');
    if ($fp) {
        $content = fread($fp, 655350);
        $content = preg_replace('/(?<=stat_money).{5}/s', pack('H*', '0480C584B4'), $content);

        rewind($fp);
        fwrite($fp, $content);
        echo 'Done.';
    } else {
        echo 'Invalid file.';
    } 

    fclose($fp);
} else {
    echo 'Usage: ', $_SERVER['argv'][0], '<filename>';
}

__halt_compiler();

""" + """ " | out-null

If ($args) {
    [char[]] $binary = Get-Content -encoding byte $args[0]

    $binary = [string]::join('', $binary) -replace`
              'stat_money.{5}', `
              "stat_money$([char]0x4)$([char]0x80)$([char]0xC5)$([char]0x84)$([char]0xB4)"

    Set-Content $args[0] ([byte[]][char[]] $binary) -encoding byte

    "Done."

} Else {
    "Usage: " + $MyInvocation.MyCommand.Name +" <filename>"
}

"""
from sys import argv
from os.path import basename

if len(argv) > 1:
    name = 'stat_money'

    f = open(argv[1], 'r+b')
    binary = bytearray(f.read())

    try:
        index = binary.index(name) + 1 + len(name)
        binary[index:index+4] = '\x80\xc5\x84\xb4'

        f.seek(0)
        f.write(binary)
        f.close()
        print('Done.')
    except:
        print('Invalid file.')
else:
    print('Usage: %s <filename>' % basename(argv[0]))

# " | out-null
python patch.ps1 DEF4_SAVE.sol
или
powershell -Command .\patch.ps1 DEF4_SAVE.sol
или
php patch.ps1 DEF4_SAVE.sol

Жаль расцветить три языка в одном файле можно только вручную.
10 комментариев
28 августа 2010 15:15

Собеседование

У нас с Сергеем Чистовичем сейчас проходит примерно по 1—2 собеседования в день. Для оптимизации (чтобы быстрее понять что знает кандидат, а что нет), приходится придумывать вопросы с подвохом.

Например (это Python), что будет тут — True или False и почему:
u'ВАС' == 'ВАС'
str('') == str('')
object() == object()
Добавлено через несколько часов: ребята из комментариев, вы что правда считаете этот элементарнейший тест «тонкостями» и «хитростями» языка? То есть вы в коде никогда не сравниваете два объекта? Два числа, например, да что числа, просто любые два объекта?

А такие вещи как разное поведение наследования у «классических» и «новых» классов, наверное, вообще у вас считается заумью?
43 комментария
27 июля 2010 13:40

Никто ещё не выпустил пиво Python?

Сейчас сижу на кухне, а перед глазами стоит соседская литровая банка пива, подумалось, что если бы кто-нибудь выпускал пиво «Пайтон», то «1L» на нём смотрелось бы очень гармонично.

Не все знают Пайтон, поэтому придётся разъяснить шутку. «1L» — так в Пайтоне записывается число «1» типа «long» (антизанудская мантра: знаю, long — это класс-объект), так что для пайтонистов такое сочетание вполне узнаваемо.
6 комментариев
30 июня 2010 01:08

Невнятный exception у xml.sax

import xml.sax as sax

sax.parseString(u'<r/>', sax.ContentHandler())
Вот этот код выдаёт совершенно невразумительный exception: «xml.sax._exceptions.SAXParseException: :1:1: not well-formed (invalid token)». Ошибка в том, что строка не объект класса str (как должно быть), а unicode.
1 комментарий
30 марта 2010 16:24