{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Algoritmusok Python nyelven\n", "\n", "## 4. Előadás, Objektumorientált programozás 1.\n", "\n", "### 2020. március 5." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Technikai információk\n", "\n", "### Diák elérhetősége:\n", "[damasdigabor.web.elte.hu/teaching](https://damasdigabor.web.elte.hu/teaching)\n", "\n", "Óra kezdés: 14:00" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a=5\n", "def f():\n", " print(a)\n", "f()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a=5\n", "def f():\n", " a=a+1\n", " print(a)\n", "f()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Namespace (névtér)\n", " A namespace a változó nevek és az objektumok közti leképezés. \n", " Pl:\n", " - beépített nevekhez (`abs()`, `sorted()`, `int` stb...) tartozik egy namespace \n", " - globális namespace: ide kerülnek a függvényeken kívül létrehozott változók\n", " - lokális namespece: minden függvény létrehoz egy saját namespacet, először abban keres \n", " \n", " Különböző namespacekben szerepelhet egyező név! " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Ez egy szándékosan zavaróan megírt kód. \n", "a=5 # a globális namespaceben 'a' az 5-re fog mutatni\n", "def foo(a): # ez már egy másik `a`, ami a foo() függvény namespaceben él\n", " print(a+1) # itt a foo()-hoz tartozó 'a'-ra hivatkozunk. \n", " def belsofugveny(a): # ez egy harmadik 'a' változó, ez már a belsofugveny()-hez tartozik\n", " print(a+5); # itt a belsofugveny()-hez tartozó 'a'-ra hivatkozunk. \n", " belsofugveny(a) # itt a foo()-hoz tartozó 'a'-ra hivatkozunk. \n", " \n", "foo(10)\n", "a # itt a globális 'a'-ra hivatkozunk. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Scope\n", "Minden namespacehez tartozik egy scope. A scope a kódnak az a része, ahol a neveket automatikusan abban az adott namespaceben keresi a program." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a=5 #\n", " #\n", "def foo(a): # \n", " print(a+1) # \n", " # \n", " def belsofugveny(a): # \n", " print(a+5); #\n", " #\n", " belsofugveny(a) # \n", " #\n", "foo(10) # \n", "a # " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Hogyan érjük el egy másik namespaceben lévő objektumokat?\n", " - `nonlocal valnev` megmondja, hogy eggyel kintebbi scopeban keressen. (Pontosabban, a \"legutóbbi\" nem lokális használatot keresi)\n", " - `global valnev` megmondja, hogy a globális scopeban keressen. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def scope_test():\n", " def do_local():\n", " spam = \"local spam\"\n", "\n", " def do_nonlocal():\n", " nonlocal spam\n", " spam = \"nonlocal spam\"\n", "\n", " def do_global():\n", " global spam\n", " spam = \"global spam\"\n", "\n", " spam = \"test spam\"\n", " do_local()\n", " print(\"lokális értékadás után:\", spam)\n", " do_nonlocal()\n", " print(\"nonlocal kulcsszó után:\", spam)\n", " do_global()\n", " print(\"global kulcsszó után:\", spam)\n", "\n", "scope_test()\n", "print(\"globális scopeban:\", spam)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A másik lehetőség, hogy megadjuk, hogy melyik namespaceben kell keresni. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import math\n", "math.pi # a math modul namespaceben keresi a pi nevű változót" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vajon ezeknél mit történik?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a=5\n", "def f():\n", " print(a)\n", " a=a+1\n", "#f()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "l=[1,2,3]\n", "def f():\n", " l.append(\"matek\")\n", " print(l)\n", "f()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Programozási paradigmák\n", "Sokféle van, például:\n", " - Procedurális\n", " - Funckionális\n", " - Objektumorientált \n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Példa: Főzés vs matek vs autók" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mikor melyiket válasszuk? " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Python\n", " - többféle stílusban is lehet használni, a fentiek mindegyikét tudja többé kevésbé\n", " - sokszor vegyesen is használjuk\n", " - erősen támogatja az objektumorientált paradigmát. Minden objektum! \n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import random\n", "def foo():\n", " pass\n", "[int,bool,foo,random] " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Objektumorientált programozás\n", "\n", "- Osztályok: A programot objektumok köré szervezzük. Minden objektum tartalmaz adatokat és metódusokat, amik az adatokat kezelik. \n", "- Öröklődés (Inheritance): Specifikusabb objektumokat hozhatunk létre korábbiak, melyek öröklik a korábbiak tulajdonságait\n", "- Egységbezárás (Encapsulation): Az összetartozó adatokat és metódusokat együtt kezeljük. \n", "- Absztrakció (Abstraction): A belső működést elrejtjük és csak a szükséges részt mutatjuk meg a felhasználónak. \n", "- Polimorfizmus (Polymorphism): A leszármazottak és példányok felülírhatják a metódusokat. Több osztályból is örököltethetünk egyszerre. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Osztály (class) definiálása\n", "\n", "- `class` kulcsszóval\n", "- példányokat tudunk létrehozni\n", "- minden példánynak van egy saját namespace \n", "- attribútumokat tudunk kapcsolni hozzájuk melyek nem befolyásolják a többi példány attribútumait\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Ember:\n", " pass" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a=Ember()\n", "a.nev=\"Gipsz Jakab\"\n", "a.kor=24\n", "b=Ember()\n", "b.nev=\"Gipsz Jakabné\"\n", "b.kor=22\n", "l=[a,b]\n", "for e in l:\n", " print(e.nev,e.kor)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "type(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Init\n", "- `__init__` függvény automatikusan meghívódik amikor a példány elkészül. \n", " - olyasmi mint egy konstruktor\n", " - nem kötelező\n", "- minden függvény első paramétere maga a példány. Ezt megszokásból `self`-nek hívjuk. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Ember:\n", " def __init__(self,nev,kor):\n", " print(\"Létrejött egy ember\")\n", " self.kor = kor\n", " self.nev = nev\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a=Ember(\"Gipsz Jakab\",24)\n", "b=Ember(\"Gipsz Jakabné\",22)\n", "\n", "l=[a,b]\n", "for e in l:\n", " print(e.nev,e.kor)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Metódusok\n", "\n", "- Függvények az osztály definíciójában\n", "- Automatikusan az első argumentumuk a példány lesz. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Ember:\n", " def __init__(self,nev,kor):\n", " self.kor = kor\n", " self.nev = nev\n", " \n", " def szuletesi_ev(self): # egy paramétert vár\n", " print(2020-self.kor)\n", " \n", " def egykoru(self,other): \n", " print(self.kor==other.kor)\n", " \n", " \n", "a=Ember(\"Gipsz Jakab\",24)\n", "a.szuletesi_ev() # de paraméter nélkül hívjuk meg, mivel az első paraméter maga 'a' lesz \n", "b=Ember(\"Gipsz Jakabné\",22)\n", "a.egykoru(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Metódusok meghívása\n", "Két lehetőség van:\n", "\n", "1. `példány.metódus(param)`\n", "2. `class.metódus(példány, param)`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a=Ember(\"Gipsz Jakab\",24)\n", "a.szuletesi_ev() \n", "Ember.szuletesi_ev(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### `__str__` metódus\n", "Egy speciális metódus, amit arra használunk hogy megadjuk, hogy a `print()` függvény hogyan írja ki az objektumot. \n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Ember:\n", " def __init__(self,nev,kor,lakohely):\n", " self.kor = kor\n", " self.nev = nev\n", " self.lakohely = lakohely\n", " def __str__(self): \n", " return self.nev+\" egy \"+str(self.kor)+\" éves \"+ self.lakohely + \"i lakos.\"\n", " \n", "a=Ember(\"Gipsz Jakab\",24,\"budapest\")\n", "print(a)\n", "b=Ember(\"Gipsz Jakabné\",22,\"kecskemét\")\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "slideshow": { "slide_type": "slide" } }, "source": [ "### Osztály attribútumok \n", "\n", "- Olyan attribútum, amin az ossztály összes tagja osztozik. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Ember:\n", " letszam = 42" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### A példányokon és a class objektumon keresztül is elérjük" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a = Ember()\n", "a.letszam" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Ember.letszam" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "#### Megváltoztatni a classon keresztül lehet" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a1 = Ember()\n", "a2 = Ember()\n", "\n", "print(a1.letszam,a2.letszam)\n", "Ember.letszam = 43\n", "a1.letszam, a2.letszam" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "#### A példányokon keresztül viszont nem" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a1 = Ember()\n", "a2 = Ember()\n", "\n", "a1.letszam = 11\n", "a2.letszam" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Azért, mert ez egy új attribútumot hoz létre a példány namespacében. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a1.letszam" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Öröklődés\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Ember:\n", " pass\n", "\n", "class Matematikus(Ember):\n", " pass\n", "\n", "e = Ember()\n", "m = Matematikus()\n", "print(isinstance(e, Matematikus))\n", "print(isinstance(m, Ember))\n", "print(issubclass(Ember, Matematikus))\n", "print(issubclass(Matematikus,Ember))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ha nem írunk semmilyen osztályt, automatikusan az `object` osztály a szülő osztály:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A: pass\n", "class B(object): pass\n", "\n", "print(issubclass(A, object))\n", "print(issubclass(B, object))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Metódus öröklődés\n", "\n", "A metódusok öröklődnek, de felülírhatóak." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A(object):\n", " def foo(self):\n", " print(\"A.foo függvény\")\n", " \n", " def bar(self):\n", " print(\"A.bar függvény\")\n", " \n", "class B(A):\n", " def foo(self):\n", " print(\"B.foo függvény\")\n", " \n", "b = B()\n", "b.foo()\n", "b.bar()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Attribútum öröklődés\n", "Mivel az adat attribútumok bárhol létrehozhatóak, csak akkor \"öröklődnek\", ha a szülő osztályban lévő kód meghívódik." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A(object):\n", " \n", " def foo(self):\n", " self.value = 42\n", " \n", "class B(A):\n", " pass\n", "\n", "b = B()\n", "print(b.__dict__) # a __dict__ kiírja az összes attribútumot \n", "a = A()\n", "print(a.__dict__)\n", "a.foo()\n", "print(a.__dict__)\n", "print(b.__dict__)\n", "b.foo()\n", "print(b.__dict__)\n" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### A szülő osztály konstruktora\n", "\n", "- meghívódik az szülő osztály `__init__` függvénye. Viszont mivel az `__init__` nem egy szokásos konstruktor, így nem hívódik meg automatikusan a szülő osztály init függvénye, ha felülírja a gyerek osztály." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class A(object):\n", " def __init__(self):\n", " print(\"A.__init__ called\")\n", " \n", "class B(A):\n", " #pass\n", " def __init__(self):\n", " print(\"B.__init__ called\")\n", " \n", "class C(A):\n", " pass\n", " \n", "b = B()\n", "print(\"c létrehozása\")\n", "c = C()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "A szülő osztály metódusai kétféleképpen is elérhetőek\n", "1. a már tanult módon, az osztály nevével\n", "2. vagy pedig a **super** függvény segítségével" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class A(object):\n", " def __init__(self):\n", " print(\"A.__init__ \")\n", " \n", " \n", "class B(A):\n", " def __init__(self):\n", " A.__init__(self)\n", " print(\"B.__init__ \")\n", " \n", "class C(A):\n", " def __init__(self):\n", " super().__init__()\n", " print(\"C.__init__ \")\n", " \n", "print(\"B\")\n", "b = B()\n", "print(\"C\")\n", "c = C()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "class A(object):\n", " def __init__(self):\n", " print(\"A.__init__ \")\n", " \n", " \n", "class B(A):\n", " def __init__(self):\n", " print(\"B.__init__ \")\n", " \n", "class C(B):\n", " def __init__(self):\n", " super().__init__()\n", " print(\"C.__init__ \")\n", " \n", "c = C()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "slideshow": { "slide_type": "notes" } }, "outputs": [], "source": [ "class Ember(object):\n", " \n", " def __init__(self, nev, kor):\n", " self.nev = nev\n", " self.kor = kor\n", " \n", " def __str__(self):\n", " return \"{0}, életkor: {1}\".format(self.nev, self.kor)\n", " \n", "class Alkalmazott(Ember):\n", " \n", " def __init__(self, nev, kor, pozicio, fizetes):\n", " self.pozicio = pozicio\n", " self.fizetes = fizetes\n", " super().__init__(nev, kor)\n", " \n", " def __str__(self):\n", " return \"{0}, pozíció: {1}, fizetés: {2}\".format(super().__str__(), self.pozicio, self.fizetes)\n", " \n", " \n", "e = Alkalmazott(\"Jakab Gipsz\", 33, \"főnök\", 450000)\n", "print(e)\n", "print(Ember(e.nev, e.kor))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1. Példa: polinomok" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Polinom:\n", " \n", " def __init__(self, lista):\n", " self.ehlista=lista\n", " \n", " def __str__(self):\n", " szoveg=\"\"\n", " for i,eh in enumerate(self.ehlista):\n", " szoveg=szoveg+str(eh)+\"x^\"+str(i)+\"+\"\n", " szoveg=szoveg.rstrip(\"+\") \n", " return szoveg\n", " \n", " def deri(self):\n", " l=[]\n", " for i,eh in enumerate(self.ehlista):\n", " if i==0:\n", " pass\n", " else:\n", " l.append(i*eh)\n", " return Polinom(l)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "a=Polinom([1,2,4,5])\n", "print(a)\n", "print(a.deri())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Masodfoku(Polinom):\n", " def egyikgyok(self):\n", " a=self.ehlista[2]\n", " b=self.ehlista[1]\n", " c=self.ehlista[0]\n", " return (-b+(b**2-4*a*c)**(1/2))/(2*a) " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "p=Masodfoku([2,3,1])\n", "print(p)\n", "p.egyikgyok()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class Polinom:\n", " \n", " def __init__(self, lista):\n", " self.ehlista=lista\n", " \n", " def __str__(self):\n", " szoveg=\"\"\n", " for i,eh in enumerate(self.ehlista):\n", " szoveg=szoveg+str(eh)+\"x^\"+str(i)+\"+\"\n", " szoveg=szoveg.rstrip(\"+\") \n", " return szoveg\n", " \n", " def deri(self):\n", " l=[]\n", " for i,eh in enumerate(self.ehlista):\n", " if i==0:\n", " pass\n", " else:\n", " l.append(i*eh)\n", " return Polinom(l)\n", " \n", " def beh(self,x):\n", " valasz=0\n", " for i,eh in enumerate(self.ehlista):\n", " valasz=valasz+eh*pow(x,i)\n", " return valasz\n", "class Masodfoku(Polinom):\n", " def egyikgyok(self):\n", " a=self.ehlista[2]\n", " b=self.ehlista[1]\n", " c=self.ehlista[0]\n", " return (-b+(b**2-4*a*c)**(1/2))/(2*a) \n", "p=Polinom([2,1])\n", "print(p.beh(5))\n", "m=Masodfoku([1,2,1])\n", "m.beh(m.egyikgyok())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2. Példa: Sárkányok\n", "![sarkany](dragon.jpg) " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class sarkany:\n", " def __init__(self, nev):\n", " self.nev=nev" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class repulo_sarkany(sarkany):\n", " def __init__(self, nev, szarnyfesztav):\n", " super().__init__(nev)\n", " self.szarnyfesztav=szarnyfesztav\n", " \n", " def tamadas(self):\n", " print(\"A\", self.nev, \"nevű sárkány a levegőből rád vetette magát\", )\n", " \n", " def repules(self):\n", " print(\"A\", self.nev, \"nevű sárkány a repül\", )\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "smaug=repulo_sarkany(\"Smaug\",12)\n", "smaug.repules()\n", "smaug.tamadas()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class tuzokado_sarkany(sarkany):\n", " def __init__(self, nev):\n", " super().__init__(nev)\n", " \n", " def tamadas(self):\n", " print(\"A\", self.nev, \"nevű sárkány szénné égetett\", )\n", " \n", " def tuzokadas(self):\n", " print(\"A\", self.nev, \"nevű sárkány a tüzet okád\", )\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "susu=tuzokado_sarkany(\"Süsü\")\n", "susu.tuzokadas()\n", "susu.tamadas()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Többszörös öröklődés\n", "- mindegyik osztály metódusai öröklődnek" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class repulo_tuzokado_sarkany(repulo_sarkany,tuzokado_sarkany):\n", " def __init__(self, nev, szarnyfesztav):\n", " self.nev=nev \n", " self.szarnyfesztav=szarnyfesztav\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vajon mi lesz az eredmény?" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "viserion=repulo_tuzokado_sarkany(\"Viserion\",25)\n", "viserion.repules()\n", "viserion.tuzokadas()\n", "viserion.tamadas()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Azt, hogy melyik hívódik meg, az MRO (Method Resolution Order) határozza meg. Ez egy sorrend az osztályokon, és egy metódus hívásnál addig megy a sorrendben még meg nem találja valamelyik osztályban a metódust. Nem pontosan így működik, de ökölszabálynak jó, hogy felfelé mélységi kersést végez, balról jobbra sorrendben. \n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Információk egy osztályról\n", " - általában van dokumentáció" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import wikipedia\n", "w=wikipedia.page(\"Budapest\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "type(w)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "w.__dict__" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "\", \".join(dir(wikipedia.wikipedia.WikipediaPage))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "\n", "\", \".join(dir(str))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }