Last active
August 29, 2015 14:11
-
-
Save kindlychung/01f4935a7f86aa4de9ea to your computer and use it in GitHub Desktop.
master object oriented programming in python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from urllib.request import urlopen | |
from urllib.parse import urlparse | |
import re | |
import sys | |
LINK_REGEX = re.compile("<a [^>]*href=['\"]([^'\"]+)['\"][^>]*>") | |
class LinkCollector: | |
def __init__(self, url): | |
""":type url: str""" | |
#::type: str | |
self.url = "http://" + urlparse(url).netloc | |
#::type: dict | |
self.collected_links = {} | |
#::type: set | |
self.visited_links = set() | |
def collect_links(self, path="/"): | |
full_url = self.url + path | |
page = str(urlopen(full_url).read()) | |
self.visited_links.add(full_url) | |
links = LINK_REGEX.findall(page) | |
#:type: set[str] | |
links = {self.normalize_url(path, link) for link in links} | |
self.collected_links = links.union(self.collected_links) | |
unvisited_links = links.difference(self.visited_links) | |
def __str__(self): | |
# return "\n".join(self.links) | |
def normalize_url(self, path, link): | |
""" | |
:type path: str | |
:type link: str | |
""" | |
if link.startswith("http://"): | |
return link | |
elif link.startswith("/"): | |
return self.url + link | |
else: | |
return self.url + path.rpartition("/")[0] + "/" + link | |
print(LinkCollector("http://www.google.com").collect_links()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# extend builtin class | |
class ContactList(list): | |
def search(self, name): | |
""" | |
:type self: ContactList | |
:type name: str | |
:rtype: list[Contact] | |
""" | |
matching_contacts = [] | |
""":type: list[Contact]""" | |
for contact in self: | |
if name in contact.name: | |
matching_contacts.append(contact) | |
return matching_contacts | |
# a Class that stores all its instances | |
class Contact: | |
all_contacts = ContactList() | |
def __init__(self, name, email): | |
""" | |
:type name: str | |
:type email: str | |
""" | |
self.name = name | |
self.email = email | |
self.all_contacts.append(self) | |
c1 = Contact("John", "j@j.com") | |
c2 = Contact("Jane", "j@j.cn") | |
c3 = Contact("Tom", "t@t.com") | |
[c.name for c in Contact.all_contacts] | |
# demo inheritance and super() | |
class Friend(Contact): | |
def __init__(self, name, email, phone): | |
super().__init__(name, email) | |
self.phone = phone | |
# demo of mixin (a special kind of multiple inheritance) | |
class MailSender: | |
def send_mail(self, message): | |
""" | |
:type self: MailSender | |
:type message: str | |
:param message: | |
:return: | |
""" | |
print("Sending mail to " + self.email) | |
print("Message: %s" % message) | |
class EmailableContact(Contact, MailSender): | |
pass | |
e = EmailableContact("Smith", "s@s.com") | |
e.send_mail("Hi there!") | |
# demo of polymorphism | |
class AudioFile: | |
def __init__(self, filename): | |
""" | |
:type self: AudioFile | |
:type filename: str | |
:param filename: | |
:return: | |
""" | |
if not filename.endswith(self.ext): | |
raise Exception("Invalid file format") | |
self.filename = filename | |
def play(self): | |
print("Playing %s as %s" % (self.filename, self.ext)) | |
class MP3File(AudioFile): | |
#::type: str | |
ext = "mp3" | |
class WavFile(AudioFile): | |
ext = "wav" | |
class OggFile(AudioFile): | |
ext = "ogg" | |
ogg = OggFile("my.ogg") | |
ogg.play() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pdb | |
class Document: | |
def __init__(self): | |
""" | |
:type self: Document | |
:return: | |
:rtype: | |
""" | |
#::type: list[str] | |
self.characters = [] | |
#::type: Cursor | |
self.cursor = Cursor(self) | |
#::type: str | |
self.filename = "" | |
def insert(self, character): | |
""" | |
:type character: str | |
""" | |
self.characters.insert(self.cursor, character) | |
self.cursor.forward() | |
def add(self, character): | |
#:type character: str | |
self.characters.insert(self.cursor + 1, character) | |
def delete(self): | |
try: | |
del self.characters[self.cursor] | |
if self.cursor == len(self.characters): | |
self.cursor.back() | |
except IndexError: | |
print("Document empty, nothing to delete") | |
def save(self): | |
with open(self.filename, "w") as fh: | |
fh.write(str(self)) | |
def __str__(self): | |
""" | |
:rtype: str | |
""" | |
if not self.characters: | |
return None | |
return "".join(self.characters) | |
def __len__(self): | |
return len(self.characters) | |
def show(self): | |
""" | |
:rtype: str | |
""" | |
#::type: list[str] | |
indicator = ["-"] * len(self.characters) | |
indicator[self.cursor] = "*" | |
indicator_str = "".join(indicator) | |
return str(self) + "\n" + indicator_str | |
class Cursor: | |
def __init__(self, document): | |
#:type document: Document | |
self.document = document | |
self.position = 0 | |
def forward(self): | |
if self.position == (len(self.document) - 1): | |
pass | |
else: | |
self.position += 1 | |
def back(self): | |
if self.position == 0: | |
pass | |
else: | |
self.position -= 1 | |
def home(self): | |
while self.document.characters[self.position - 1] != "\n" and self.position > 0: | |
self.position -= 1 | |
def end(self): | |
while self.document.characters[self.position + 1] != "\n" and self.position < (len(self.document) + 1): | |
self.position += 1 | |
def __int__(self): | |
return self.position | |
doc = Document() | |
doc.insert("a") | |
doc.insert("b") | |
doc.insert("c") | |
doc.insert("d") | |
doc.insert("e") | |
print(doc.show()) | |
doc.delete() | |
print(doc.show()) | |
doc.forward() | |
doc.forward() | |
doc.forward() | |
print(doc.show()) | |
doc.delete() | |
print(doc.show()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss | |
import datetime | |
last_id = 0 | |
class Note: | |
def __init__(self:"Note", memo:str, tags:str=""): | |
self.memo = memo | |
self.tags = tags | |
self.creation_date = datetime.date.today() | |
global last_id | |
last_id += 1 | |
self.id = last_id | |
def match(self, filter): | |
return filter in self.memo or filter in self.tags | |
n1 = Note("hello first") | |
n2 = Note("hello again") | |
n1.id | |
n2.id | |
n1.match("hello") | |
n2.match("second") | |
class Notebook: | |
""" | |
:type notes: list of [Note] | |
""" | |
def __init__(self:"Notebook"): | |
self.notes = [] | |
""":type: list of [Note]""" | |
def new_note(self:"Notebook", memo:str, tags:str=""): | |
self.notes.append(Note(memo, tags)) | |
def find_note(self, note_id:int) -> Note: | |
for note in self.notes: | |
if note.id == note_id: | |
return note | |
return None | |
def modify_memo(self:"Notebook", note_id:int, memo:str): | |
note = self.find_note(note_id) | |
if note: | |
note.memo = memo | |
return True | |
return False | |
def modify_tags(self:"Notebook", note_id:int, tags:str): | |
note = self.find_note(note_id) | |
if note: | |
note.tags = tags | |
return True | |
return False | |
def search(self:"Notebook", filter:str): | |
return [note for note in self.notes if note.match(filter)] | |
class Menu: | |
def __init__(self): | |
self.notebook = Notebook() | |
self.choices = { | |
"1": self.show_notes, | |
"2": self.search_notes, | |
"3": self.add_note, | |
"4": self.modify_note, | |
"5": self.quit | |
} | |
def display_menu(self): | |
print(""" | |
Notebook Menu | |
1. Show all notes | |
2. Search Notes | |
3. Add note | |
4. Modify note | |
5. Quit | |
""") | |
def run(self): | |
while True: | |
self.display_menu() | |
choice = input("Enter an option: ") | |
action = self.choices.get(choice) | |
if action: | |
action() | |
else: | |
print("{0} is not a valid choice".format(choice)) | |
def show_notes(self, notes=None): | |
""" | |
:type notes: list[Note] | |
""" | |
if not notes: | |
notes = self.notebook.notes | |
for note in notes: | |
print("{0}: {1}\n{2}".format(note.id, note.tags, note.memo)) | |
def search_notes(self): | |
filter = input("Search for: ") | |
notes = self.notebook.search(filter) | |
self.show_notes(notes) | |
def add_note(self): | |
memo = input("Enter a memo") | |
self.notebook.new_note(memo) | |
print("Your note has been added.") | |
def modify_note(self): | |
id = input("Enter a note id: ") | |
memo = input("Enter a memo: ") | |
tags = input("Enter tags: ") | |
if memo: | |
self.notebook.modify_memo(id, memo) | |
if tags: | |
self.notebook.modify_tags(id, tags) | |
def quit(self): | |
print("Thank you for using our software, bye!") | |
sys.exit(0) | |
Menu().run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MakeMeal: | |
def prepare(self): pass | |
def cook(self): pass | |
def eat(self): pass | |
def go(self): | |
self.prepare() | |
self.cook() | |
self.eat() | |
class MakePizza(MakeMeal): | |
def prepare(self): | |
print "Prepare Pizza" | |
def cook(self): | |
print "Cook Pizza" | |
def eat(self): | |
print "Eat Pizza" | |
class MakeTea(MakeMeal): | |
def prepare(self): | |
print "Prepare Tea" | |
def cook(self): | |
print "Cook Tea" | |
def eat(self): | |
print "Eat Tea" | |
makePizza = MakePizza() | |
makePizza.go() | |
print 25*"+" | |
makeTea = MakeTea() | |
makeTea.go() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import time | |
from threading import Thread | |
def sleeper(i): | |
print("Thread %d sleeping" % i) | |
time.sleep(3) | |
print("Thread %d wakes up" % i) | |
for i in range(10): | |
t = Thread(target=sleeper, args=(i, )) | |
t.start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# classic example of the state design pattern | |
class Base(object): | |
@classmethod | |
def make(cls, *args, **kwargs): | |
print("Base.make(%s, %s) start" % (args, kwargs)) | |
print("Base.make end") | |
class Foo(Base): | |
@classmethod | |
def make(cls, *args, **kwargs): | |
print("Foo.make(%s, %s) start" % (args, kwargs)) | |
super(Foo, cls).make(*args, **kwargs) | |
print("Foo.make end") | |
class Bar(Base): | |
@classmethod | |
def make(cls, *args, **kwargs): | |
print("Bar.make(%s, %s) start" % (args, kwargs)) | |
super(Bar, cls).make(*args, **kwargs) | |
print("Bar.make end") | |
class FooBar(Foo,Bar): | |
@classmethod | |
def make(cls, *args, **kwargs): | |
print("FooBar.make(%s, %s) start" % (args, kwargs)) | |
super(FooBar, cls).make(*args, **kwargs) | |
print("FooBar.make end") | |
fb = FooBar.make(1, 2, c=3) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys, os, shutil, zipfile | |
class ZipReplace: | |
def __init__(self, filename, search_string, replace_string): | |
""" | |
:type self: ZipReplace | |
:type filename: str | |
:type search_string: str | |
:type replace_string: str | |
""" | |
self.filename = filename | |
self.search_string = search_string | |
self.replace_string = replace_string | |
self.temp_dir = "unzipped-%s" % filename | |
def _full_filename(self, filename): | |
""" | |
:type filename: str | |
""" | |
return os.path.join(self.temp_dir, filename) | |
def zip_find_replace(self): | |
self.unzip_files() | |
self.find_replace() | |
self.zip_files() | |
def unzip_files(self): | |
os.mkdir(self.temp_dir) | |
zip = zipfile.ZipFile(self.filename) | |
try: | |
zip.extractall(self.temp_dir) | |
finally: | |
zip.close() | |
def find_replace(self): | |
for filename in os.listdir(self.temp_dir): | |
with open(self._full_filename(filename)) as file: | |
contents = file.read() | |
contents = contents.replace(self.search_string, self.replace_string) | |
with open(self._full_filename(filename), "w") as file: | |
file.writable(contents) | |
def zip_files(self): | |
file = zipfile.ZipFile(self.filename, "w") | |
for filename in os.listdir(self.temp_dir): | |
file.write(self._full_filename(filename), filename) | |
shutil.rmtree(self.temp_dir) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment