Уведомления

Группа в Telegram: @pythonsu

#1 Дек. 22, 2021 01:33:01

Еленочка
От:
Зарегистрирован: 2008-04-12
Сообщения: 24
Репутация: +  0  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

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

 field[1, 'a'] = 25    field['a', 1] = 25     field['a', '1'] = 25      field['1', 'a'] = 25    field['1a'] = 25    field['a1'] = 25    field[1, 'A'] = 25   field['A', 1] = 25   field['A', '1'] = 25    field['1', 'A'] = 25   field['1A'] = 25   field['A1'] = 25.
Т.е. ключи принимаются различные - tuple (int, str), tuple (str, int) или str.
Так же по запросу ключа - выдать значение. Эту часть реализовала.
Теперь мне нужно дополнить ключами вида field.a1 = 25 (т.е. использовать и __setattr__). И вот тут не нашла еще способ как совместить __setattr__ + setitem, и не потерять функционал старых методов. С выдачей, вроде получилось.
Код длинный, пока выложу обрывком, если надо, то и полностью выложу.
Обработку ключей разбила на маленькие функции (сначала определю tuple или str, функции на обработку каждого)
 class Field:
    def __init__(self):
        self.my_list = {}
        self.my_set_key = set()
    def to_my_list_tuple(self, str_val1, str_val2):
        pass
        # Обработка tuple
    def to_my_list_str(self, str_val1, str_val2=None):
        # Обработка str
        pass
    def my_new_key(self, key):
        #Любой получаемый ключ преобразую к виду 'a1', 'b555'
        pass
    
    def __getitem__(self, key):
        try:
            new_key = self.my_new_key(key)
            if new_key in self.my_list:
                return self.my_list[new_key]
            else:
                return None
        except:
            new_key = self.__getattr__(self, key)   #работает, возможно и не самое лучшее решение
# c __setitem не получилось использовать try:  except
    def __setitem__(self, key, value):    
        new_key = None
        new_key = self.my_new_key(key)
        if new_key is None:
            raise ValueError
        else:
            self.my_list[new_key] = value
            if new_key in self.my_set_key:
                pass
            else:
                self.my_set_key.add(new_key)
    def __iter__(self):
        self.froz_set = frozenset(self.my_set_key)
        for key in self.my_list:
            yield self.my_list[key]
    def __delitem__(self, key):
        new_key = self.my_new_key(key)
        del self.my_list[new_key]
    def __contains__(self, key):
        new_key = self.my_new_key(key)
        # print(new_key in self.my_list)
        return new_key in self.my_list
    def __getattr__(self, key):
        new_key = self.my_new_key(key)
        if new_key in self.my_list:
            return self.my_list[new_key]
        else:
            return None
    def __setattr__(self, key, value):
        pass



Отредактировано FishHook (Дек. 22, 2021 11:09:03)

Офлайн

#2 Дек. 22, 2021 11:27:44

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

   
class MyWeirdDict:
   
    def __getattr__(self, item):
        try:
            return super().__getattr__(item)
        except AttributeError as e:
            raise KeyError(item) from e
   
    def __getitem__(self, item):
        return getattr(self, item)
  
    def __setitem__(self, key, value):
        setattr(self, key, value)
  
  
d = MyWeirdDict()
d.key_1 = 34
d['key_2'] = 56
print(d.key_1)
print(d.key_2)
print(d['key_2'])
  
  
class MyWeirdDict2:
  
    def __init__(self):
        self._dct = {}
  
    def __getattr__(self, item):
        return self._dct[item]
  
    def __getitem__(self, item):
        return self._dct[item]
  
    def __setitem__(self, key, value):
        self._dct[key] = value
 
 
d = MyWeirdDict2()
d.key_1 = 34
d['key_2'] = 56
print(d.key_1)
print(d.key_2)
print(d['key_2'])
 



Офлайн

#3 Дек. 22, 2021 23:00:21

Еленочка
От:
Зарегистрирован: 2008-04-12
Сообщения: 24
Репутация: +  0  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

