Уведомления

Группа в Telegram: присоединиться | Jabber-конференция сообщества: pythonua@conference.jabber.ru

#1 Май 16, 2018 06:11:30

irgit
Зарегистрирован: 2018-02-04
Сообщения: 18
Репутация: +  0  -
Профиль   Отправить e-mail  

Говнокод. Научите изяществу

Друзья. Только недавно начал писать, поэтому методы превращаются в говнокод. Научите пожалуйста, с самого начала - писать изящно и красиво. Если не сложно, покажите более правильную реализацию, укажите ошибки, например этого кода (https://github.com/tarbagan/vk_parse_group_inregion/blob/master/vk_get_group.py):


 #!/usr/bin/python
# -*- coding: utf-8 -*-
from urllib.request import urlopen
from urllib.parse   import quote
import json
import time
import csv
q = quote("Поисковый запрос") #Например Новости. Можно поставить пробел " ", тогда найдет все группы у которых не менее двух слов
token = "TOKEN"
def get_multicity(): #Получаем населенные пункты вашего региона. Вместо 1157049& укажите свой индификатор региона ВК
    url = "https://api.vk.com/method/database.getCities.json?region_id=1157049&country_id=1&count=200&access_token=" + token + "&v=5.52"
    response = urlopen(url)
    data = response.read()
    city = json.loads(data)
    return city
def multi_search():
    gr = []
    for st in get_multicity()["response"]["items"]:
        stid = str((st["id"]))
        namecity = str((st["title"]))
        url2 = "https://api.vk.com/method/groups.search.json?q="+q+"&city_id="+stid+"&count=1000&sort=0&access_token="+ token +"&v=5.52"
        response2 = urlopen(url2)
        data2 = response2.read()
        group = json.loads(data2)
        time.sleep(0.5)
        if group ["response"]["count"] !=0:
            for pars in group["response"]["items"]:
                pars['city'] = namecity
                grid = str(pars['id'])
                print( "Получаем: %s" % namecity )
                url3 = "https://api.vk.com/method/groups.getMembers.json?group_id="+grid+"&access_token=" + token + "&v=5.52"
                response3 = urlopen(url3)
                data3 = response3.read()
                folower = json.loads(data3)
                fl = (folower["response"]["count"])
                pars['follower'] = fl
                pars['url'] = (str("https://vk.com/club"+grid))
                gr.append(pars)
                time.sleep(0.5)
    return gr
def save_cvs(): #Сохраняем результат в файл CVS
    datagroup = multi_search()
    with open( "d:/AnacodaProgect/group.csv", "w", encoding='utf-8' ) as file: #Укажите путь к ашему файлу cvs
        fieldnames = ['id', 'name', 'is_closed', 'type', 'photo_200', 'city', 'follower', 'url']
        writer = csv.DictWriter( file, fieldnames=fieldnames )
        writer.writeheader()
        for sgroup in datagroup:
            idg = (sgroup["id"])
            nmg = (sgroup["name"])
            icg = (sgroup["is_closed"])
            tyg = (sgroup["type"])
            phg = (sgroup["photo_200"])
            cig = (sgroup["city"])
            flg = (sgroup["follower"])
            urg = (sgroup["url"])
            writer.writerow({'id': idg, 'name': nmg, 'is_closed': icg, 'type': tyg, 'photo_200': phg, 'city': cig, 'follower': flg, 'url': urg} )
save_cvs()
print ("ok")

Отредактировано irgit (Май 16, 2018 06:13:48)

Офлайн

#2 Май 16, 2018 09:51:21

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

Говнокод. Научите изяществу

irgit
 def save_cvs(): #Сохраняем результат в файл CVS
CSV - comma separated values

irgit
Научите пожалуйста, с самого начала - писать изящно и красиво.
Нельзя быстро научиться. Нужно планомерно читать хорошие книги одну за одной, там будет много кодов в правильном виде. Их стиль и будешь копировать, пока он не усвоится. Чем больше будешь писать, тем он легче будет писаться. А потом ты вообще забудешь, что ты научился писать код, тебе будет казаться, что ты с рождения его умеешь писать. Как мы книжки читаем - нам кажется, что мы эти буквы, которые видим, всегда знали. Мы забыли то состояние, когда не знали ни одной буквы.

Что у тебя тут? Глобальная переменная? Значит, ты должен поиметь проблемы из-за глобальных переменных, чтобы для себя самого уяснить, что лучше потрудиться лишний раз и от них полностью избавиться через немогу. То есть для этого тоже нужно мотивацию иметь - знать, что будут вполне конкретные проблемы, если так оставить.

У тебя в коде мало переменных. То есть код пришлёпнут к конкретным каким-то строкам, числам, структурам данных. Стоит только vk.com изменить адресацию у себя внутри, как твой код не только перестанет работать, но и его придётся полностью писать заново, чтобы восстановить. А должно быть так, что формат адреса должен где-то храниться, где его можно быстро поменять и вся программа сразу переключится на новый вид адреса и всё будет работать. Это называется абстрагирование. То есть код должен быть общим, а конкретные детальки должны к нему просто подключаться в одном небольшом месте.

Много книг надо прочитать, причём правильных (есть и водяные книги, где на кучу страниц одна вода бесполезная), в которых всякие технологие программирования раскрываются.
Ты даже если весь Python выучишь наизусть, это тебе ничего не даст, потому что технологии программирования питон тебе не сообщит. Язык не учит программировать. Язык - это просто кисти и краски. А чтобы рисовать картины ими, надо изучать правила и законы изобразительного искусства. Можно кучу кисточек выучить и что дальше? Ничего само не нарисуется.

Основной признак хренового кода - это когда ты сам открываешь его потом, через год, а понять его не можешь, забыл всё из него, а на отладку и новые прогоны времени нет. То есть код не читается, его надо изучать там, проверять. Вот у тебя маленький код, а когда программа нормальная, много фич там, там кода дофига и ты его просто прочитать даже не можешь физически, даже если он читается. Соответственно, там должно быть всё поделено на автономные кусочки (модульность программы). Это тоже надо всё уметь делать, но сначала надо узнать теорию, как это вообще делается. Сам тоже не догадаешься.


tags: learning



Отредактировано py.user.next (Май 16, 2018 10:00:41)

Офлайн

#3 Май 16, 2018 11:37:34

irgit
Зарегистрирован: 2018-02-04
Сообщения: 18
Репутация: +  0  -
Профиль   Отправить e-mail  

Говнокод. Научите изяществу

py.user.next
Нельзя быстро научиться. Нужно планомерно читать хорошие книги одну за одной, там будет много кодов в правильном виде. Их стиль и будешь копировать, пока он не усвоится. Чем больше будешь писать, тем он легче будет писаться. А потом ты вообще забудешь, что ты научился писать код, тебе будет казаться, что ты с рождения его умеешь писать. Как мы книжки читаем - нам кажется, что мы эти буквы, которые видим, всегда знали. Мы забыли то состояние, когда не знали ни одной буквы.

Что у тебя тут? Глобальная переменная? Значит, ты должен поиметь проблемы из-за глобальных переменных, чтобы для себя самого уяснить, что лучше потрудиться лишний раз и от них полностью избавиться через немогу. То есть для этого тоже нужно мотивацию иметь - знать, что будут вполне конкретные проблемы, если так оставить.

У тебя в коде мало переменных. То есть код пришлёпнут к конкретным каким-то строкам, числам, структурам данных. Стоит только vk.com изменить адресацию у себя внутри, как твой код не только перестанет работать, но и его придётся полностью писать заново, чтобы восстановить. А должно быть так, что формат адреса должен где-то храниться, где его можно быстро поменять и вся программа сразу переключится на новый вид адреса и всё будет работать. Это называется абстрагирование. То есть код должен быть общим, а конкретные детальки должны к нему просто подключаться в одном небольшом месте.

Много книг надо прочитать, причём правильных (есть и водяные книги, где на кучу страниц одна вода бесполезная), в которых всякие технологие программирования раскрываются.
Ты даже если весь Python выучишь наизусть, это тебе ничего не даст, потому что технологии программирования питон тебе не сообщит. Язык не учит программировать. Язык - это просто кисти и краски. А чтобы рисовать картины ими, надо изучать правила и законы изобразительного искусства. Можно кучу кисточек выучить и что дальше? Ничего само не нарисуется.

Основной признак хренового кода - это когда ты сам открываешь его потом, через год, а понять его не можешь, забыл всё из него, а на отладку и новые прогоны времени нет. То есть код не читается, его надо изучать там, проверять. Вот у тебя маленький код, а когда программа нормальная, много фич там, там кода дофига и ты его просто прочитать даже не можешь физически, даже если он читается. Соответственно, там должно быть всё поделено на автономные кусочки (модульность программы). Это тоже надо всё уметь делать, но сначала надо узнать теорию, как это вообще делается. Сам тоже не догадаешься.

Благодарю за ответ, он сподигнул меня на более глубокое осмысление Дзнен. Попробую переписать данный код согласно некой философии структурирования. Что посоветуете почитать?

Отредактировано irgit (Май 16, 2018 11:38:19)

Офлайн

#4 Май 16, 2018 11:50:45

irgit
Зарегистрирован: 2018-02-04
Сообщения: 18
Репутация: +  0  -
Профиль   Отправить e-mail  

Говнокод. Научите изяществу

 def get_multicity():
    url = "https://api.vk.com/method/database.getCities.json?region_id=1157049&country_id=1&count=200&access_token=" + token + "&v=5.52"
    response = urlopen(url)
    data = response.read()
    city = json.loads(data)
    return city

Подскажите пожалуйста. Этот фрагмент кода лучше записывать как класс (class) или как функцию (def)? Не могу понять, в чем принципиальная разница? Можно ли его упростить? Можно ли его оптимизировать? Как бы его написал гуру питона?

Офлайн

#5 Май 16, 2018 13:35:14

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

Говнокод. Научите изяществу

irgit
Этот фрагмент кода лучше записывать как класс (class) или как функцию (def)?
Тут надо сделать подачу ссылки снаружи
 def get_multicity(url):

irgit
Не могу понять, в чем принципиальная разница?
Функция - это алгоритм, принимающий что-то на вход и выдающий что-то на выход.
Объект - это несколько функций, объединённых в группу, которые работают над одним общим набором данных.
Класс - это шаблон для создания объектов.

Например, класс list описывает такие объекты, у которых есть внутреннее содержимое и методы append(), pop(), insert(), которые работают с этим внутренним содержимым.
  
>>> lst = []
>>> lst
[]
>>> lst.append(1)
>>> lst.append(2)
>>> lst.append(3)
>>> lst
[1, 2, 3]
>>> lst.pop()
3
>>> lst.pop()
2
>>> lst.pop()
1
>>> lst
[]
>>>
Таким образом при одном описании класса списка у двух разных объектов-списков, созданных по этому описанию, будет разное внутреннее содержимое. Методы одного списка работают только с его содержимым, а методы другого списка работают только с его содержимым. То есть класс один, а объектов с его помощью можно создавать много и они все будут индивидуальными.

Понятие исполнителя тебе нужно узнать. Это можно прочитать в книжке “Программирование для математиков” Кушниренко-Лебедев

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

Пример исполнителя TwoLists, который хранит внутри себя два исполнителя list и управляет ими таким образом, чтобы перемещать исполнители int из одного в другой.
  
>>> class TwoLists:
...     
...     def __init__(self):
...         self.lst1 = [1, 2, 3]
...         self.lst2 = [4, 5, 6]
...     
...     def move(self):
...         self.lst2.append(self.lst1.pop())
...     
...     def show(self):
...         return self.lst1, self.lst2
... 
>>> two_lists = TwoLists()
>>> 
>>> two_lists.show()
([1, 2, 3], [4, 5, 6])
>>> 
>>> two_lists.move()
>>> two_lists.show()
([1, 2], [4, 5, 6, 3])
>>> 
>>> two_lists.move()
>>> two_lists.show()
([1], [4, 5, 6, 3, 2])
>>>
Исполнитель TwoLists управляет двумя исполнителями list определённым образом, известным только ему. Снаружи, когда мы вызываем методы move() и show(), мы не знаем, что эти методы делают внутри. Также, когда мы используем объект TwoLists, мы не знаем, что внутри TwoLists хранятся исполнители list. В этом фишка исполнителей - они хранят в себе семантику, а наружу предоставляют только интерфейс для управления ими.

Исполнители можно делать разные, с любой семантикой и любыми интерфейсами. Список - хороший, наглядный пример исполнителя. Мы не знаем, как он устроен, но мы можем им пользоваться для выполнения задач. Мы можем поместить в него данные и убрать из него данные, при этом мы не знаем, как он их хранит внутри себя, мы не знаем, какими исполнителями он для этого пользуется внутри себя.

Дерево исполнителей может приводить к очень забубённому поведению, которое сразу так и не осмыслишь. Но при этом можно гарантировать, что всё выполнится ими точно до миллиметра.



Отредактировано py.user.next (Май 16, 2018 13:57:16)

Офлайн

#6 Май 16, 2018 15:01:57

PEHDOM
Зарегистрирован: 2016-11-28
Сообщения: 700
Репутация: +  146  -
Профиль   Отправить e-mail  

Говнокод. Научите изяществу

irgit
Подскажите пожалуйста. Этот фрагмент кода лучше записывать как класс (class) или как функцию (def)?
ИМХО класс тут как зайцу пятая нога.
достаточно познавательный перевод статьи, почитайте там как раз по ходу про ваш случай: https://habr.com/post/140581/
Признак того, что объект не должен быть классом — если в нём всего 2 метода, и один из них — инициализация, __init__. Каждый раз видя это, подумайте: «наверное, мне нужна просто одна функция».

Офлайн

#7 Май 16, 2018 20:54:01

vic57
Зарегистрирован: 2015-07-07
Сообщения: 767
Репутация: +  105  -
Профиль   Отправить e-mail  

Говнокод. Научите изяществу

irgit
Можно ли его упростить? Можно ли его оптимизировать?
как коллеги сказали - данные нужно отделять от функции.
и у тебя нет обработки ошибок совсем
примерно так
 import requests
DATA = {}
DATA['req']='https://api.vk.com/method/database.getCities.jsonregion_id=1157049&country_id=1&count=200&access_token='
DATA['token'] = 'TOKEN'
DATA['version'] = '&v=5.52'
def get_multicity(url=None):
    try:
        r = requests.get(url,timeout=5)
    except Exception as e:
        return {'ERROR':str(e)}
    else:
        return r.json()
ret = get_multicity(DATA['req'] + DATA['token'] + DATA['version'])
print(ret)

Отредактировано vic57 (Май 16, 2018 20:59:34)

Офлайн

#8 Май 16, 2018 20:56:39

vic57
Зарегистрирован: 2015-07-07
Сообщения: 767
Репутация: +  105  -
Профиль   Отправить e-mail  

Говнокод. Научите изяществу

можно еще разбить данные на ключи region_id, country_id и т.д. совершенству нет предела

Офлайн

#9 Май 17, 2018 04:16:20

irgit
Зарегистрирован: 2018-02-04
Сообщения: 18
Репутация: +  0  -
Профиль   Отправить e-mail  

Говнокод. Научите изяществу

py.user.next
Понятие исполнителя тебе нужно узнать. Это можно прочитать в книжке “Программирование для математиков” Кушниренко-Лебедев

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

Спасибо! Скачал, читаю Your text to link here…

Офлайн

#10 Май 17, 2018 04:17:53

irgit
Зарегистрирован: 2018-02-04
Сообщения: 18
Репутация: +  0  -
Профиль   Отправить e-mail  

Говнокод. Научите изяществу

PEHDOM
ИМХО класс тут как зайцу пятая нога.
достаточно познавательный перевод статьи, почитайте там как раз по ходу про ваш случай: https://habr.com/post/140581/

Благодарю, увлекательно)

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version