l = lambda a, b: a + b print l(4, 5) res = sorted([4, -5, 1, -2, -8, 7], cmp=lambda x, y: abs(y) - abs(x)) print resWynik:
9 [-8, 7, -5, 4, -2, 1]
ekstaza, geniusz, przebłysk, olśnienie, półprawdy, półśrodki, przemilczenia, zaćmienia, głupstwa, kłamstewka, oszustwa, hultajstwo, wyrachowanie, nieprawda, nieobiektywność, niepodważalna prawda, nierówność, nieomylność, słuszność, perfekcja, krnąbrność ... niegodziwość
l = lambda a, b: a + b print l(4, 5) res = sorted([4, -5, 1, -2, -8, 7], cmp=lambda x, y: abs(y) - abs(x)) print resWynik:
9 [-8, 7, -5, 4, -2, 1]
gen_expression = (val for val in [1, 2, 3, 4, 7] if val % 2) try: print gen_expression.next() print next(gen_expression) print gen_expression.next() print gen_expression.next() except StopIteration: print 'Dostalem wyjatek'Wynik:
1 3 7 Dostalem wyjatekDrugim rodzajem generatora jest generator function, który wygląda jak zwykła funkcja. Pozwala jednak na korzystanie mechanizmu yield. W momencie, gdy metoda trafi na takie miejsce, jej działanie jest przerywane i zwracana jest kontrola do naszej części kodu.
def gen_fun(arg = 1): num = 0 yield num while True: num += arg yield num yield -num # Zwraca generator object g = gen_fun() print [g.next() for _ in xrange(15)]Wynik:
[0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, 6, -6, 7, -7]Możemy również przekazać jakąś wartość do wnętrza generatora. W tym celu należy skorzystać z metody send(), które tak jak next() wznawia jego działanie. Jeżeli na takim generatorze zawołamy tylko next(), do środka przekazana zostanie wartość None.
def gen(): arg = 1 num = 0 while True: num += arg a = yield num if a is not None: arg = a g = gen() print g.next() print g.next() print g.send(100) print g.next()Wynik:
1 2 102 202
#include <iostream> #include <string> using namespace std; int main() { for (const auto& ch : string("rozciaganie")) cout << ch << " "; cout << endl; return 0; }Wynik:
r o z c i a g a n i e
#include <iostream> #include <vector> using namespace std; int main() { vector<int> v = {1, 2, 4, 6}; auto vit = v.begin(); cout << *vit << endl; return 0; }Drugim ficzerem jest detekcja typu przy pomocy decltype. Na podstawie zadanej zmiennej lub wyrażenia odgaduje typ, który będzie nadany nowej zmiennej. W przypadku wyrażenie, nie dochodzi do ewaluacji, wyciągany jest jedynie zwracany typ. Warto też pamiętać, że jeżeli wsadzimy do decltype zmienną i ujmiemy ją w dodatkowe nawiasy, typ który dostaniemy zawsze będzie referencją, a nowa zmienna będzie musiała być zainicjalizowana. Jeżeli natomiast z nawiasów nie skorzystamy to referencję uzyskamy tylko, gdy sama zmienna będzie typem referencyjnym.
#include <iostream> #include <vector> #include <list> #include <boost/type_index.hpp> using namespace std; list<double>::iterator get_it(list<double> l) { return l.begin(); } int main() { list<double> l = {7.1, 2.3, 4.6}; decltype(get_it(l)) it = get_it(l); // list<double>::iterator it = get_it(l); cout << boost::typeindex::type_id_with_cvr<decltype(it)>().pretty_name() << " " << *it << endl; int i = 879; decltype((i)) var1 = i; // int& var1 = i; cout << boost::typeindex::type_id_with_cvr<decltype(var1)>().pretty_name() << " " << var1 << endl; int& j = i; decltype(j) var2 = i; // int& var2 = i; cout << boost::typeindex::type_id_with_cvr<decltype(var2)>().pretty_name() << " " << var2 << endl; decltype(i) br = 54; // int br = 54; cout << boost::typeindex::type_id_with_cvr<decltype(br)>().pretty_name() << " " << br << endl; return 0; }Wyniki:
std::_List_iterator<double> 7.1 int& 879 int& 879 int 54
int i, *ip = nullptr; // i jest typu int, ip jest wskaźnikiem na int. int* p1, p2; // p1 jest wskaźnikiem na int, p2 jest typu int. int* a, &b = *ip; // a jest wskaźnikiem na int, b jest referencją na wartość // wskazywaną przez ip.A teraz trochę o const. Zawsze jest to dla mnie mylące, przynajmniej po dłuższym okresie czasu, gdy wiedza powolutku wyparowuje.
const int c = 8; // c jest stałą typu int, jego wartość nie może być zmieniona. const int &r = c; // ok, referencja na stały obiekt typu int - mówimy co będziemy mogli // robić przy pomocy referencji - odwołując się do r nie damy rady // zmodyfikować c (chociaż sam w sobie nie jest const). int &r2 = c; // error, referencja na niestały obiekt.Nie ma czegoś takiego jak stałe referencje (z technicznego punktu widzenia), są tylko referencje na stałe. Ponieważ nie można zmusić referencji by wskazywała na inny obiekt w jakimś sensie wszystkie referencje są stałe.
double dval = 3.14; const double *pt = &dval; // ok (tak jak wyżej), ale nie możemy zmieniać dval, przy pomocy ptA teraz co powstanie, gdy const znajdzie się w różnych miejscach? Pewne oznaczenia - cytując za książką:
Używamy terminu top-level const do oznaczenia, że sam wskaźnik jest stały. Kiedy wskaźnik może wskazywać na stały obiekt, odnosimy się do tego jako low-level const
int i = 0; const int c1 = 88; // c1 jest stałym obiektem typu int int const c2 = 99; // (TO SAMO) c2 jest stałym obiektem typu int int *const p1 = &i; // p1 jest stałym wskaźnikiem na obiekt typu int (top-level const). const int ci = 42; // ci jest stałym obiektem typu int (top-level const). const int *p2 = &ci; // p2 jest wskaźnikiem na stały obiekt typu int (low-level). int const *p3 = &ci; // (TO SAMO) p3 jest wskaźnikiem na stały obiekt typu int. const int *const p4 = p2; // p3 jest stałym wskaźnikiem na stały obiekt typu int // (prawy const jest top-level; lewy nie) const int &r = i; // referencja na stały obiekt typu int. // const w typach referencyjnych zawsze jest low-level.W odróżnieniu od referencji, wskaźniki są obiektami, więc mogą być const, co znaczy, że po ustawieniu w momencie inicjalizacji nie mogą na nic innego wskazywać.
#include <iostream> #include <stdio.h> using namespace std; constexpr int get_size() { return 6; } int main() { constexpr int sz = get_size() + 80; // ok, pod warunkiem, że funkcja też jest constexpr. printf("%d", sz); return 0; }I podgląd tego co wyprodukował kompilator (g++ -std=c++17 -S -masm=intel main.cpp). Jak widać w pliku binarnym pojawia się już obliczona wartość (80+6=86).
main: .LFB1824: .cfi_startproc endbr64 push rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp .cfi_def_cfa_register 6 sub rsp, 16 mov DWORD PTR -4[rbp], 86 mov esi, 86 lea rdi, .LC0[rip] mov eax, 0 call printf@PLT mov eax, 0 leave .cfi_def_cfa 7, 8 ret .cfi_endproc