Можете Вы методы патча обезьяны на базовых типах в Python?

8 ответов

Что точно Вы подразумеваете под Патчем Обезьяны здесь? Существуют несколько немного отличающихся определений .

, Если Вы имеете в виду, "можно ли изменить методы класса во времени выполнения?", тогда ответ - решительно да:

class Foo:
  pass # dummy class

Foo.bar = lambda self: 42

x = Foo()
print x.bar()

, Если Вы имеете в виду, "можно ли изменить методы класса во времени выполнения, и заставляют все экземпляры того класса измениться после совершения ?" тогда ответ - да также. Просто измените порядок немного:

class Foo:
  pass # dummy class

x = Foo()

Foo.bar = lambda self: 42

print x.bar()

, Но Вы не можете сделать этого для определенных встроенных классов, как int или float. Методы этих классов реализованы в C и существуют определенные абстракции, принесенные в жертву для создания реализации легче и более эффективной.

я не действительно ясен на [1 111], почему Вы хотели бы изменить поведение встроенных числовых классов так или иначе. Если необходимо изменить их поведение, разделите их на подклассы!!

40
ответ дан Dan Lenski 7 November 2019 в 11:14
поделиться

Нет, но у Вас есть UserDict UserString и UserList, которые были сделаны с точно этим в памяти.

, Если Вы гуглите Вас, найдет примеры для других типов, но это встроено.

В общем исправлении обезьяны менее используется в Python, чем в Ruby.

2
ответ дан Luka Marinko 7 November 2019 в 11:14
поделиться

Если Вы действительно действительно действительно хотите сделать патч обезьяны в Python, можно сделать (sortof) взлом с "нечто импорта как панель" техника.

, Если у Вас есть класс, такой как TelnetConnection, и Вы хотите расширить его, разделить его на подклассы в отдельном файле и назвать его чем-то как TelnetConnectionExtended.

Затем наверху Вашего кода, где Вы обычно говорили бы:

import TelnetConnection

изменение, что, чтобы быть:

import TelnetConnectionExtended as TelnetConnection

и затем везде в Вашем коде, что Вы ссылаетесь на TelnetConnection, будет на самом деле ссылаться на TelnetConnectionExtended.

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

3
ответ дан HanClinto 7 November 2019 в 11:14
поделиться

Нет, Вы не можете сделать этого в Python. Я полагаю, что он хорошая вещь.

1
ответ дан sanxiyn 7 November 2019 в 11:14
поделиться

Базовые типы Python неизменны дизайном, как указали другие пользователи:

>>> int.frobnicate = lambda self: whatever()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'int'

Вы, конечно могли достигать эффекта, который Вы описываете путем создания подкласса, так как пользовательские типы в Python изменяемы по умолчанию.

>>> class MyInt(int):
...   def frobnicate(self):
...     print 'frobnicating %r' % self
... 
>>> five = MyInt(5)
>>> five.frobnicate()
frobnicating 5
>>> five + 8
13

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

существует, конечно, несколько ситуаций, где Python программисты, которые бегло говорят на идиоме, рассматривают этот вид разделения на подклассы правильного поступка. Например, os.stat() возвраты tuple подкласс, который добавляет именованных участников, точно для обращения к виду беспокойства удобочитаемости, к которому Вы обращаетесь в Вашем примере.

>>> import os
>>> st = os.stat('.')
>>> st
(16877, 34996226, 65024L, 69, 1000, 1000, 4096, 1223697425, 1223699268, 1223699268)
>>> st[6]
4096
>>> st.st_size
4096

Однако в определенном примере Вы даете, я не полагаю, что разделение на подклассы float в item.price (или в другом месте), очень вероятно, считали бы вещью Pythonic сделать. Я могу легко воображать кого-то решающего добавить price_should_equal() метод к [1 110], если это было основным вариантом использования; если бы Вы искали что-то более общее, возможно, могло бы иметь больше смысла использовать параметры, передаваемые по имени для создания подразумеваемого смысла более ясным, как в [1 120]

should_equal(observed=item.price, expected=19.99)

или что-то вдоль тех строк. Это является немного подробным, но несомненно это могло быть улучшено. Возможное преимущество для такого подхода по исправлению обезьяны стиля Ruby состоит в том, что should_equal() мог легко выполнить его сравнение на любом типе, не всего int или float. Но и возможно я становлюсь слишком оказавшимся в деталях конкретного примера, который Вы, оказалось, обеспечили.

13
ответ дан zaphod 7 November 2019 в 11:14
поделиться

Нет, Вы не можете. В Python все данные (классы, методы, функции, и т.д.) определенный в дополнительных модулях C (включая builtins) неизменны. Это вызвано тем, что модули C совместно используются несколькими интерпретаторами в том же процессе, таким образом, monkeypatching их также влиял бы на несвязанные интерпретаторы в том же процессе. (Несколько интерпретаторов в том же процессе возможны через C API, и было некоторое усилие к созданию их применимо на уровне Python.)

Однако классы, определенные в коде Python, могут быть monkeypatched, потому что они локальны для того интерпретатора.

70
ответ дан user2357112 7 November 2019 в 11:14
поделиться

Что делает should_equal ? Это логическое возвращение True или False ? В этом случае это пишется:

item.price == 19.99

Нет никакого вкуса для учета, но ни один обычный разработчик Python не скажет, что он менее читабелен, чем ваша версия.

Вместо этого should_equal устанавливает какой-то валидатор? (почему валидатор должен быть ограничен одним значением? Почему бы просто не установить значение и не обновлять его после этого?) Если вам нужен валидатор, это никогда не сработает, так как вы предлагаете изменить либо целое число, либо все целые числа. (Валидатор, который требует, чтобы 18,99 равнялся 19,99 , всегда потерпит неудачу.) Вместо этого вы можете записать его следующим образом:

item.price_should_equal(19.99)

или this:

item.should_equal('price', 19.99)

и определить соответствующие методы для элементов. класс или суперклассы.

1
ответ дан 7 November 2019 в 11:14
поделиться

Вот пример реализации item.price.should_equal , хотя я бы использовал Decimal вместо float в реальной программе:

class Price(float):
    def __init__(self, val=None):
        float.__init__(self)
        if val is not None:
            self = val

    def should_equal(self, val):
        assert self == val, (self, val)

class Item(object):
    def __init__(self, name, price=None):
        self.name = name
        self.price = Price(price)

item = Item("spam", 3.99)
item.price.should_equal(3.99)
4
ответ дан 7 November 2019 в 11:14
поделиться
Другие вопросы по тегам:

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