FishHook
В данном решении получается, что значения не хранятся в одном объекте. key1 не попадет в словарь. В этом основная для меня проблема. И если ввести
 field[1, 'a'] = 25
field.a1 = 555    
То значение не перезапишется.
А мне необходимо, извлечь ключ, преобразовать ( к виду a1, b44556, v6 (одна буква и цифра)) записать в словарь.



Отредактировано Еленочка (Дек. 22, 2021 23:58:33)

Офлайн

#4 Дек. 23, 2021 00:06:56

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10010
Репутация: +  857  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

Еленочка
В данном решении получается, что значения не хранятся в одном объекте.
И если ввести
  
field[1, 'a'] = 25
field.a1 = 555    
То значение не перезапишется.
Да конечно, он не догнал, что нужно сделать. Что тут не так всё просто делается.

Нужно написать одну функцию, которая берёт любую хрень эту и отображает её в одну точную хрень (то есть отображает множество на один элемент). И всё. И потом эта одна точная хрень используется для хранения в объекте поля. Если ты захотел взять её значение, то ты опять пропускаешь ключ через функцию, которая приводит этот ключ к точному виду, и таким образом оно возвращается.

Вот этот эффект, когда ты ООП занимаешься, не умея декомпозировать в структурной парадигме.



Офлайн

#5 Дек. 23, 2021 10:49:16

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

py.user.next
Нужно написать одну функцию, которая берёт любую хрень эту и отображает её в одну точную хрень
ну теперь то всё понятно! Декомпозировал в структурной парадигме как боженька



Офлайн

#6 Дек. 23, 2021 11:28:04

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10010
Репутация: +  857  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

FishHook
ну теперь то всё понятно! Декомпозировал
Да я вот набросал без оптимизаций
  
