Przerobienie funkcji na bardziej 'funkcyjną'.

0

Opis problemu:
Mam listę organizacji, każda z nich ma listę tzw. środowisk. Mam również ID urządzenia które ma być zarejestrowane w każdym środowisku w każdej organizacji. Normalny kod z pętlami przedstawia się następująco:

organizations = ["org1", "org2", "org3"]
environments = {"org1": ["prod", "test", "dev"],
                "org2": ["prod", "test", "dev"],
                "org3": ["prod", "test", "dev"]}

def getID():
    return "uuid:exampleID"


def get_orgs():
    return organizations


def get_envs(org):
    return environments[org]


def register_id_in_env(uuid, org, env):
    print(uuid + " " + org + " " + env + " registered")


def registerALL():
    orgs = get_orgs()
    for o in orgs:
        envs = get_envs(o)
        for e in envs:
            register_id_in_env(getID(), o, e)

Czy ktoś mógłby mi pomóc w napisaniu implementacji funkcji registerALL() w bardziej funkcyjny sposób, z użyciem map, lambd itp ?
Z góry dziękuję za pomoc.

0

Ok. Przepraszam za to pytanie. Za szybko je zadałem :(
Napisałem coś takiego :

map(lambda org: map(lambda env: register_id_in_env(getID(), org, env), get_envs(org)), get_orgs())

Czy uważacie że to jest OK ?

1

Jeśli funkcja ma być funkcyjna to z definicji nie może być tam żadnych skutków ubocznych więc nie może być printowania czegokolwiek, bo printując wywalasz rzeczy na standardowe wyjście, co jest skutkiem ubocznym. Funkcja może zwracać jakąś wartość, ale nie powinna niczego zmieniać ani robić jakichkolwiek skutków ubocznych, inaczej z definicji nie będzie to już programowanie funkcyjne (nie znaczy, że będzie to koniecznie złe, po prostu nie będzie to zgodne z paradygmatem funkcyjnym).

registerALL()

dlaczego registerALL a nie register_all?

Czy uważacie że to jest OK ?

strasznie czytelne takie długie linijki....

2
map(lambda org: map(lambda env: register_id_in_env(getID(), org, env), get_envs(org)), get_orgs())

Wiem że "map" kojarzy się z funkcyjnością, ale rzadko jest dobrym pomysłem w pythonie - bo robi dokładnie tego co list comprehension. Po zmianie wyglądałoby to mniej-więcej tak:

[[register_id_in_env(getID(), org, env) for env in get_envs(org)] for org in get_orgs()]

...ale tak czy inaczej, ten kod nie ma nic wspólnego z funkcyjnością (ani moja ani Twoja wersja) - programowanie funkcyjne opiera się na "czystych" funkcjach i braku efektów ubocznych, a registerAll jest czysto imperatywną funkcją mutującą stan.

Funkcyjne rozwiązanie tego problemu wyglądałoby tak, że funkcja register_all() dostaje listę organizacji, i zwraca listę rejestracji - bez żadnych zmian w globalnym stanie. Nie mówię żeby tak to przepisać, być może przepisanie tego w taki sposób nie pasuje do Twojego problemu/programu - nie wszystko musi być funkcyjne :P.

Tak czy inaczej wersja z mapami jest mniej czytelna od wersji z pętlami i nie polecam tego pisać w ten sposób.

0

Zgadzam się że bardziej moje pytanie bardziej powinno brzmieć : jak napisać one-linera niż coś tam z funkcyjnym.

Dzięki serdeczne za odpowiedzi.

2

Najważniejsze, żeby było czytelnie, a bardzo często kilka krótkich linijek jest bardziej czytelnych od jednej długiej.

Swoją drogą zamiast pisać:

    orgs = get_orgs()
    for o in orgs:
        envs = get_envs(o)
        for e in envs:
            register_id_in_env(getID(), o, e)

możesz napisać:

    for o in get_orgs():
        for e in get_envs(o):
            register_id_in_env(getID(), o, e)

(wywalić niepotrzebne przypisania do zmiennych) i już będzie bardziej czytelne...

no i nie rozumiem czemu getID czy registerALL z uppercase na końcu, przecież Python to nie PHP, żeby każdą funkcję pisać w innej konwencji nazewniczej (szczególnie tak dziwnej jak fooBAR).

1 użytkowników online, w tym zalogowanych: 0, gości: 1