SPL PHP: его интерфейсы, включающие массивы, покрывают все свойства массива?

1119 Не обязательно легко, но возможно. Нам нужно создать новый тип EnumMeta 1 sup>, создать Enum обычным образом, а затем переназначить тип после создания Enum:

from enum import Enum, EnumMeta

class FrozenEnum(EnumMeta):
    "prevent creation of new attributes"
    def __getattr__(self, name):
        if name not in self._member_map_:
            raise AttributeError('%s %r has no attribute %r'
                % (self.__class__.__name__, self.__name__, name))
        return super().__getattr__(name)

    def __setattr__(self, name, value):
        if name in self.__dict__ or name in self._member_map_:
            return super().__setattr__(name, value)
        raise AttributeError('%s %r has no attribute %r'
                % (self.__class__.__name__, self.__name__, name))

class Color(Enum):
    red = 1
    green = 2
    blue = 3

Color.__class__ = FrozenEnum

и использования :

>>> type(Color)


>>> list(Color)
[, , ]

>>> Color.blue


>>> Color.baz = 3
Traceback (most recent call last):
  ...
AttributeError: FrozenEnum 'Color' has no attribute 'baz'

>>> Color.baz
Traceback (most recent call last):
  ...
AttributeError: 'FrozenEnum' object has no attribute 'baz'

Попытка переназначения члена по-прежнему приводит к более дружественной ошибке:

>>> Color.blue = 9
Traceback (most recent call last):
  ...
AttributeError: Cannot reassign members.

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

def freeze(enum_class):
    enum_class.__class__ = FrozenEnum
    return enum_class

и используется:

@freeze
class Color(Enum):
    red = 1
    green = 2
    blue = 3

Обратите внимание, что все еще можно перезаписать обычные атрибуты, такие как функции:

@freeze
class Color(Enum):
    red = 1
    green = 2
    blue = 3
    def huh(self):
        print("Huh, I am %s!" % self.name)

и используемые :

>>> Color.huh


>>> Color.blue.huh()
Huh, I am blue!

>>> Color.huh = 3
>>> Color.huh
3
>>> Color.blue.huh()
Traceback (most recent call last):
  ...
TypeError: 'int' object is not callable

Даже это может быть заблокировано, но я оставлю это (пока) в качестве упражнения для кого-то еще.


1 sup> Это только второй случай, который я видел, когда требуется подкласс EnumMeta. О других см. this question .

Раскрытие: я являюсь автором Python stdlib Enum , enum34 backport и Advanced Enumeration (aenum) библиотека. I>

6
задан Wilco 28 September 2008 в 06:49
поделиться

3 ответа

Единственными проблемами, о которых я могу думать, является gettype () и is_array () функции. Проверьте свой код на

gettype($FakeArray) == 'array' 
is_array($FakeArray)

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

7
ответ дан 8 December 2019 в 17:31
поделиться

Другие различия включают '+' оператор для массивов (слияние) и отказ всего array_* функции, включая наиболее часто используемое array_merge и array_shift.

3
ответ дан 8 December 2019 в 17:31
поделиться

В дополнение к точкам, сделанным выше, Вы не смогли бы сделать работу подсказок типа массива пространства пользователя с экземплярами Вашего класса. Например:

<?php
function f(array $a) { /*...*/ }

$ao = new ArrayObject();
f($ao); //error
?>

Вывод:

Catchable fatal error: Argument 1 passed to f() must be an array, object given 
4
ответ дан 8 December 2019 в 17:31
поделиться
Другие вопросы по тегам:

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