>>> def f(key):
...     if type(key) is str:
...         a, b = key[:len(key) // 2], key[len(key) // 2:]
...     elif type(key) is tuple:
...         a, b = tuple(map(str, key))
...     out = None
...     if a[0].isalpha() and b[0].isdigit():
...         out = a.lower() + b
...     elif a[0].isdigit() and b[0].isalpha():
...         out = b.lower() + a
...     else:
...         raise ValueError
...     return out
... 
>>> lst = ['1a',
...        'a1',
...        '1A',
...        'A1',
...        (1, 'a'),
...        (1, 'A'),
...        ('a', 1),
...        ('A', 1),
...        ('a', '1'),
...        ('A', '1'),
...        ('1', 'a'),
...        ('1', 'A')]
>>> 
>>> for i in lst:
...     print(repr(i), '->', repr(f(i)))
... 
'1a' -> 'a1'
'a1' -> 'a1'
'1A' -> 'a1'
'A1' -> 'a1'
(1, 'a') -> 'a1'
(1, 'A') -> 'a1'
('a', 1) -> 'a1'
('A', 1) -> 'a1'
('a', '1') -> 'a1'
('A', '1') -> 'a1'
('1', 'a') -> 'a1'
('1', 'A') -> 'a1'
>>> 
>>> lst = ['123abc',
...        'abc123',
...        '123ABC',
...        'ABC123',
...        (123, 'abc'),
...        (123, 'ABC'),
...        ('abc', 123),
...        ('ABC', 123),
...        ('abc', '123'),
...        ('ABC', '123'),
...        ('123', 'abc'),
...        ('123', 'ABC')]
>>> 
>>> for i in lst:
...     print(repr(i), '->', repr(f(i)))
... 
'123abc' -> 'abc123'
'abc123' -> 'abc123'
'123ABC' -> 'abc123'
'ABC123' -> 'abc123'
(123, 'abc') -> 'abc123'
(123, 'ABC') -> 'abc123'
('abc', 123) -> 'abc123'
('ABC', 123) -> 'abc123'
('abc', '123') -> 'abc123'
('ABC', '123') -> 'abc123'
('123', 'abc') -> 'abc123'
('123', 'ABC') -> 'abc123'
>>>
Ничоси! Смотри, что творит! Прямо гением надо быть, чтобы сообразить такое!



Отредактировано py.user.next (Дек. 23, 2021 11:30:49)

Офлайн

#7 Дек. 23, 2021 11:41:25

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

Теперь мне нужно дополнить ключами вида field.a1 = 25
задача была по крайней мере сформулирована следующим образом

__setitem__ и __setattr__ в одном классе
И вот тут не нашла еще способ как совместить __setattr__ + setitem, и не потерять функционал старых методов.

очевидно, у автора нет проблем с парсингом ключа, а есть в использовании магических методов питона.



Отредактировано FishHook (Дек. 23, 2021 11:54:09)

Офлайн

#8 Дек. 23, 2021 14:00:51

Еленочка
От:
Зарегистрирован: 2008-04-12
Сообщения: 24
Репутация: +  0  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

 import re
class Field:
    def __init__(self):
        self.my_list = {}
        self.my_set_key = set()
    def to_my_list_tuple(self, str_val1, str_val2):
        key_str = None
        key_int = None
        if isinstance(str_val1, int):
            if str_val1 > 0:
                if isinstance(str_val2, str):
                    if len(str_val2) == 1 and str_val2.isalpha():
                        key_str = str_val2.lower()
                        key_int = str_val1
                        return key_str, key_int
                    else:
                        raise ValueError
                        # return key_str, key_int
                else:
                    raise ValueError
                    # return key_str, key_int
            else:
                raise ValueError
                # return key_str, key_int
        elif isinstance(str_val2, int):
            if str_val2 > 0:
                if isinstance(str_val1, str):
                    if len(str_val1) == 1 and str_val1.isalpha():
                        key_str = str_val1.lower()
                        key_int = str_val2
                        return key_str, key_int
                    else:
                        raise ValueError
                        # return key_str, key_int
                else:
                    raise ValueError
                    # return key_str, key_int
            else:
                raise ValueError
                # return key_str, key_int
        elif isinstance(str_val1, str) and isinstance(str_val2, str):
            if ('.' in str_val1) or ('.' in str_val2) or ('-' in str_val1) or ('-' in str_val2):
                raise ValueError
                # return key_str, key_int
            else:
                if (str_val1.isdigit()) and (int(str_val1) > 0):
                    if str_val2.isalpha() and len(str_val2) == 1:
                        key_str = str_val2.lower()
                        key_int = str_val1
                        return key_str, key_int
                    else:
                        raise ValueError
                        # return key_str, key_int
                elif str_val1.isalpha() and len(str_val1) == 1:
                    if (str_val2.isdigit()) and (int(str_val2) > 0):
                        key_str = str_val1.lower()
                        key_int = int(str_val2)
                        return key_str, key_int
                else:
                    raise ValueError
                    # return key_str, key_int
        else:
            raise ValueError
            # return key_str, key_int
    def to_my_list_str(self, str_val1, str_val2=None):
        key_str = None
        key_int = None
        if isinstance(str_val1, str) and (str_val2 is None):
            if ('.' in str_val1) or ('-' in str_val1):
                raise ValueError
                # return key_str, key_int
            elif len(str_val1) == 1:
                raise ValueError
                # return key_str, key_int
            else:
                num_value = re.findall(r'\d+', str_val1)
                match_value = re.findall(r'(?i)[a-z,A-Z]+', str_val1)
                match_value = ''.join(match_value)
                if len(match_value) == 1:
                    key_str = match_value.lower()
                    key_int = int("".join(list(map(str, num_value))))
                    return key_str, key_int
                else:
                    raise ValueError
                    # return key_str, key_int
        else:
            raise ValueError
            # return key_str, key_int
    def str_my_list(self, key_str, key_int):
        if key_str is None and key_int is None:
            new_key = None
        else:
            new_key = str(key_str) + str(key_int)
        return new_key
    def my_new_key(self, key):
        if isinstance(key, tuple) or isinstance(key, str):
            if isinstance(key, tuple):
                key_str, key_int = self.to_my_list_tuple(str_val1=key[0], str_val2=key[1])
                new_key = self.str_my_list(key_str=key_str, key_int=key_int)
                return new_key
            elif isinstance(key, str):
                key_str, key_int = self.to_my_list_str(str_val1=key, str_val2=None)
                new_key = self.str_my_list(key_str=key_str, key_int=key_int)
                return new_key
        else:
            raise TypeError
    def __setitem__(self, key, value):
        new_key = None
        new_key = self.my_new_key(key)
        if new_key is None:
            raise ValueError
        else:
            self.my_list[new_key] = value
            if new_key in self.my_set_key:
                pass
            else:
                self.my_set_key.add(new_key)
    def __getitem__(self, key):
        new_key = self.my_new_key(key)
        if new_key in self.my_list:
            return self.my_list[new_key]
        else:
            return None
    def __iter__(self):
        self.froz_set = frozenset(self.my_set_key)
        for key in self.my_list:
            yield key
    def __delitem__(self, key):
        new_key = self.my_new_key(key)
        # del self.my_set_key[new_key]
        del self.my_list[new_key]
    def __contains__(self, key):
        new_key = self.my_new_key(key)
        # print(new_key in self.my_list)
        return new_key in self.my_list

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

Обращение, как бы можно обойти:
     def __getitem__(self, key):
        try:
            new_key = self.my_new_key(key)
            if new_key in self.my_list:
                return self.my_list[new_key]
            else:
                return None
        except:
            new_key = self.__getattr__(self, key)

А когда записываю, то надо добавить реализацию через __setattr_, а try: exept - даст обработку только ключей с . и потерю . Значит надо или через get, или может как-то переносить словарь…. еще не додумала до конца.



Офлайн

#9 Дек. 23, 2021 15:38:18

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10010
Репутация: +  857  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

FishHook
задача была по крайней мере сформулирована следующим образом
Еленочка
__setitem__ и __setattr__ в одном классе
А если бы она спросила “как правильно спрыгнуть с девятого этажа?”, ты бы тоже стал ей советовать белые тапочки надеть? Нахуа?

Вот она код выложила, вот видно стало хорошо, что процедурная парадигма там пропущена вообще. Типа ООП заменило всё. А ведь это не так. ООП - это продолжение структурной парадигмы, а не её замена. А структурная парадигма - продолжение процедурной парадигмы, а не её замена. Поэтому это всё надо учить сначала, чтобы не писать вот такое. Такой трэш. Блок-схемки надо учить.

Еленочка
  
match_value = re.findall(r'(?i)[a-z,A-Z]+', str_val1)
Это ещё что такое? Может, подучить что-нибудь сначала, почитать там? Если ты берёшь и маленькие, и большие буквы, то зачем там флажок игнорирования регистра? А запятая вот эта умиляет просто. Да… надо учиться, а то так и будешь херню смешную писать.

Еленочка
  
key_int = int("".join(list(map(str, num_value))))
Хм, интересно, для чего здесь list используется? Для того, чтобы сказать, что масло оно масляное?

Вот, смотри
  
>>> ''.join(map(str, range(5)))
'01234'
>>>

Еленочка
  
if isinstance(key, tuple) or isinstance(key, str):
О, ещё куча операций.

Вот так надо
  
>>> isinstance('a', (tuple, str))
True
>>> isinstance((1, 2), (tuple, str))
True
>>> isinstance(1, (tuple, str))
False
>>>

Элементарнейшие вещи не освоены.



Отредактировано py.user.next (Дек. 23, 2021 15:53:40)

Офлайн

#10 Дек. 23, 2021 17:47:58

xam1816
Зарегистрирован: 2020-05-11
Сообщения: 1393
Репутация: +  124  -
Профиль   Отправить e-mail  

__setitem__ и __setattr__ в одном классе

Еленочка
Добрый день. Задача учебная.
У вас эти задачи без теории?Имеется ввиду к ним прилагается теоретическая часть или какие-нибудь теги для поиска

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version