У меня были проблемы с intl при использовании Moodle, которые я исправил, выполнив следующие действия:
$ cd /Applications/XAMPP/bin
intl
, запустив $ sudo ./pecl install intl
. Это должно скомпилировать некоторые вещи, и в случае успеха установка должна завершиться: Build process completed successfully
Installing '/Applications/XAMPP/xamppfiles/lib/php/extensions/no-debug-non-zts-20131226/intl.so'
install ok: channel://pecl.php.net/intl-3.0.0
configuration option "php_ini" is not set to php.ini location
You should add "extension=intl.so" to php.ini
$ cd ../etc
Там у вас будет php.ini
, к которому вы должны добавить extension=intl.so
. В моей системе я добавил строку после строки 959, которую вы можете найти, выполнив поиск php_intl
Надеюсь, это сработает для вас!
Здесь есть две вещи:
1. class attributes and instance attributes
2. difference between the operators + and += for lists
+
оператор вызывает метод __add__
в списке. Он берет все элементы из своих операндов и создает новый список, содержащий эти элементы, поддерживающие их порядок.
+=
оператор вызывает метод __iadd__
в списке. Он требует итерации и добавляет все элементы итерабельности в список на месте. Он не создает новый объект списка.
В классе foo
оператор self.bar += [x]
не является оператором присваивания, но фактически переводит на
self.bar.__iadd__([x]) # modifies the class attribute
, который изменяет список на месте и действует как метод списка extend
.
В классе foo2
, наоборот, оператор присваивания в методе init
self.bar = self.bar + [x]
может быть деконструирован как: экземпляр не имеет атрибута bar
(есть атрибут класса с тем же именем), поэтому он обращается к атрибуту class bar
и создает новый список, добавляя к нему x
. Оператор преобразуется в:
self.bar = self.bar.__add__([x]) # bar on the lhs is the class attribute
Затем он создает атрибут экземпляра bar
и присваивает ему вновь созданный список. Обратите внимание, что bar
на rhs присваивания отличается от bar
на lhs.
Для экземпляров класса foo
, bar
является атрибутом класса, а не атрибутом экземпляра. Следовательно, любое изменение атрибута class bar
будет отражено для всех экземпляров.
Напротив, каждый экземпляр класса foo2
имеет свой собственный атрибут экземпляра bar
, который отличается от атрибута класса с тем же именем bar
.
f = foo2(4)
print f.bar # accessing the instance attribute. prints [4]
print f.__class__.bar # accessing the class attribute. prints []
Надеюсь, это очистит.
Проблема в том, что bar
определяется как атрибут класса, а не переменная экземпляра.
В foo
атрибут класса модифицирован в методе init
, поэтому все экземпляры затронуты.
В foo2
переменная экземпляра определяется с помощью атрибута (пустого) класса, и каждый экземпляр получает свой собственный bar
.
«Правильный» реализация будет:
class foo:
def __init__(self, x):
self.bar = [x]
Конечно, атрибуты класса являются полностью законными. Фактически вы можете получить доступ и изменить их, не создавая экземпляр класса следующим образом:
class foo:
bar = []
foo.bar = [x]
Хотя прошло много времени и было сказано много правильных вещей, нет ответа, который связывает оба эффекта.
У вас есть 2 эффекта:
+=
(как указано Scott Griffiths ) В классе foo
метод __init__
изменяет атрибут класса. Это потому, что self.bar += [x]
соответствует self.bar = self.bar.__iadd__([x])
. __iadd__()
для модификации места, поэтому он изменяет список и возвращает ссылку на него.
Обратите внимание, что экземпляр dict изменен, хотя это, как правило, не требуется, поскольку класс dict уже содержит одно и то же назначение , Таким образом, эта деталь почти незаметна - кроме случаев, когда вы делаете foo.bar = []
. Здесь экземпляры bar
остаются теми же благодаря сказанному факту.
Однако в классе foo2
используется bar
класса, но не затрагивается. Вместо этого к нему добавляется [x]
, образуя новый объект, так как здесь вызывается self.bar.__add__([x])
, который не изменяет объект. Результат помещается в экземпляр dict then, давая экземпляру новый список как dict, в то время как атрибут класса остается модифицированным.
Различие между ... = ... + ...
и ... += ...
также влияет на присвоения впоследствии :
f = foo(1) # adds 1 to the class's bar and assigns f.bar to this as well.
g = foo(2) # adds 2 to the class's bar and assigns g.bar to this as well.
# Here, foo.bar, f.bar and g.bar refer to the same object.
print f.bar # [1, 2]
print g.bar # [1, 2]
f.bar += [3] # adds 3 to this object
print f.bar # As these still refer to the same object,
print g.bar # the output is the same.
f.bar = f.bar + [4] # Construct a new list with the values of the old ones, 4 appended.
print f.bar # Print the new one
print g.bar # Print the old one.
f = foo2(1) # Here a new list is created on every call.
g = foo2(2)
print f.bar # So these all obly have one element.
print g.bar
Вы можете проверить идентичность объектов с помощью print id(foo), id(f), id(g)
(не забудьте дополнительные ()
s, если вы находитесь на Python3).
BTW: Оператор +=
называется «расширенным назначением» и, как правило, имеет целью сделать возможными модификации на месте.
a += b
отличается от a = a + b
для двух списков a
и b
. Но это имеет смысл; extend
чаще всего предназначалось для списков, а не для создания новой копии всего списка, которая будет иметь более высокую временную сложность. Если разработчикам необходимо быть осторожными, чтобы они не изменяли исходные списки на месте, то кортежи являются лучшим вариантом, являющимся неизменяемыми объектами. +=
с кортежами не может изменить исходный кортеж.
– Pranjal Mittal
5 June 2017 в 01:31
Другие ответы, похоже, в значительной степени затронули его, хотя, кажется, стоит указать и ссылаться на Augmented Assignments PEP 203 :
Они [расширенные операторы присваивания] реализуют тот же оператор, что и их обычная двоичная форма, за исключением того, что операция выполняется «на месте», когда объект левой стороны поддерживает ее, а левая сторона - только оценивается один раз.
...
Идея расширенного назначения в Python заключается в том, что это не просто более простой способ написать общую практику хранения результата бинарной операции в ее левом операнде, но также и способ для левого операнда, о котором идет речь, знать, что он должен действовать «на себя», а не создавать модифицированную копию самого себя.
Общий ответ: +=
пытается вызвать специальный метод __iadd__
, а если он недоступен, он пытается использовать __add__
. Таким образом, проблема заключается в различии между этими специальными методами.
Специальный метод __iadd__
предназначен для дополнения на месте, то есть он мутирует объект, на котором он действует. Специальный метод __add__
возвращает новый объект и также используется для стандартного оператора +
.
Поэтому, когда оператор +=
используется для объекта, у которого __iadd__
определен объект изменен на месте. В противном случае вместо этого попытается использовать plain __add__
и вернуть новый объект.
Вот почему для изменяемых типов, таких как списки +=
, изменяется значение объекта, тогда как для неизменяемых типов, таких как кортежи, строки и целые числа вместо этого возвращаются новый объект (a += b
становится эквивалентным a = a + b
).
Для типов, которые поддерживают как __iadd__
, так и __add__
, вы должны быть осторожны, какой из них вы используете. a += b
вызывается __iadd__
и мутирует a
, тогда как a = a + b
создаст новый объект и назначит его a
. Это не то же самое действие!
>>> a1 = a2 = [1, 2]
>>> b1 = b2 = [1, 2]
>>> a1 += [3] # Uses __iadd__, modifies a1 in-place
>>> b1 = b1 + [3] # Uses __add__, creates new list, assigns it to b1
>>> a2
[1, 2, 3] # a1 and a2 are still the same list
>>> b2
[1, 2] # whereas only b1 was changed
Для неизменяемых типов (где у вас нет __iadd__
) a += b
и a = a + b
эквивалентны. Это позволяет использовать +=
для неизменяемых типов, что может показаться странным конструктивным решением, пока вы не подумаете, что в противном случае вы не могли бы использовать +=
для неизменяемых типов, таких как числа!
__radd__
, который иногда может быть вызван (он имеет отношение к выражениям, которые в основном связаны с подклассами).
– jfs
27 February 2010 в 20:55
+=
фактически расширяет i> список, это объясняет, почему x = []; x = x + {}
дает TypeError
, а x = []; x += {}
просто возвращает []
.
– zezollo
16 August 2017 в 07:19
>>> elements=[[1],[2],[3]]
>>> subset=[]
>>> subset+=elements[0:1]
>>> subset
[[1]]
>>> elements
[[1], [2], [3]]
>>> subset[0][0]='change'
>>> elements
[['change'], [2], [3]]
>>> a=[1,2,3,4]
>>> b=a
>>> a+=[5]
>>> a,b
([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
>>> a=[1,2,3,4]
>>> b=a
>>> a=a+[5]
>>> a,b
([1, 2, 3, 4, 5], [1, 2, 3, 4])