1. Python / Говнокод #17263

    −117

    1. 001
    2. 002
    3. 003
    4. 004
    5. 005
    6. 006
    7. 007
    8. 008
    9. 009
    10. 010
    11. 011
    12. 012
    13. 013
    14. 014
    15. 015
    16. 016
    17. 017
    18. 018
    19. 019
    20. 020
    21. 021
    22. 022
    23. 023
    24. 024
    25. 025
    26. 026
    27. 027
    28. 028
    29. 029
    30. 030
    31. 031
    32. 032
    33. 033
    34. 034
    35. 035
    36. 036
    37. 037
    38. 038
    39. 039
    40. 040
    41. 041
    42. 042
    43. 043
    44. 044
    45. 045
    46. 046
    47. 047
    48. 048
    49. 049
    50. 050
    51. 051
    52. 052
    53. 053
    54. 054
    55. 055
    56. 056
    57. 057
    58. 058
    59. 059
    60. 060
    61. 061
    62. 062
    63. 063
    64. 064
    65. 065
    66. 066
    67. 067
    68. 068
    69. 069
    70. 070
    71. 071
    72. 072
    73. 073
    74. 074
    75. 075
    76. 076
    77. 077
    78. 078
    79. 079
    80. 080
    81. 081
    82. 082
    83. 083
    84. 084
    85. 085
    86. 086
    87. 087
    88. 088
    89. 089
    90. 090
    91. 091
    92. 092
    93. 093
    94. 094
    95. 095
    96. 096
    97. 097
    98. 098
    99. 099
    100. 100
    class DictOfLists(defaultdict): # it's possible to use dict instead 
        
        def __init__(self, *args, **kwds):
            __args=self.__check_args(*args)
            self.__check_kwds(**kwds)
            defaultdict.__init__(self,(lambda:[]), *__args, **kwds)
            # dict.__init__(self, *__args, **kwds)
    
        def __is_valid_item(self,item):
            if len(item)==2 and not hasattr(item[0],"__iter__") and hasattr(item[1],"__iter__"):
                return True
            return False
        
        def __check_args(self,*args):
            if len(args)>1:
                if type(args) == tuple and self.__is_valid_item(args):
                    return [args,]  # tuple of key and list of values
                else:
                    raise TypeError("Item of %s must be a tuple of (key,IterableValue) but %s=%s is not"%\
                                            (self.__class__.__name__, 
                                             args.__class__.__name__,
                                             repr(args)))
            if len(args) != 1: return args
            
            if isinstance(args[0], DictOfLists): return args
            
            if hasattr(args[0],"__iter__"): 
                if len(args[0]) == 0: return args # empty iterator
    
                items = args[0].items() if type(args[0]) == dict else args[0]
                if self.__is_valid_item(items):
                    return [args,]  # tuple of key and list of values
                for v in items:
                    if not (type(v) == tuple and len(v)==2):
                        raise TypeError("Item of %s must be a tuple of (key, IterableValue) but %s=%s is not"%\
                                            (self.__class__.__name__, 
                                             v.__class__.__name__,
                                             v))   
                    if not hasattr(v[1],"__iter__"):
                        raise TypeError("Value of %s must be iterable but %s(%s) is not"%\
                                            (self.__class__.__name__, 
                                             v[1].__class__.__name__,
                                             repr(v[1])))
                        
            else: raise TypeError(" %s must be initialized by {},[],() or %s but %s is not"%\
                                      (self.__class__.__name__, 
                                       self.__class__.__name__, 
                                       args[0].__class__.__name__))
            return args
        
        def __check_kwds(self, **kwds):
            for v in kwds.itervalues():
                if not hasattr(v,"__iter__"):
                            raise TypeError("Value of %s must be iterable but %s(%s) is not"%\
                                        (self.__class__.__name__, 
                                         v.__class__.__name__,
                                         repr(v)))
        def walk(self):
            for k, v in self.iteritems():
                for x in v:
                    yield k, v, x
            raise StopIteration
    
        def __setitem__(self, *args, **kwargs):
            self.__check_args(*args)
            self.__check_kwds(**kwargs)       
            return dict.__setitem__(self, *args, **kwargs)
        
        def update(self, *args, **kwds):
            _args=self.__check_args(*args)
            self.__check_kwds(**kwds)
            dict.update(self,*_args, **kwds)
    
    correct = [ {}, [], (),         # empty iterable
            {'k2':[], 'k22':[]},    # multipe items dict
            [('k3',[]),('k32',[])], # array tuples key list val
            (('k4',[]),('k42',[])), # tuple of tuples key list val
            ('k5',[])               # tuple of key list val
            ]
    strange = [('e0','12'), ('e1','123')]
    
    import inspect
    def init_tester(dict_class,t_array,cs):
        print "\n%s %s %s"%( inspect.currentframe().f_code.co_name, dict_class().__class__.__name__, cs )    
        for i in t_array:
            try:
                print repr(i).ljust(26), repr(dict_class(i)).ljust(74),
                print ' work '.ljust(8)
            except Exception,e:
                print "dosn't work ",
                print e
                continue
        print "------------------------------"
    
    if __name__ == '__main__': 
       
        init_tester( DictOfLists, correct, "correct")
        init_tester( dict, correct, "correct")
        init_tester( DictOfLists, strange, "strange")
        init_tester( dict, strange, "strange")

    Вот такой вот словарь, значениями элементов которого могут быть только списки. В принципе легко его доделать, чтобы знаечениями были все iterable, но не строки. Кроме этого, он внимательнее проверяет агрументы. Например если ему послать ('k5',[]), он воспримет это как: k5 - key, [] - value. Build-in dict например воспринимает ('12','34') как 1 - key, 2 - value, 3 - key, 4 - value. Соответственно если ему послать ('12','345'), он ругнется. Мне показалось, что это немного странное поведение, трактовать 2-х символьные строки, как key-value. Покритикуйте please. В том числе "стиль" и "красоту".

    Запостил: apgurman, 05 Декабря 2014

    Комментарии (57) RSS

    • а у этого всего есть какая-либо цель? где какую проблему решает?
      Ответить
      • Решает проблему свободного времени автора.
        Ответить
      • Я уже написал. Мне не нравится что: Build-in dict например воспринимает ('12','34') как 1 - key, 2 - value, 3 - key, 4 - value. Соответственно если ему послать ('12','345'), он ругнется. Мне показалось, что это немного странное поведение, трактовать 2-х символьные строки, как key-value.
        Ответить
        • а. это потому что строки в питоне такие загадочные?
          Ответить
          • Тупо потому, что на туплах тоже работает for ... in, а на строках - оператор [].
            Ответить
            • Я не берусь судить что тупо что нет, я просто исправил это для себя в этом словаре чтобы быть уверенным что он будет всегда работать в нужном мне контексте. Контекст простой должен быть ключ и значение в виде списка. Сложные проверки при создании словаря нужны чтобы случайно кто-то не впихнул туда при инициализации не список а какой-нибудь стринг. Сложно получилось потому что стандартные dict и defaultdict не делают эту сложную работу. Я ее сделал раз и теперь всю жизнь буду использовать без боязни. Если кто может это упростить найти ошибки или еще что посоветовать. С удовольствием приму совет. Только без потери функциональности. То есть точно нельзя разрешать инициализировать и добавлять в словарь, что-либо кроме итерабле и стринги в моем случае не есть итерабле. Я столько раз возился с ошибками вызванными тем, что питон такй гибкий. Что хочется его немного ужесточить, хотябы в этом конкретном случае.
              Ответить
              • >чтобы случайно кто-то не впихнул туда при инициализации не список а какой-нибудь стринг.
                Ответил в другом треде. Так блин тупо проверь на isinstance(param, basestring)
                Ответить
                • s-a--m, там не только на стринг нужно проверять. Ты напиши сам, тогда поймешь . А то любишь из пустого в порожнее по десять раз переливать. Пораскинь мозгами, прежде чем критиковать или советы давать. Ну ведь долго же все это тебе разжевывать. Там же и тест кейсы есть Что еще нужно?
                  Ответить
                  • > Там же и тест кейсы есть
                    Проблема с передачей тупла вместо списка - самое настоящее ССЗБ: ты нарушил контракт какой-то из своих функций. Так что смирись с гибкостью питона, пиши докстринги, соблюдай описанные в них контракты и делай тест кейсы в других местах. А твой класс ненужен.

                    P.S. Ну либо перелезь на более строгий язык типа c#.
                    Ответить
                    • Он нужет мне. Я не говорил, что он нужен всем. Он нужен и удобен для большого количества задач. Не нравится не ешь)) Я не полезность его просил пообсуждать
                      Ответить
                      • > Я не полезность его просил пообсуждать
                        У нас тут свобода слова. Что хотим, то и обсуждаем. Одно время отношения Лура и Кузи обсуждали в теме про SQL иньекции в PHP...

                        С требованиями милости просим на платные сервисы code review.
                        Ответить
                        • Да пожалуйста трепись. Надеюсь тут не все п****болы.
                          Ответить
                        • Расскажите про Гуру и Кузю
                          Ответить
                          • они жили долго и счастливо, пока не умерли в один день
                            Ответить
                            • >они жили долго и счастливо
                              Пока Он не познакомил Её с флюент-интерфейсом.
                              Ответить
                      • Вступлюсь за борманда - он обсуждает не полезность, а что в питоне утиная типизация by design. А в следующий раз, выкладывая код с просьбой предложить, для начала прямо в комментарии в коде укажи, что он должен делать.
                        Ответить
                        • s-a--m, я как пытался указал. Может не достаточно подробно, но старался. Остальное, надеался, будет понятно из кода. Тем более, что тут вроде как не п****болы должны были быть, а ВОЛКИ от Питона. И вроде как, достаточно адекватно и вежливо формулирую ход своих мыслей, приведших вот именно к такой реализации. В оправдвние местным п****болам ВОЛКАМ могу сказать, что получилось очень даже продуктивное обсуждение. Не то чтобы очень много нового узнал, но много того что не заметил сразу, вы все вместе помогли найти. СПАСИБО всем. Надеюсь на дальнейшее продуктивное общение.
                          Ответить
                          • ВОЛКОВ я здесь не замечал,

                            >Остальное, надеался, будет понятно из кода.
                            Все еще непонятно, что должен делать класс, и что из этого не может стандартная библиотека.
                            Ответить
                  • Слушай, то ты выкладываешь, чтобы тебе советы давали, то тебе советы не давай. Не выкладывай тогда это сюда вообще - и все будут счастливы.
                    Ответить
    • Вообще просто обертка чтобы проще был работать Такие словари часто нужны
      Ответить
      • http://ideone.com/i4y20A - ни со вторым ни третьим не работает.
        Ответить
        • Ничего не понял. С каким вторым и каким третьим?
          Ответить
          • python2 и python3 оба ругаются на синтакс.
            Ответить
            • Мой 2.7 не ругается. Я обязательно проверю. Вы сами то видите что-либо странное с синтаксисом? Эта часть кода просто для тестирования. Прямого отношения к словарю значения не имеет.
              Ответить
              • > Вы сами то видите что-либо странное с синтаксисом?

                Как перловщику, мне весь питон видится странным.
                Ответить
                • А мне казалось, что матёрого перловщика уже ничем не удивить...

                  А ошибка там из-за того, что ты запустил на питоне 3.х, (а для 2.х там не хватает строчки с импортом).

                  http://ideone.com/W00KYy
                  Ответить
                  • > А мне казалось, что матёрого перловщика уже ничем не удивить...

                    Не рожал. Природа не угодила - мужиком родился. Как следствие "матёрым" по определению быть не могу.

                    Да и в перле таких проблем нет, так как там строки есть просто строки. И только если попросить - списки.
                    Ответить
                    • Строки тут ничем не виноваты, см. выше. Виноват только ОП, который додумался отдать в конструктор dict'а тупл (key, val) вместо списка из туплов [(key, val)].

                      > Природа не угодила - мужиком родился.
                      О_о. http://ru.wiktionary.org/wiki/матёрый
                      Ответить
                      • > > Природа не угодила - мужиком родился.
                        > О_о. http://ru.wiktionary.org/wiki/матёрый

                        странно. "матёрый" == "мать" == "рожамшая". какое нелогичное слово.
                        Ответить
                    • В перле другие проблемы - юникод и нахуйненужность.
                      Ответить
                • что тут сказать? Читайте только пЁрлы))
                  Ответить
    • def walk(self):
              for k, v in self.iteritems():
                  for x in v:
                      yield k, v, x
              raise StopIteration

      Зачем последняя строка?
      Ответить
      • Вы правы в данном контексте эта строка аналогично просто return. Просто так написалось.
        Ответить
        • return из елды невозможен, разве нет? Вроде можно
          Ответить
          • Возможен, но только без параметров.
            Ответить
            • Точно.
              SyntaxError: 'return' with argument inside generator

              А почему, кстати?
              Ответить
    • Такой код получается когда руки чешутся а голова не работает.
      Ответить
      • А что-то более аргументированное есть? Что-то типа примера, как бы Вы это "элегантнее" сделали. Мы же здесь собрались не для того, чтобы сказать "да ты тупой мудак", а для того, чтобы сказать: "я бы вот сделал так и так... потому, что так и так". С удовольствием увижу и по достоинству оценю Ваш работающий, элегантный пример.
        Ответить
        • >а у этого всего есть какая-либо цель? где какую проблему решает?
          Ответить
          • Я уже написал. Мне не нравится что: Build-in dict например воспринимает ('12','34') как 1 - key, 2 - value, 3 - key, 4 - value. Соответственно если ему послать ('12','345'), он ругнется. Мне показалось, что это немного странное поведение, трактовать 2-х символьные строки, как key-value.
            Ответить
            • > Build-in dict например воспринимает ('12','34') как 1 - key, 2 - value, 3 - key, 4 - value.
              Полный пример, на котором проявляется бага, можешь кинуть?

              P.S. dict(('12', '34')) что ли? А в чем смысл так писать?
              Ответить
            • Я так догадываюсь, что причина, по которой dict себя так ведет со строками - это не потому, что кто-то так задумал, а результат того, что код использует более общие процедуры (и получается компактнее, без лишних проверок).

              Глядя на это - я не вижу смысла специально предотвращать вышеописаное поведение - вряд ли кто-то специально будет ожидать именно то, или другое поведение от словаря, если его инициализировать с какими-то странными входными данными. И поэтому, все эти проверки кажутся лишними. Я бы максимум написал бы что-нибудь типа:

              def args_validator(args):
                  return all(len(x) == 2 for x in args)

              И этим бы и ограничился.
              Ответить
              • Build-in dict так и поступает А потом сидишь час и разбираешься почему он валится. Мне нужен надежный словарь который ругнется если ему подсунуть вместо списка аргументов, просто строку. Ну всякие полезности типа ldict[new_key].append(new_val), вместо If new_key not in ldict: ldict[new_key]=[]; ldict[new_key].append(new_val); ... тоже радуют. Как кстати здесь код в комменты вставлять?
                Ответить
                • [code]...[/code]
                  Ответить
                • > If new_key not in ldict: ldict[new_key]=[]; Idict[new_key].append(new_val);
                  collections.defaultdict посмотри, тебе понравится. Там твой dict of lists в первом же примере.
                  Ответить
                  • Я от него наследуюсь если ты заметил. Но у меня все равно больше всяких фичей. Мелкие но приятно))
                    Ответить
                • ValueError: dictionary update sequence element #1 has length 3; 2 is required
                  С таким сообщением об ошибке нужно часами сидеть разбираться? Чет мне слухи кажутся сильно преувеличеными.

                  Я не вижу чем этот надежнее встроенного. В чем выражается надежность?

                  ПС. Бессмысленно и даже не совсем правильно проверять так на возможность итерации. Просто это вообще не нужно проверять - если цикл не возможен, то будет соответствующая ошибка со знакомым и понятным описанием. Еще хуже будет, если repr(v) бросит исключение - вот тогда можно будет по-настоящему запутаться.
                  Ответить
                • Может, тебе нужна статическая типизация?

                  Вообще duck typing имеет свои минусы тоже, иной раз опечатаешься, подашь dict вместо set или наоборот, а потом со стектрейса хуеешь.
                  Ответить
            • Так может просто проверять, строка ли параметр?
              Ответить
              • Ты вот просто возими и попробуй, просто напиши код который делает эти проверки. И поймешь, что я очень даже компактно исправил недостатки стандартных словарей. Безусловно недостатки не в глобальном смысле(ибо не хочу обсуждать что там в глобальном смысле), а вот в для данной конкретной задачи. Вместо того, чтобы каждай раз проверять лежит ли в словаре список, а не просто нечно. Я запретил везде, где знал и как умел добавление не списков. Задачка надеюсь понятна.
                Ответить
                • >>поймешь, что я очень даже компактно исправил недостатки стандартных словарей.
                  - так а хуле, может, сразу в стандартную поставку пистона добавить?
                  Ответить
                  • В стандартной поставке Python(а) итак говнокода который стоит выбросить хватает. А стандартный dict стоило бы доработать Там конечно те приблуды что я написал не нужны. Но часть из них, точно спасла бы кучу времени у тысячь программистов особенно у тех, кто ожидает от него логичного, а не "стандарного для Python" поведения.
                    Ответить
      • ))
        Ответить
    • А почему для тестирования юзаешь самопальный велик, а не модуль unittest?
      Ответить
      • Просто было так быстрее. Будет время допишу и юнит тест. Вообще то я всегда самопальным великам доверяю больше. В том числе самопальным великам-словарям))
        Ответить

    Добавить комментарий