Скрытые возможности Python [закрыто]

Поскольку язык программирования Go не поддерживает в настоящее время общие типы, это будет трудно сделать.

Почему у Go нет общих типов?

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

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

Это остается открытой проблемой.

blockquote>

Посмотрите на пакет сортировки Go , чтобы увидеть, как он обрабатывает сравнения и другие операции, относящиеся к типу, путем определения sort.Interface с методами Len, Less и Swap.

1420
задан 30 revs, 24 users 18% 23 May 2017 в 12:34
поделиться

145 ответов

Вы можете украсить функции классами, заменив функцию экземпляром класса:

class countCalls(object):
    """ decorator replaces a function with a "countCalls" instance
    which behaves like the original function, but keeps track of calls

    >>> @countCalls
    ... def doNothing():
    ...     pass
    >>> doNothing()
    >>> doNothing()
    >>> print doNothing.timesCalled
    2
    """
    def __init__ (self, functionToTrack):
        self.functionToTrack = functionToTrack
        self.timesCalled = 0
    def __call__ (self, *args, **kwargs):
        self.timesCalled += 1
        return self.functionToTrack(*args, **kwargs)
6
ответ дан 22 November 2019 в 20:19
поделиться

Управление пределом рекурсии

Получение или установка максимальной глубины рекурсии с помощью sys.getrecursionlimit () и sys.setrecursionlimit ().

Мы можем ограничить это, чтобы предотвратить переполнение стека, вызванное бесконечной рекурсией.

6
ответ дан 22 November 2019 в 20:19
поделиться

Создание Enums

в Python, вы можете сделать это, чтобы быстро создать перечисление:

>>> FOO, BAR, BAZ = range(3)
>>> FOO
0

, но «enums» не нужно иметь целочисленные значения. Вы даже можете сделать это:

class Colors(object):
    RED, GREEN, BLUE, YELLOW = (255,0,0), (0,255,0), (0,0,255), (0,255,255)

#now Colors.RED is a 3-tuple that returns the 24-bit 8bpp RGB 
#value for saturated red
11
ответ дан 22 November 2019 в 20:19
поделиться

Совершенно секретные атрибуты

>>> class A(object): pass
>>> a = A()
>>> setattr(a, "can't touch this", 123)
>>> dir(a)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', "can't touch this"]
>>> a.can't touch this # duh
  File "<stdin>", line 1
    a.can't touch this
                     ^
SyntaxError: EOL while scanning string literal
>>> getattr(a, "can't touch this")
123
>>> setattr(a, "__class__.__name__", ":O")
>>> a.__class__.__name__
'A'
>>> getattr(a, "__class__.__name__")
':O'
9
ответ дан 22 November 2019 в 20:19
поделиться

Обратные косые черты внутри необработанных строк все еще могут экранировать кавычки. См. Это:

>>> print repr(r"aaa\"bbb")
'aaa\\"bbb'

Обратите внимание, что в последней строке присутствуют как обратная косая черта, так и двойные кавычки.

Как следствие, вы не можете заканчивать необработанную строку обратной косой чертой:

>>> print repr(r"C:\")
SyntaxError: EOL while scanning string literal
>>> print repr(r"C:\"")
'C:\\"'

Это происходит потому, что необработанные строки были реализованы для помощи в написании регулярных выражений, а не для записи путей Windows. Прочтите подробное обсуждение этого вопроса на Попался - обратная косая черта в именах файлов Windows .

7
ответ дан 22 November 2019 в 20:19
поделиться

После небольшого количества работы модуль потоковой обработки становится удивительно простым в использовании. Этот декоратор изменяет функцию так, чтобы она выполнялась в собственном потоке, возвращая экземпляр класса-заполнителя вместо обычного результата. Вы можете проверить ответ, проверив placeolder.result или дождаться его, вызвав placeholder.awaitResult ()

def threadify(function):
    """
    exceptionally simple threading decorator. Just:
    >>> @threadify
    ... def longOperation(result):
    ...     time.sleep(3)
    ...     return result
    >>> A= longOperation("A has finished")
    >>> B= longOperation("B has finished")

    A doesn't have a result yet:
    >>> print A.result
    None

    until we wait for it:
    >>> print A.awaitResult()
    A has finished

    we could also wait manually - half a second more should be enough for B:
    >>> time.sleep(0.5); print B.result
    B has finished
    """
    class thr (threading.Thread,object):
        def __init__(self, *args, **kwargs):
            threading.Thread.__init__ ( self )  
            self.args, self.kwargs = args, kwargs
            self.result = None
            self.start()
        def awaitResult(self):
            self.join()
            return self.result        
        def run(self):
            self.result=function(*self.args, **self.kwargs)
    return thr
4
ответ дан 22 November 2019 в 20:19
поделиться

Exposing Mutable Buffers

Using the Python Buffer Protocol to expose mutable byte-oriented buffers in Python (2.5/2.6).

(Sorry, no code here. Requires use of low-level C API or existing adapter module).

5
ответ дан 22 November 2019 в 20:19
поделиться

Питоническая идиома x = ... if ... else ... намного превосходит x = ... и ... или ... и вот почему:

Хотя утверждение

x = 3 if (y == 1) else 2

эквивалентно

x = y == 1 and 3 or 2

, если вы используете x = ... и ... или ... идиома, однажды вас может укусить такая запутанная ситуация:

x = 0 if True else 1    # sets x equal to 0

и, следовательно, не эквивалентно

x = True and 0 or 1   # sets x equal to 1

. Подробнее о том, как это сделать, см. Скрытые возможности Python .

5
ответ дан 22 November 2019 в 20:19
поделиться

Обезносные объекты

Каждый объект в Python имеет __ Dict __ , который хранит атрибуты объекта. Итак, вы можете сделать что-то вроде этого:

class Foo(object):
    def __init__(self, arg1, arg2, **kwargs):
        #do stuff with arg1 and arg2
        self.__dict__.update(kwargs)

f = Foo('arg1', 'arg2', bar=20, baz=10)
#now f is a Foo object with two extra attributes

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

class struct(object):
    def __init__(**kwargs):
       self.__dict__.update(kwargs)

s = struct(foo=10, bar=11, baz="i'm a string!')
5
ответ дан 22 November 2019 в 20:19
поделиться

В Python нет секретов ;)

4
ответ дан 22 November 2019 в 20:19
поделиться

Вы можете присвоить нескольким переменным одно и то же значение

>>> foo = bar = baz = 1
>>> foo, bar, baz
(1, 1, 1)

Полезно для компактной инициализации нескольких переменных значением None.

4
ответ дан 22 November 2019 в 20:19
поделиться

Объедините распаковку с функцией печати:

# in 2.6 <= python < 3.0, 3.0 + the print function is native
from __future__ import print_function 

mylist = ['foo', 'bar', 'some other value', 1,2,3,4]  
print(*mylist)
4
ответ дан 22 November 2019 в 20:19
поделиться

Python 2.x игнорирует запятые, если они находятся после последнего элемента последовательности:

>>> a_tuple_for_instance = (0,1,2,3,)
>>> another_tuple = (0,1,2,3)
>>> a_tuple_for_instance == another_tuple
True

Завершающая запятая приводит к тому, что одиночный элемент в скобках обрабатывается как последовательность:

>>> a_tuple_with_one_element = (8,)
6
ответ дан 22 November 2019 в 20:19
поделиться

Slices & Mutability

Копирование списков

>>> x = [1,2,3]
>>> y = x[:]
>>> y.pop()
3
>>> y
[1, 2]
>>> x
[1, 2, 3]

Замена списков

>>> x = [1,2,3]
>>> y = x
>>> y[:] = [4,5,6]
>>> x
[4, 5, 6]
6
ответ дан 22 November 2019 в 20:19
поделиться

Срезы как lvalue. Это Решето Эратосфена создает список, который имеет либо простое число, либо 0. Элементы обнуляются при назначении срезов в цикле.

def eras(n):
    last = n + 1
    sieve = [0,0] + list(range(2, last))
    sqn = int(round(n ** 0.5))
    it = (i for i in xrange(2, sqn + 1) if sieve[i])
    for i in it:
        sieve[i*i:last:i] = [0] * (n//i - i + 1)
    return filter(None, sieve)

Для работы левому срезу должен быть назначен список справа такой же длины.

6
ответ дан 22 November 2019 в 20:19
поделиться

Управление памятью

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

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

2
ответ дан 22 November 2019 в 20:19
поделиться

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

Однако просто добавьте ссылку на определение вашего класса, и все будет хорошо:

например, раньше:

class Bleh:
    pass

сейчас,

class Blah:
    pass

так что маринованный сохраненный файл вашего пользователя содержит ссылка на Bleh, которого не существует из-за переименования. Исправить?

Bleh = Blah

просто!

3
ответ дан 22 November 2019 в 20:19
поделиться

Тот факт, что ВСЕ является объектом и как таковой является расширяемым. Я могу добавить переменные-члены в качестве метаданных к функции, которую я определяю:

>>> def addInts(x,y): 
...    return x + y
>>> addInts.params = ['integer','integer']
>>> addInts.returnType = 'integer'

Это может быть очень полезно для написания динамических модульных тестов, например

3
ответ дан 22 November 2019 в 20:19
поделиться

Встроенная функция getattr:

>>> class C():
    def getMontys(self):
        self.montys = ['Cleese','Palin','Idle','Gilliam','Jones','Chapman']
        return self.montys


>>> c = C()
>>> getattr(c,'getMontys')()
['Cleese', 'Palin', 'Idle', 'Gilliam', 'Jones', 'Chapman']
>>> 

Полезно, если вы хотите отправить функцию в зависимости от контекста. См. Примеры в Dive Into Python ( Здесь )

2
ответ дан 22 November 2019 в 20:19
поделиться

Classes as first-class objects (shown through a dynamic class definition)

Note the use of the closure as well. If this particular example looks like a "right" approach to a problem, carefully reconsider ... several times :)

def makeMeANewClass(parent, value):
  class IAmAnObjectToo(parent):
    def theValue(self):
      return value
  return IAmAnObjectToo

Klass = makeMeANewClass(str, "fred")
o = Klass()
print isinstance(o, str)  # => True
print o.theValue()        # => fred
2
ответ дан 22 November 2019 в 20:19
поделиться

Простой способ проверить, находится ли ключ в dict:

>>> 'key' in { 'key' : 1 }
True

>>> d = dict(key=1, key2=2)
>>> if 'key' in d:
...     print 'Yup'
... 
Yup
3
ответ дан 22 November 2019 в 20:19
поделиться

Что касается реализации Ником Джонсоном класса свойств (просто демонстрация дескрипторов, конечно, а не замена встроенного), я бы включил сеттер который вызывает AttributeError:

class Property(object):
    def __init__(self, fget):
        self.fget = fget

    def __get__(self, obj, type):
        if obj is None:
            return self
        return self.fget(obj)

    def __set__(self, obj, value):
       raise AttributeError, 'Read-only attribute'

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

2
ответ дан 22 November 2019 в 20:19
поделиться
** Using sets to reference contents in sets of frozensets**

Как вы, вероятно, знаете, наборы являются изменяемыми и, следовательно, не хешируемыми, поэтому необходимо использовать frozensets, если вы хотите создать набор наборов (или использовать наборы в качестве ключей словаря):

>>> fabc = frozenset('abc')
>>> fxyz = frozenset('xyz')
>>> mset = set((fabc, fxyz))
>>> mset
{frozenset({'a', 'c', 'b'}), frozenset({'y', 'x', 'z'})}

Однако можно проверить членство и удалить / отбросить члены, используя обычные наборы:

>>> abc = set('abc')
>>> abc in mset
True
>>> mset.remove(abc)
>>> mset
{frozenset({'y', 'x', 'z'})}

Цитата из документации стандартной библиотеки Python:

Обратите внимание, что аргумент elem для __ contains__ () , remove () и discard () методы могут быть набором. Чтобы облегчить поиск эквивалентного морозильника, Набор elem временно изменяется во время поиска, а затем восстанавливается. В течение поиск, набор elem не следует читать или изменять, поскольку он не имеют значимое значение.

К сожалению, и, возможно, удивительно, то же самое нельзя сказать о словарях:

>>> mdict = {fabc:1, fxyz:2}
>>> fabc in mdict
True
>>> abc in mdict
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
TypeError: unhashable type: 'set'
3
ответ дан 22 November 2019 в 20:19
поделиться

Можно построить функции kwargs по требованию:

kwargs = {}
kwargs[str("%s__icontains" % field)] = some_value
some_function(**kwargs)

Вызов str() как-то нужен, так как питон жалуется, что это не строка. Не знаю почему ;) Я использую это для динамических фильтров внутри объектной модели Djangos:

result = model_class.objects.filter(**kwargs)
0
ответ дан 22 November 2019 в 20:19
поделиться

Раскосы

def g():
    print 'hi!'

def f(): (
    g()
)

>>> f()
hi!
-9
ответ дан 22 November 2019 в 20:19
поделиться