diff --git a/asyncio/ccxt_async.py b/asyncio/ccxt_async.py
new file mode 100644
index 0000000..d217141
--- /dev/null
+++ b/asyncio/ccxt_async.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+
+import asyncio
+import functools
+import os
+import sys
+
+root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+sys.path.append(root + '/python')
+
+import ccxt.async_support as ccxt # noqa: E402
+
+
+async def print_ticker(symbol, id):
+ # verbose mode will show the order of execution to verify concurrency
+ exchange = getattr(ccxt, id)({'verbose': True})
+ print(await exchange.fetch_ticker(symbol))
+ await exchange.close()
+
+
+if __name__ == '__main__':
+
+ symbol = 'ETH/BTC'
+ print_ethbtc_ticker = functools.partial(print_ticker, symbol)
+ [asyncio.ensure_future(print_ethbtc_ticker(id)) for id in [
+ 'bitfinex',
+ 'poloniex',
+ 'kraken',
+ 'bittrex',
+ 'hitbtc',
+ ]]
+ loop = asyncio.get_event_loop()
+ pending = asyncio.all_tasks(loop)
+ loop.run_until_complete(asyncio.gather(*pending))
\ No newline at end of file
diff --git a/asyncio/multi_tasks.py b/asyncio/multi_tasks.py
new file mode 100644
index 0000000..ee081f1
--- /dev/null
+++ b/asyncio/multi_tasks.py
@@ -0,0 +1,16 @@
+import asyncio
+import time
+
+async def say_after(delay, what):
+ await asyncio.sleep(delay)
+ print(what)
+
+async def main():
+ print(f"started at {time.strftime('%X')}")
+
+ await say_after(1, 'hello')
+ await say_after(2, 'world')
+
+ print(f"finished at {time.strftime('%X')}")
+
+asyncio.run(main())
diff --git a/asyncio/simple.py b/asyncio/simple.py
new file mode 100644
index 0000000..675b564
--- /dev/null
+++ b/asyncio/simple.py
@@ -0,0 +1,8 @@
+import asyncio
+
+async def main():
+ print('Hello ...')
+ await asyncio.sleep(1)
+ print('... World!')
+
+asyncio.run(main())
diff --git a/cffi/_simple_example.py b/cffi/_simple_example.py
new file mode 100644
index 0000000..2689d2b
--- /dev/null
+++ b/cffi/_simple_example.py
@@ -0,0 +1,8 @@
+# auto-generated file
+import _cffi_backend
+
+ffi = _cffi_backend.FFI('_simple_example',
+ _version = 0x2601,
+ _types = b'\x00\x00\x04\x0D\x00\x00\x03\x03\x00\x00\x01\x0F\x00\x00\x02\x01\x00\x00\x07\x01',
+ _globals = (b'\x00\x00\x00\x23printf',0,),
+)
diff --git a/cffi/main.py b/cffi/main.py
new file mode 100644
index 0000000..d7195d8
--- /dev/null
+++ b/cffi/main.py
@@ -0,0 +1,7 @@
+from _simple_example import ffi
+
+lib = ffi.dlopen(None) # Unix: open the standard C library
+#import ctypes.util # or, try this on Windows:
+#lib = ffi.dlopen(ctypes.util.find_library("c"))
+
+lib.printf(b"hi there, number %d\n", ffi.cast("int", 2))
diff --git a/cffi/simple_example_build.py b/cffi/simple_example_build.py
new file mode 100644
index 0000000..b788ce1
--- /dev/null
+++ b/cffi/simple_example_build.py
@@ -0,0 +1,15 @@
+# file "simple_example_build.py"
+
+# Note: this particular example fails before version 1.0.2
+# because it combines variadic function and ABI level.
+
+from cffi import FFI
+
+ffi = FFI()
+ffi.set_source("_simple_example", None)
+ffi.cdef("""
+ int printf(const char *format, ...);
+""")
+
+if __name__ == "__main__":
+ ffi.compile()
diff --git a/click/group.py b/click/group.py
new file mode 100644
index 0000000..8790cf8
--- /dev/null
+++ b/click/group.py
@@ -0,0 +1,19 @@
+import click
+
+@click.group()
+def cli():
+ pass
+
+@click.command()
+def initdb():
+ click.echo('init db')
+
+@click.command()
+def dropdb():
+ click.echo('Droped the db')
+
+cli.add_command(initdb)
+cli.add_command(dropdb)
+
+if __name__ == '__main__':
+ cli()
diff --git a/click/pass_content.py b/click/pass_content.py
new file mode 100644
index 0000000..21327da
--- /dev/null
+++ b/click/pass_content.py
@@ -0,0 +1,16 @@
+import click
+
+@click.group()
+@click.option('--debug/--no-debug', default=False)
+@click.pass_context
+
+def cli(ctx, debug):
+ ctx.obj['DEBUG'] = debug
+
+@cli.command()
+@click.pass_context
+def sync(ctx):
+ click.echo('Debug is %s' % (ctx.obj['DEBUG'] and 'on' or 'off'))
+
+if __name__ == '__main__':
+ cli(obj={})
diff --git a/click/simple.py b/click/simple.py
new file mode 100644
index 0000000..5bb3ce5
--- /dev/null
+++ b/click/simple.py
@@ -0,0 +1,12 @@
+import click
+
+@click.command()
+@click.option('--count', default=1, help='Number of greetings.')
+@click.option('--name', prompt='Your name', help='The person to greet.')
+def hello(count, name):
+ """Simple program that greets NAME for a total of COUNT times."""
+ for x in range(count):
+ click.echo('Hello %s!' % name)
+
+if __name__ == '__main__':
+ hello()
diff --git a/duck_typing/polymorphism.py b/duck_typing/polymorphism.py
new file mode 100644
index 0000000..e1f334f
--- /dev/null
+++ b/duck_typing/polymorphism.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+class Duck:
+ def quack(self):
+ print "Quaaaaaack!"
+
+class Bird:
+ def quack(self):
+ print "bird imitate duck."
+
+class Doge:
+ def quack(self):
+ print "doge imitate duck."
+
+def in_the_forest(duck):
+ duck.quack()
+
+duck = Duck()
+bird = Bird()
+doge = Doge()
+for x in [duck, bird, doge]:
+ in_the_forest(x)
diff --git a/duck_typing/redirect_stdout.py b/duck_typing/redirect_stdout.py
new file mode 100644
index 0000000..9cdb6d3
--- /dev/null
+++ b/duck_typing/redirect_stdout.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+#coding=utf-8
+
+import sys
+
+sys.stdout = open('stdout.log', 'a') # 只要是 file-like, 不管是什么类型
+print 'foo'
+
+sys.stdout = sys.__stdout__ # 恢复
+print 'bar'
diff --git a/eval/eval_hello.py b/eval/eval_hello.py
new file mode 100644
index 0000000..68a8bcb
--- /dev/null
+++ b/eval/eval_hello.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# http://www.mojidong.com/python/2013/05/10/python-exec-eval/
+
+a = 1
+print(eval("a + 1"))
+
+a = 1
+g = {
+ 'a': 10
+}
+print(eval("a + 1", g))
+
+a = 10
+b = 20
+c = 20
+g = {
+ 'a': 6,
+ 'b': 8
+}
+l = {
+ 'b': 9,
+ 'c': 10
+}
+print(eval("a+b+c", g, l))
+
+print(eval('abs(a)',{'__builtins__':__builtins__, 'a':-1}))
+# eval('abs(a)',{'__builtins__':None, 'a':-1})
diff --git a/excel/README.md b/excel/README.md
new file mode 100644
index 0000000..f598327
--- /dev/null
+++ b/excel/README.md
@@ -0,0 +1,11 @@
+# excel
+
+## Install
+* Use python3.
+* `pip install -r requirements.txt`
+
+## Run
+* `python xls2csv.py`
+
+## Docs
+*
diff --git a/excel/input.xls b/excel/input.xls
new file mode 100644
index 0000000..1a07457
Binary files /dev/null and b/excel/input.xls differ
diff --git a/excel/requirements.txt b/excel/requirements.txt
new file mode 100644
index 0000000..4f1b83f
--- /dev/null
+++ b/excel/requirements.txt
@@ -0,0 +1,2 @@
+xlrd
+csv
diff --git a/excel/xls2csv.py b/excel/xls2csv.py
new file mode 100644
index 0000000..2f81a62
--- /dev/null
+++ b/excel/xls2csv.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+#!/usr/bin/env python
+
+import csv, xlrd, os
+from os import listdir
+from os.path import isfile, join
+
+def xls_to_csv(xls_file):
+ wb = xlrd.open_workbook(xls_file)
+ for sheet in wb.sheet_names():
+ sh = wb.sheet_by_name(sheet)
+ csv_file_name = os.path.splitext(xls_file)[0] + "_" + sheet + ".csv"
+ with open(csv_file_name, 'w', encoding='utf8') as file:
+ wr = csv.writer(file, quoting=csv.QUOTE_ALL)
+ for rownum in range(sh.nrows):
+ wr.writerow(sh.row_values(rownum))
+
+if __name__ == '__main__':
+ onlyfiles = [f for f in listdir(os.getcwd()) if isfile(join(os.getcwd(), f))]
+ for file in onlyfiles:
+ if os.path.splitext(file)[1] == ".xls" or os.path.splitext(file)[1] == ".xlsx":
+ xls_to_csv(file)
diff --git a/exec/exec_hello.py b/exec/exec_hello.py
new file mode 100644
index 0000000..3110ae2
--- /dev/null
+++ b/exec/exec_hello.py
@@ -0,0 +1,27 @@
+#!/usr/bin/env python
+# http://www.mojidong.com/python/2013/05/10/python-exec-eval/
+
+a = 2
+exec "a=1"
+print(a)
+
+a = 10
+b = 20
+g = {
+ 'a':6,
+ 'b':8
+}
+exec "global a; print a,b" in g
+
+a = 10
+b = 20
+c = 20
+g = {
+ 'a':6,
+ 'b': 8
+}
+l = {
+ 'b':9,
+ 'c':10
+}
+exec "global a;print a,b,c" in g,l
diff --git a/ffmpeg/BlackBerry.mp4 b/ffmpeg/BlackBerry.mp4
new file mode 100644
index 0000000..6889533
Binary files /dev/null and b/ffmpeg/BlackBerry.mp4 differ
diff --git a/ffmpeg/get_info.py b/ffmpeg/get_info.py
new file mode 100644
index 0000000..e862ee3
--- /dev/null
+++ b/ffmpeg/get_info.py
@@ -0,0 +1,9 @@
+
+import subprocess as sp
+
+cmd = ['ffmpeg', '-i', 'BlackBerry.mp4', '-']
+pipe = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
+pipe.stdout.readline()
+pipe.terminate()
+infos = pipe.stderr.read()
+print(infos)
diff --git a/ffmpeg/read_write_audio_framee.py b/ffmpeg/read_write_audio_framee.py
new file mode 100644
index 0000000..e69de29
diff --git a/ffmpeg/read_write_video_frames.py b/ffmpeg/read_write_video_frames.py
new file mode 100644
index 0000000..411f8af
--- /dev/null
+++ b/ffmpeg/read_write_video_frames.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+import subprocess as sp
+import numpy
+
+cmd = ["ffmpeg",
+ "-i", "BlackBerry.mp4",
+ "-f", "image2pipe",
+ "-pix_fmt", "rgb24",
+ "-vcodec", "rawvideo",
+ "-"]
+
+pipe = sp.Popen(cmd, stdout=sp.PIPE, bufsize=10 ** 8)
+
+# # read 380*480*3 bytes (= 1 frame)
+# raw_image = pipe.stdout.read(320*180*3)
+# # transform the byte read into a numpy array
+# image = numpy.fromstring(raw_image, dtype='uint8')
+# image = image.reshape((180,320,3))
+# # throw away the data in the pipe's buffer.
+# pipe.stdout.flush()
+
+# seek https://trac.ffmpeg.org/wiki/Seeking
+# command = ["ffmpeg",
+# '-ss', '00:59;59',
+# '-i', 'myHolidays.mp4',
+# '-ss', '1',
+# '-f', 'image2pipe',
+# '-pix_fmt', 'rgb24',
+# '-vcodec', 'rawvideo', '-']
+# pipe = sp.Popen(command, stdout=sp.PIPE, bufsize=10 ** 8)
diff --git a/ffmpeg/sample.mp4 b/ffmpeg/sample.mp4
new file mode 100644
index 0000000..05d289c
Binary files /dev/null and b/ffmpeg/sample.mp4 differ
diff --git a/flask/flaskr-tdd/requirements.txt b/flask/flaskr-tdd/requirements.txt
index 0366ea1..a858efe 100644
--- a/flask/flaskr-tdd/requirements.txt
+++ b/flask/flaskr-tdd/requirements.txt
@@ -1,6 +1,6 @@
coverage==4.0
docopt==0.6.2
-ecdsa==0.13
+ecdsa==0.13.3
Fabric==1.10.2
Flask==0.10.1
Flask-Boost==0.7.2
diff --git a/func/args.py b/func/args.py
index 0299aaf..fb38377 100644
--- a/func/args.py
+++ b/func/args.py
@@ -11,9 +11,9 @@ def x(a, b, *c):
# 参数前面为**, 代表这个位置的参数不知道有多少个参数, 如果有, 则将其存储为字典
def y(*c, **k):
- print c
- print k
+ print(c)
+ print(k)
if __name__ == "__main__":
x(1,2,3,4)
- y(1,2,a="b",c="d")
\ No newline at end of file
+ y(1,2,a="b",c="d")
diff --git a/grpc/helloworld/.gitignore b/grpc/helloworld/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/grpc/helloworld/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/grpc/helloworld/README.md b/grpc/helloworld/README.md
new file mode 100644
index 0000000..e889863
--- /dev/null
+++ b/grpc/helloworld/README.md
@@ -0,0 +1 @@
+[This code's documentation lives on the grpc.io site.](http://www.grpc.io/docs)
diff --git a/grpc/helloworld/greeter_client.py b/grpc/helloworld/greeter_client.py
new file mode 100644
index 0000000..561b25b
--- /dev/null
+++ b/grpc/helloworld/greeter_client.py
@@ -0,0 +1,47 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""The Python implementation of the GRPC helloworld.Greeter client."""
+
+from grpc.beta import implementations
+
+import helloworld_pb2
+
+_TIMEOUT_SECONDS = 10
+
+
+def run():
+ channel = implementations.insecure_channel('localhost', 50051)
+ stub = helloworld_pb2.beta_create_Greeter_stub(channel)
+ response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'), _TIMEOUT_SECONDS)
+ print "Greeter client received: " + response.message
+
+
+if __name__ == '__main__':
+ run()
diff --git a/grpc/helloworld/greeter_server.py b/grpc/helloworld/greeter_server.py
new file mode 100644
index 0000000..1514d8f
--- /dev/null
+++ b/grpc/helloworld/greeter_server.py
@@ -0,0 +1,56 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""The Python implementation of the GRPC helloworld.Greeter server."""
+
+import time
+
+import helloworld_pb2
+
+_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+
+
+class Greeter(helloworld_pb2.BetaGreeterServicer):
+
+ def SayHello(self, request, context):
+ return helloworld_pb2.HelloReply(message='Hello, %s!' % request.name)
+
+
+def serve():
+ server = helloworld_pb2.beta_create_Greeter_server(Greeter())
+ server.add_insecure_port('[::]:50051')
+ server.start()
+ try:
+ while True:
+ time.sleep(_ONE_DAY_IN_SECONDS)
+ except KeyboardInterrupt:
+ server.stop()
+
+if __name__ == '__main__':
+ serve()
diff --git a/grpc/helloworld/helloworld_pb2.py b/grpc/helloworld/helloworld_pb2.py
new file mode 100644
index 0000000..8df42ba
--- /dev/null
+++ b/grpc/helloworld/helloworld_pb2.py
@@ -0,0 +1,202 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: helloworld.proto
+
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name='helloworld.proto',
+ package='helloworld',
+ # syntax='proto3',
+ serialized_pb=b'\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x18\n\x10io.grpc.examples\xa2\x02\x03HLWb\x06proto3'
+)
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+
+
+
+_HELLOREQUEST = _descriptor.Descriptor(
+ name='HelloRequest',
+ full_name='helloworld.HelloRequest',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='name', full_name='helloworld.HelloRequest.name', index=0,
+ number=1, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=b"".decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ # syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=32,
+ serialized_end=60,
+)
+
+
+_HELLOREPLY = _descriptor.Descriptor(
+ name='HelloReply',
+ full_name='helloworld.HelloReply',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='message', full_name='helloworld.HelloReply.message', index=0,
+ number=1, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=b"".decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ # syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=62,
+ serialized_end=91,
+)
+
+DESCRIPTOR.message_types_by_name['HelloRequest'] = _HELLOREQUEST
+DESCRIPTOR.message_types_by_name['HelloReply'] = _HELLOREPLY
+
+HelloRequest = _reflection.GeneratedProtocolMessageType('HelloRequest', (_message.Message,), dict(
+ DESCRIPTOR = _HELLOREQUEST,
+ __module__ = 'helloworld_pb2'
+ # @@protoc_insertion_point(class_scope:helloworld.HelloRequest)
+ ))
+_sym_db.RegisterMessage(HelloRequest)
+
+HelloReply = _reflection.GeneratedProtocolMessageType('HelloReply', (_message.Message,), dict(
+ DESCRIPTOR = _HELLOREPLY,
+ __module__ = 'helloworld_pb2'
+ # @@protoc_insertion_point(class_scope:helloworld.HelloReply)
+ ))
+_sym_db.RegisterMessage(HelloReply)
+
+
+DESCRIPTOR.has_options = True
+DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), b'\n\020io.grpc.examples\242\002\003HLW')
+import abc
+from grpc.beta import implementations as beta_implementations
+from grpc.early_adopter import implementations as early_adopter_implementations
+from grpc.framework.alpha import utilities as alpha_utilities
+from grpc.framework.common import cardinality
+from grpc.framework.interfaces.face import utilities as face_utilities
+class EarlyAdopterGreeterServicer(object):
+ """"""
+ __metaclass__ = abc.ABCMeta
+ @abc.abstractmethod
+ def SayHello(self, request, context):
+ raise NotImplementedError()
+class EarlyAdopterGreeterServer(object):
+ """"""
+ __metaclass__ = abc.ABCMeta
+ @abc.abstractmethod
+ def start(self):
+ raise NotImplementedError()
+ @abc.abstractmethod
+ def stop(self):
+ raise NotImplementedError()
+class EarlyAdopterGreeterStub(object):
+ """"""
+ __metaclass__ = abc.ABCMeta
+ @abc.abstractmethod
+ def SayHello(self, request):
+ raise NotImplementedError()
+ SayHello.async = None
+def early_adopter_create_Greeter_server(servicer, port, private_key=None, certificate_chain=None):
+ import helloworld_pb2
+ import helloworld_pb2
+ method_service_descriptions = {
+ "SayHello": alpha_utilities.unary_unary_service_description(
+ servicer.SayHello,
+ helloworld_pb2.HelloRequest.FromString,
+ helloworld_pb2.HelloReply.SerializeToString,
+ ),
+ }
+ return early_adopter_implementations.server("helloworld.Greeter", method_service_descriptions, port, private_key=private_key, certificate_chain=certificate_chain)
+def early_adopter_create_Greeter_stub(host, port, metadata_transformer=None, secure=False, root_certificates=None, private_key=None, certificate_chain=None, server_host_override=None):
+ import helloworld_pb2
+ import helloworld_pb2
+ method_invocation_descriptions = {
+ "SayHello": alpha_utilities.unary_unary_invocation_description(
+ helloworld_pb2.HelloRequest.SerializeToString,
+ helloworld_pb2.HelloReply.FromString,
+ ),
+ }
+ return early_adopter_implementations.stub("helloworld.Greeter", method_invocation_descriptions, host, port, metadata_transformer=metadata_transformer, secure=secure, root_certificates=root_certificates, private_key=private_key, certificate_chain=certificate_chain, server_host_override=server_host_override)
+
+class BetaGreeterServicer(object):
+ """"""
+ __metaclass__ = abc.ABCMeta
+ @abc.abstractmethod
+ def SayHello(self, request, context):
+ raise NotImplementedError()
+
+class BetaGreeterStub(object):
+ """The interface to which stubs will conform."""
+ __metaclass__ = abc.ABCMeta
+ @abc.abstractmethod
+ def SayHello(self, request, timeout):
+ raise NotImplementedError()
+ SayHello.future = None
+
+def beta_create_Greeter_server(servicer, pool=None, pool_size=None, default_timeout=None, maximum_timeout=None):
+ import helloworld_pb2
+ import helloworld_pb2
+ request_deserializers = {
+ ('helloworld.Greeter', 'SayHello'): helloworld_pb2.HelloRequest.FromString,
+ }
+ response_serializers = {
+ ('helloworld.Greeter', 'SayHello'): helloworld_pb2.HelloReply.SerializeToString,
+ }
+ method_implementations = {
+ ('helloworld.Greeter', 'SayHello'): face_utilities.unary_unary_inline(servicer.SayHello),
+ }
+ server_options = beta_implementations.server_options(request_deserializers=request_deserializers, response_serializers=response_serializers, thread_pool=pool, thread_pool_size=pool_size, default_timeout=default_timeout, maximum_timeout=maximum_timeout)
+ return beta_implementations.server(method_implementations, options=server_options)
+
+def beta_create_Greeter_stub(channel, host=None, metadata_transformer=None, pool=None, pool_size=None):
+ import helloworld_pb2
+ import helloworld_pb2
+ request_serializers = {
+ ('helloworld.Greeter', 'SayHello'): helloworld_pb2.HelloRequest.SerializeToString,
+ }
+ response_deserializers = {
+ ('helloworld.Greeter', 'SayHello'): helloworld_pb2.HelloReply.FromString,
+ }
+ cardinalities = {
+ 'SayHello': cardinality.Cardinality.UNARY_UNARY,
+ }
+ stub_options = beta_implementations.stub_options(host=host, metadata_transformer=metadata_transformer, request_serializers=request_serializers, response_deserializers=response_deserializers, thread_pool=pool, thread_pool_size=pool_size)
+ return beta_implementations.dynamic_stub(channel, 'helloworld.Greeter', cardinalities, options=stub_options)
+# @@protoc_insertion_point(module_scope)
diff --git a/grpc/helloworld/protos/helloworld.proto b/grpc/helloworld/protos/helloworld.proto
new file mode 100644
index 0000000..7d58870
--- /dev/null
+++ b/grpc/helloworld/protos/helloworld.proto
@@ -0,0 +1,51 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+option java_package = "io.grpc.examples";
+option objc_class_prefix = "HLW";
+
+package helloworld;
+
+// The greeting service definition.
+service Greeter {
+ // Sends a greeting
+ rpc SayHello (HelloRequest) returns (HelloReply) {}
+}
+
+// The request message containing the user's name.
+message HelloRequest {
+ string name = 1;
+}
+
+// The response message containing the greetings
+message HelloReply {
+ string message = 1;
+}
diff --git a/grpc/helloworld/run_client.sh b/grpc/helloworld/run_client.sh
new file mode 100755
index 0000000..77c5a2c
--- /dev/null
+++ b/grpc/helloworld/run_client.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# This is where you have cloned out the https://github.com/grpc/grpc repository
+# And built gRPC Python.
+# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS
+#GRPC_ROOT=~/github/grpc
+
+python greeter_client.py
diff --git a/grpc/helloworld/run_codegen.sh b/grpc/helloworld/run_codegen.sh
new file mode 100755
index 0000000..ef0397f
--- /dev/null
+++ b/grpc/helloworld/run_codegen.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# Runs the protoc with gRPC plugin to generate protocol messages and gRPC stubs.
+protoc -I protos --python_out=. --grpc_out=. --plugin=protoc-gen-grpc=`which grpc_python_plugin` protos/helloworld.proto
diff --git a/grpc/helloworld/run_server.sh b/grpc/helloworld/run_server.sh
new file mode 100755
index 0000000..b3070a9
--- /dev/null
+++ b/grpc/helloworld/run_server.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# This is where you have cloned out the https://github.com/grpc/grpc repository
+# And built gRPC Python.
+# ADJUST THIS PATH TO WHERE YOUR ACTUAL LOCATION IS
+#GRPC_ROOT=~/github/grpc
+
+python greeter_server.py
+
diff --git a/imageio/akhead-gray.jpg b/imageio/akhead-gray.jpg
new file mode 100644
index 0000000..f49a0b5
Binary files /dev/null and b/imageio/akhead-gray.jpg differ
diff --git a/imageio/akhead.png b/imageio/akhead.png
new file mode 100644
index 0000000..e80afca
Binary files /dev/null and b/imageio/akhead.png differ
diff --git a/imageio/gray.py b/imageio/gray.py
new file mode 100644
index 0000000..e6c269a
--- /dev/null
+++ b/imageio/gray.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+import imageio
+
+im = imageio.imread('akhead.png')
+print(im.shape) # im is a numpy array
+imageio.imwrite('akhead-gray.jpg', im[:,:,0])
diff --git a/ipython/.ipynb_checkpoints/test_matplot-checkpoint.ipynb b/ipython/.ipynb_checkpoints/test_matplot-checkpoint.ipynb
deleted file mode 100644
index 5cb5fe5..0000000
--- a/ipython/.ipynb_checkpoints/test_matplot-checkpoint.ipynb
+++ /dev/null
@@ -1,107 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {
- "collapsed": false
- },
- "outputs": [
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from matplotlib.pyplot import *\n",
- "from numpy import *\n",
- "x = linspace(0, 2 * pi)\n",
- "plot(x, sin(x), label=r'$\\sin(x)$')\n",
- "plot(x, cos(x), 'ro', label=r'$\\cos(x)$')\n",
- "title(r'Two familiar functions')\n",
- "legend()"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": []
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "metadata": {
- "collapsed": true
- },
- "outputs": [],
- "source": []
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 2",
- "language": "python",
- "name": "python2"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 2
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython2",
- "version": "2.7.9"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/list/Overview b/list/Overview
new file mode 100644
index 0000000..98d6cca
--- /dev/null
+++ b/list/Overview
@@ -0,0 +1,4 @@
+ Notes on List in Python
+ 1. Contains notes on various methods on list in python
+ 2. Contains the basic codes as an example
+
diff --git a/list/commands on list.py b/list/commands on list.py
new file mode 100644
index 0000000..1ac15ef
--- /dev/null
+++ b/list/commands on list.py
@@ -0,0 +1,136 @@
+""" CLEAR COMMAND """
+l=[1,2,3,4,5,6]
+l.clear()
+#Use to clear all elements in the list
+# but maintain the id of the objects (erased elements of the list).
+print(l)
+
+
+
+""" COPY COMMAND """
+l=[1,2]
+l1=l
+#so here actually whats happening a copy of l is not made in l1
+#instead l1 will also call the same elements as being called by l.
+id(l)
+# in python whatever is in square brackets in a list are objects.
+id(l1)
+#Hence, both the id of l and l1 will be same
+#no copy of the list is made.
+
+#so lets do try append 'l1' and see if it affects 'l' or not
+
+l1.append(4)
+print(l1)# l1 got changed
+print(l)# so did l
+
+"""But what if i don't want to change l and
+make l1 a copy of the objects not the pointer of the same objects.
+We have a command called copy() in lists """
+
+#Let's use the copy command.
+l=[1,2]
+l1=l.copy()#makes a copy of object at different ID
+print(id(l))
+print(id(l1))
+l1.append(4)# Will only change l1 not l.
+print(l)
+print(l1)
+
+
+""" AN ANALOGY OF THE COPY COMMAND """
+""" without copy command """
+#Suppose you want to read a novel.
+#You asked one of your friends(Srishti) for it.
+#She found it in the library and told u it's location
+#(same like variable gives you a output via print command)
+#You asked another friend(Prashant) too.
+#He contacted Srishti and told u about the same location.
+
+
+""" with copy command """
+#Suppose you want to read a novel.
+#You asked one of your friends(Srishti) for it.
+#She found it in the library and told u it's location
+#(same like variable gives you a output via print command)
+#You asked another friend(Prashant) too.
+#He contacted Srishti and went to the library
+#Took a copy of it and added it to his own personal llibrary
+#Now told you to come and read it from his library whenever u want to.
+
+
+l=[1,2,3,4,5,6]
+le=[]
+for i in l:
+ if i%2==0:
+ le.append(i)
+
+lee=[i for i in l if i%2==0]
+
+lx=[x**2 for x in l]
+
+import keyword
+keyword.iskeyword("1srishti")#willl tell us whether the word is a keyword or not
+
+'1srish'.isidentifier()#helps in identifying whether the name given to any identifier
+# is feasible or not but it can't differentiate the keywords
+
+
+
+#program to find feasible names of an identifier
+#By:-Srishti Singh
+c=input("Enter any string: ")
+import keyword
+if(keyword.iskeyword(c)==False and c.isidentifier()==True ):
+ print("It is an identifier")
+else:
+ print("It is not an identifier")
+
+
+l=[1,2,3,[4,5],6,7,8]
+import copy
+a=copy.copy(l)
+b=copy.deepcopy(l)
+print(a,b)
+l[3][0]=10
+print(a,b)
+
+
+#Program to show difference between shallow and deep copy
+l=[1,2,3,[4,5],6,7,8]
+import copy
+a=copy.copy(l)
+b=copy.deepcopy(l)
+print("Original list:",l)
+print("Your Shallow Copied list is:",a)
+print("Your Deep Copied list is:",b)
+l[3][0]=10
+print("Original list after alteration:",l)
+print("Shallow Copied list after alteration:",a)
+print("Deep Copied list after alteration:",b)
+
+d={"Name":"Srishti Singh","System ID":2018013720,"Course":"B.Tech. CSE with specialisation in A.I. and Machine Learning"}
+a=d.keys()
+print(a)
+
+s="234"
+integer_s=int(s)
+float_s=float(s)
+tuple_s=tuple(s)
+list_s=list(s)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/list/evenodd.py b/list/evenodd.py
new file mode 100644
index 0000000..b941e1e
--- /dev/null
+++ b/list/evenodd.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Jan 16 10:07:18 2019
+
+@author: Dell
+"""
+
+#to sort even odd numbers
+l=[]
+s=int(input("Enter Number of Elements in the List: "))
+for i in range(s):
+ x=int(input("Enter element in the list: "))
+ l.append(x)
+e=[]
+o=[]
+for i in range(len(l)):
+ if l[i]%2==0:
+ e.append(l[i])
+ else:
+ o.append(l[i])
+print("List of your Even Numbers is:",e)
+print("List of your Odd Numbers is:",o)
+
+
+
+
+
diff --git a/list/functions_on_list.py b/list/functions_on_list.py
new file mode 100644
index 0000000..91f063f
--- /dev/null
+++ b/list/functions_on_list.py
@@ -0,0 +1,44 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Jan 23 10:37:23 2019
+
+@author: Dell
+"""
+
+import random
+l=[2,3,4,3,3,4,1,2,3]
+random.shuffle(l)
+print(l)
+
+random.randint(2,3)
+s="hello"#firstly string is converted to lower case firstly and output is always in uppercase
+s.startswith('h')#check whether starting word is h
+s.endswith('O')
+
+s={1,2,3,3,4,5,6}
+print(s)
+
+s="hello"
+ss=set(s)
+print(ss)
+
+ss.add(40)
+ss.update(["orange"])#Always give articles in form of a list
+print(ss)
+
+
+s="hello"
+ss=set(s)
+print(ss)
+ss.update("orange")
+print(ss)
+
+#remove an item from set
+ss.remove('h')
+
+ss.discard('o')
+
+del(ss)
+
+sset=set(("orange","apple"))
+print(sset)
diff --git a/list/practice1.py b/list/practice1.py
new file mode 100644
index 0000000..ff53c48
--- /dev/null
+++ b/list/practice1.py
@@ -0,0 +1,221 @@
+"""
+Q1. WAP that will create a new list of age given the list of year of birth using list comprehension.
+Q2. Create a list which will print all the characters in a string which are not vowels using list
+ comprehension.
+Q3. Create a list of squares of numbers given a list of ten numbers using list comprehension.
+Q4. WAP which will input a string from the user and gives the list of first letter of every word
+ in the list using list comprehension.
+Q5. WAP to create a tuple containing types of fishes and using list comprehension print all the items
+ of the tuple if item is not octupus.
+Q6. Differentiate between deep copy and shallow copy.
+Q7. Write some of the features of python.
+Q8. How will you get all the keys from the dictionARY.Write a small program to demonstrate it.
+Q9. Do following conversions:
+ String to integer
+ String to long
+ String to float
+ String to a tupple
+ String to a list
+ String to a set
+ String to a dictonary
+Q10.Create a dictionary using tupple.
+Q11.What do you understand by frozen set.
+Q12.What is the purpose of following operators:-
+ 1) **
+ 2) //
+ 3) is
+ 4) not in
+"""
+#break and continue
+#P1
+List_Year=[]
+n=int(input("Enter number of elements in your list: "))
+for i in range(n):
+ x=int(input("Enter Year Of Birth: "))
+ List_Year.append(x)
+List_age=[2019-x for x in List_Year]
+print("LIst of Ages are: ",List_age)
+
+#P2
+s=input("Enter a string: ")
+l=[x for x in s if x not in ['a','e','i','o','u']]
+print("Your list of consonants is:",l)
+
+#P3
+a=int(input("Enter starting number: "))
+l=[x**2 for x in range(a,a+10)]
+print("Your list of square of numbers is:",l)
+
+#P4
+s=input("Enter any string: ")
+ls=s.split()
+l=[x[0] for x in ls ]
+print("Your first letter of all words are:",l)
+
+#P5
+List=[]
+n=int(input("Enter number of fishes in your list: "))
+for i in range(n):
+ x=input("Enter Name of Fish: ")
+ List.append(x)
+t=tuple(List)
+l=[x for x in t if x !='octopus']
+print("Your list is:",l)
+
+
+#FEB 5/2019
+#Some more functions on lists and tupples and dictionaries.
+
+t=(23,45,67,78)
+len(t)
+max(t) #Only works when we have same datatypes ,in string compares ASCII value.
+min(t)
+
+d1={'aman':1,'srishti':2,'babita':3}
+s=str(d1)
+print(s)
+
+#dict also has clear and copy(it makes a deep copy.) as lists. simple assignment gives (shallow copy).
+
+seq={'name','class','roll'}
+dict1={}
+dict1= dict1.fromkeys(seq,10)#wiillform keys as elements of seq and every key has a value 10
+print(dict1)
+l1=[1,2,3]
+dict1=dict1.fromkeys(l1)#form keys as that of l1
+
+dict1={'1':1,'2':2,'3':3}
+
+#we can delete anything using del(list,tupple,lists).
+
+
+
+#Q1. Count the number of words in a string.
+#Q2. Calculate factorial of a function using functions.
+
+#P1
+para=input("Enter a paragraph: ")
+para.lower()
+paral=para.split()
+dict1={}
+dict1=dict1.fromkeys(paral,0)
+for p in paral:
+ dict1[p]=dict1[p]+1
+print(dict1)
+
+para=input("Enter a paragraph: ")
+para.lower()
+l=para.split()
+d={}
+for i in l:
+ d[i]=d.get(i,0)+1
+
+#P2
+def facto(n):
+ if n==1:
+ return (1)
+ elif n>1:
+ return n*facto(n-1)
+ else:
+ print("Error!!! Negative numbers don't have a factorial")
+num=int(input("Enter the number whose factorial you want to find: "))
+print("Your {number}! is: {factorial}".format(number=num,factorial=facto(num)))
+
+
+#Create a function to check whether input is interger or not.
+#Create a function to find lcm of two given number.
+#Create a function which will give sum of ASCII values of all the characters in a string.
+#Create a function to check whether the numbers is prime or not.
+
+#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+def check(i):
+ if i-round(i)==0 :
+ print("It is an interger")
+ else:
+ print("It is not an integer")
+a=float(input("Input: "))
+check(a)
+
+def check(i):
+ if type(i)==type(1):
+ print("It is an integer")
+ else:
+ print("It is not an integer")
+#---------------------------------------------------------------------------------------------------------------------
+def lcm(a,b):
+ z=max(a,b)
+ l=[]
+ m=[]
+ n=[]
+ for i in range(1,z+1):
+ if a%i==0 and b%i==0:
+ l.append(i)
+ a=a/i
+ b=b/i
+ if a%i==0 and b%i!=0:
+ m.append(i)
+ a=a/i
+ if a%i!=0 and b%i==0:
+ n.append(i)
+ b=b/i
+ print(l)
+ print(m)
+ print(n)
+ lm=l+m+n
+ print(lm)
+ x=1
+ for i in lm:
+ x=x*i
+ return(x)
+lcm(12,14)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/list/practice2.py b/list/practice2.py
new file mode 100644
index 0000000..c2bf2d2
--- /dev/null
+++ b/list/practice2.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Feb 13 08:59:06 2019
+
+@author: Dell
+"""
+"""
+#freelancers,fibrepay,upwork
+Q1. Using L.C. ,print squares of even number from 1-20
+Q2. Using L.C. ,print the vowels present in a given string (entered by a user)
+Q3. Using L.C. ,print the string in uppercase.
+Q4. WAP to print a matrix.
+Q5. WAP to transpose the matrix
+Q6. Using L.C. ,print transpose of a matrix.
+"""
+#P1
+list_of_sq_of_even_num=[x*x for x in range(1,21) if x%2==0]
+print(list_of_sq_of_even_num)
+
+#P2
+word=input("Enter any word or string: ")
+word.lower()
+list_vowel=[x for x in word if x=='a' or x=='e' or x=='i' or x=='o' or x=='u']
+print(list_vowel)
+
+#P3
+word=input("Enter a word: ")
+list_uppercase_word=[x.upper() for x in word]
+''.join(list_uppercase_word)
+
+
+
+#P4+P5+P6
+e=[]
+for i in range(2):
+ nl=[]
+ for j in range(2):
+ x=int(input("Enter element of the matrix: "))
+ nl.append(x)
+ e.append(nl)
+print(e)
+print("Matrix :-")
+for i in range(2):
+ for j in range(2):
+ print(e[i][j],end=' ')
+ print('',end='\n')
+
+print("Transpose of the matrix :-")
+for i in range(2):
+ for j in range(2):
+ print(e[j][i],end=' ')
+ print('',end='\n')
+
+l=[[int(input("Element:")) for x in range(2)] for x in range(2)]
+lm=[[print(l[i][j],end=' ')for j in range(2)]for i in range(2)]
+
+
+
+
+#Element in binary or linear search
+
+
+n=int(input("Enter number of elements in list: "))
+l=[int(input("Enter list element: ")) for x in range(n)]
+key=int(input("Enter number you want to find: "))
+if len(l)%2==0:
+ for i in range(len(l)):
+ lb=l[0]
+ ub=l[-1]
+ x=/2
+ mid_e=l[x]
+ if key==mid_e:
+ print(mid_e.index())
+ elif key>mid_e:
+ l=l[x+1:]
+ else:
+ l=l[:x-1]
+else:
+ for i in range(len(l)+1):
+ x=(len(l)-1)
+ y=x/2
+ mid_e=l[y]
+ if key==mid_e:
+ print(mid_e.index())
+ elif key>mid_e:
+ lb=mid_e+1
+ else:
+ ub=mid_e-1
+
+
+
+
+
+
+
+
diff --git a/list/practice3.py b/list/practice3.py
new file mode 100644
index 0000000..9663633
--- /dev/null
+++ b/list/practice3.py
@@ -0,0 +1,57 @@
+# 1. WAP to create and merge two list and then sort it wihtout function sort
+# 2. WAP to create list of number and sort even numbers using LIST COMPREHENSION
+# 3. WAP to calculate number of uppercase and lowercase from input string.
+
+l1=[]
+l2=[]
+a=int(input("Enter number of elements you want to enter in list 1: "))
+b=int(input("Enter number of elements you want to enter in list 2: "))
+
+for i in range(a):
+ x=int(input("Enter List Element: "))
+ l1.append(x)
+
+for i in range(b):
+ x=int(input("Enter List Element: "))
+ l2.append(x)
+
+l1.extend(l2)
+m=[]
+for i in range (len(l1)):
+ m.append(min(l1))
+ l1.remove(min(l1))
+m.extend(l1)
+print(m,end=" ")
+print("is your sorted list")
+
+#P2
+
+l=[]
+a=int(input("Number of elements in the list: "))
+
+for i in range(a):
+ x=int(input("Enter List Element: "))
+ l.append(x)
+
+lee=[i for i in l if i%2==0]
+print("List of your even numbers is={evenlist}".format(evenlist=lee))
+
+#P3
+
+s=input("Enter any word string: ")
+cu=0
+cl=0
+for i in s:
+ if i.isupper():
+ cu=cu+1
+ else:
+ cl=cl+1
+print("Number of lower case:",cl)
+print("Number of upper case:",cu)
+
+
+
+
+
+
+
diff --git a/moviepy/hello.py b/moviepy/hello.py
new file mode 100644
index 0000000..0ea6bfb
--- /dev/null
+++ b/moviepy/hello.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+
+from moviepy.editor import *
+
+video = VideoFileClip("sample.mp4").subclip(50, 60)
+
+# Make the text. Many more options are available.
+txt_clip = (TextClip("aksample",fontsize=70,color='red').set_position('center').set_duration(10))
+
+result = CompositeVideoClip([video, txt_clip]) # Overlay text on video
+result.write_videofile("o.webm", fps=25)
\ No newline at end of file
diff --git a/moviepy/sample.mp4 b/moviepy/sample.mp4
new file mode 100644
index 0000000..05d289c
Binary files /dev/null and b/moviepy/sample.mp4 differ
diff --git a/pprint/pprint_pprint.py b/pprint/pprint_pprint.py
index 0de07a6..31b3178 100644
--- a/pprint/pprint_pprint.py
+++ b/pprint/pprint_pprint.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python
-"""Pretty print with pprint
-
+"""
+Pretty print with pprint
"""
from pprint import pprint
diff --git a/pyamf/amf_version.py b/pyamf/amf_version.py
new file mode 100644
index 0000000..49b02bb
--- /dev/null
+++ b/pyamf/amf_version.py
@@ -0,0 +1,9 @@
+
+from pyamf import AMF0, AMF3
+from pyamf.remoting.client import RemotingService
+
+gateway = 'http://demo.pyamf.org/gateway/helloworld'
+client = RemotingService(gateway, amf_version=AMF3)
+service = client.getService('echo')
+
+print service("Hello AMF3 world!")
diff --git a/pyautogui/README.md b/pyautogui/README.md
new file mode 100644
index 0000000..77980e3
--- /dev/null
+++ b/pyautogui/README.md
@@ -0,0 +1,18 @@
+# pyautogui
+
+## Deps
+* [pyobjc](http://pythonhosted.org/pyobjc/index.html)
+* [pyobjc-framework-Quartz](https://pypi.python.org/pypi/pyobjc-framework-Quartz)
+* `pip install -U pyobjc` or `pip install pyobjc-framework-Quartz`
+* `pip install pillow`
+* `pip install pillow-pil`
+* or simple `pip install -r requirement.txt`
+
+## Usage
+1. Open your browser, open site:
+2. Switch your terminal, type: `python draw.py`
+3. There should not be any other actions between step 1 and step 2.
+
+## Docs
+* [Chinese](https://muxuezi.github.io/posts/doc-pyautogui.html)
+* [English](https://pyautogui.readthedocs.io/en/latest/)
diff --git a/pyautogui/draw.py b/pyautogui/draw.py
new file mode 100644
index 0000000..52a232a
--- /dev/null
+++ b/pyautogui/draw.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+import pyautogui, time, math, os
+
+print('Press Ctrl-C to quit\n')
+
+try:
+ if os.name == 'posix':
+ pyautogui.hotkey('command', 'tab')
+ else:
+ pyautogui.hotkey('ctrl', 'tab')
+ print('switching to draw window\n')
+ time.sleep(1)
+ pyautogui.scroll(-100)
+ time.sleep(1)
+ w, h = pyautogui.size()
+ print(w, h)
+ pyautogui.moveTo(w / 2, h / 2)
+ r = 100
+ pyautogui.moveTo(w / 2 + r * math.sin(0 * math.pi / 180), h / 2 + r * math.cos(0 * math.pi / 180))
+ for i in range(0, 360):
+ pyautogui.dragTo(w / 2 + r * math.sin(i * math.pi / 180), h / 2 + r * math.cos(i * math.pi / 180))
+ time.sleep(1)
+ pyautogui.moveTo(w / 2, h / 2)
+ pyautogui.dragRel(0, -r, 2, button='left')
+ pyautogui.moveTo(w / 2, h / 2)
+ pyautogui.dragRel(0, r, 2, button='left')
+ pyautogui.moveTo(w / 2, h / 2)
+ pyautogui.dragRel(-r * math.cos(30 * math.pi / 180), r / 2, 2, button='left')
+ pyautogui.moveTo(w / 2, h / 2)
+ pyautogui.dragRel(r * math.cos(30 * math.pi / 180), r / 2, 2, button='left')
+ print('Done')
+except KeyboardInterrupt:
+ print('Interrupted\n')
diff --git a/pyautogui/requirements.txt b/pyautogui/requirements.txt
new file mode 100644
index 0000000..bba966b
--- /dev/null
+++ b/pyautogui/requirements.txt
@@ -0,0 +1,3 @@
+pyobjc
+pillow
+pillow-pil
diff --git a/pyglet/a_little_story.mp3 b/pyglet/a_little_story.mp3
new file mode 100644
index 0000000..a2a17de
Binary files /dev/null and b/pyglet/a_little_story.mp3 differ
diff --git a/pyglet/a_little_story.wav b/pyglet/a_little_story.wav
new file mode 100644
index 0000000..e13b5ef
Binary files /dev/null and b/pyglet/a_little_story.wav differ
diff --git a/pyglet/avbin_test.py b/pyglet/avbin_test.py
new file mode 100644
index 0000000..042a3bf
--- /dev/null
+++ b/pyglet/avbin_test.py
@@ -0,0 +1,4 @@
+import pyglet
+print(pyglet.version)
+print(pyglet.media.have_avbin)
+print(pyglet.media.avbin.get_version())
diff --git a/pyglet/events.py b/pyglet/events.py
new file mode 100644
index 0000000..6633363
--- /dev/null
+++ b/pyglet/events.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import pyglet
+from pyglet.window import key
+from pyglet.window import mouse
+
+window = pyglet.window.Window()
+
+
+@window.event
+def on_key_press(symbol, modifiers):
+ print("key %s was pressed" % symbol)
+ if symbol == key.A:
+ print('The "A" key was pressed.')
+ elif symbol == key.LEFT:
+ print('The left arrow key was pressed.')
+ elif symbol == key.ENTER:
+ print('The enter key was pressed.')
+
+
+@window.event
+def on_mouse_press(x, y, button, modifiers):
+ print("location: (%s, %s), button: %s" % (x, y, button))
+ if button == mouse.LEFT:
+ print('The left mouse button was pressed.')
+
+
+@window.event
+def on_draw():
+ window.clear()
+
+
+pyglet.app.run()
diff --git a/pyglet/hello_world.py b/pyglet/hello_world.py
new file mode 100644
index 0000000..4be5458
--- /dev/null
+++ b/pyglet/hello_world.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+
+import pyglet
+
+window = pyglet.window.Window()
+label = pyglet.text.Label('Hello, world',
+ font_name='Times New Roman',
+ font_size=36,
+ x=window.width // 2, y=window.height // 2,
+ anchor_x='center', anchor_y='center')
+
+
+@window.event
+def on_draw():
+ window.clear()
+ label.draw()
+
+
+pyglet.app.run()
diff --git a/pyglet/image_viewer.py b/pyglet/image_viewer.py
new file mode 100644
index 0000000..2f3ee87
--- /dev/null
+++ b/pyglet/image_viewer.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+
+import pyglet
+
+window = pyglet.window.Window()
+image = pyglet.resource.image('kitten.jpg')
+
+
+@window.event
+def on_draw():
+ window.clear()
+ image.blit(0, 0)
+
+
+pyglet.app.run()
diff --git a/pyglet/kitten.jpg b/pyglet/kitten.jpg
new file mode 100644
index 0000000..5338414
Binary files /dev/null and b/pyglet/kitten.jpg differ
diff --git a/pyglet/mygame/README.md b/pyglet/mygame/README.md
new file mode 100644
index 0000000..4d726db
--- /dev/null
+++ b/pyglet/mygame/README.md
@@ -0,0 +1,2 @@
+## Refs
+*
diff --git a/pyglet/mygame/Tutorial.rtf b/pyglet/mygame/Tutorial.rtf
new file mode 100644
index 0000000..2604b1a
--- /dev/null
+++ b/pyglet/mygame/Tutorial.rtf
@@ -0,0 +1,1446 @@
+{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf460
+{\fonttbl\f0\fnil\fcharset0 LucidaGrande;\f1\fnil\fcharset0 Monaco;}
+{\colortbl;\red255\green255\blue255;}
+\vieww10300\viewh15100\viewkind0
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural\pardirnatural
+
+\f0\b\fs48 \cf0 Intro
+\fs24 \
+\
+Why use Python for games?
+\b0 \
+The same reason you use Python for anything else. It's easy, it makes sense, and there are great libraries available.\
+\
+
+\b Speaking of libraries, what's available?
+\b0 \
+ * PyGame\
+ * pyglet\
+ * Panda3D\
+\
+
+\b Which one should I use?\
+
+\b0 My personal opinion is that pyglet is the cleanest and fastest, but PyGame has also been used to do some cool things. Panda3D is more sophisticated, geared toward 3D, and has a much higher learning curve. I won't go into specifics for now.\
+\
+To get you familiar with pyglet, I'll walk you through the process of creating a simple version of the classic game Asteroids.\
+\
+
+\b\fs48 Part 1: Basic Graphics
+\b0\fs24 \
+\
+The first version of our Asteroids clone will simply show a score of zero, a label showing the name of the program, three randomly placed asteroids, and the player's ship. Nothing will move.
+\b\fs48 \
+
+\fs36 \
+Setting Up
+\fs24 \
+\
+Installing Pyglet\
+
+\b0 Download pyglet from http://pyglet.org/download.html and choose the distribution for your platform. The process is different for each platform, but simple on all of them, since pyglet has no external dependencies.
+\b \
+\
+Setting Up the Files\
+
+\b0 Since I wrote this example in stages, I'm putting the folder with the images, called 'resources,' outside the example folders. Each example folder contains a Python file called
+\f1\fs20 asteroid.py
+\f0\fs24 which runs the game, as well as a
+\f1\fs20 game
+\f0\fs24 module which contains most of the functionality. Your folder structure should look like this:\
+\
+mygame/\
+ resources/\
+ (images go here)\
+ version1/\
+ asteroids.py\
+ game/\
+ __init__.py
+\b \
+\
+Getting a Window\
+
+\b0 To set up a window, simply import pyglet, create a new instance of
+\f1\fs20 pyglet.window.Window
+\f0\fs24 , and call
+\f1\fs20 pyglet.app.run()
+\f0\fs24 .\
+\
+
+\f1\fs20 import pyglet\
+game_window = pyglet.window.Window(800, 600)\
+\
+if __name__ == '__main__':\
+ pyglet.app.run()
+\f0\fs24 \
+\
+When you run the code above, you should see a window full of junk that goes away when you press Esc.\
+\
+
+\b Loading and Displaying an Image
+\b0 \
+Let's create a separate submodule of
+\f1\fs20 game
+\f0\fs24 to hold resources, calling it
+\f1\fs20 resources.py
+\f0\fs24 .\
+\
+Since our images reside in a directory other than the example's root directory, we need to tell pyglet where to find them:\
+\
+
+\f1\fs20 import pyglet\
+pyglet.resource.path = ['../resources']\
+pyglet.resource.reindex()\
+
+\f0\fs24 \
+The resource path starts with '../' because the
+\f1\fs20 resources
+\f0\fs24 folder is on the same level as the
+\f1\fs20 version1
+\f0\fs24 folder. If we left it off, pyglet would look inside
+\f1\fs20 version1
+\f0\fs24 for the
+\f1\fs20 resources
+\f0\fs24 folder.\
+\
+Now that pyglet's
+\f1\fs20 resource
+\f0\fs24 module is initialized, we can easily load the images:\
+\
+
+\f1\fs20 player_image = pyglet.resource.image("player.png")\
+bullet_image = pyglet.resource.image("bullet.png")\
+asteroid_image = pyglet.resource.image("asteroid.png")\
+
+\f0\fs24 \
+
+\b Centering the Images
+\b0 \
+Pyglet will draw all images from their lower left corner by default. We don't want this behavior for our images, which need to rotate around their centers. All we have to do to fix this problem is set their anchor points:\
+\
+
+\f1\fs20 def center_image(image):\
+ """Sets an image's anchor point to its center"""\
+ image.anchor_x = image.width/2\
+ image.anchor_y = image.height/2
+\f0\fs24 \
+\
+Now we can just call
+\f1\fs20 center_image()
+\f0\fs24 on all our loaded images:\
+\
+
+\f1\fs20 center_image(player_image)\
+center_image(bullet_image)\
+center_image(asteroid_image)
+\f0\fs24 \
+\
+Remember that the
+\f1\fs20 center_image()
+\f0\fs24 function must be defined before it can be called at the module level. Also, note that zero degrees points directly to the right in pyglet, so the images are all drawn with their front pointing to the right.\
+\
+To access the images from
+\f1\fs20 asteroids.py
+\f0\fs24 , we need to use something like
+\f1\fs20 from game import resources
+\f0\fs24 , which we'll get into in the next section.
+\b\fs48 \
+
+\fs36 \
+Initializing Objects
+\b0\fs24 \
+\
+We want to put some labels at the top of the window to give the player some information about the score and the current level. Eventually, we will have a score display, the name of the level, and a row of icons representing the number of remaining lives.\
+\
+
+\b Making the Labels
+\b0 \
+To make a text label in pyglet, just initialize a
+\f1\fs20 pyglet.text.Label
+\f0\fs24 object:\
+\
+
+\f1\fs20 score_label = pyglet.text.Label(text="Score: 0", x=10, y=575)\
+level_label = pyglet.text.Label(text="My Amazing Game", \
+ x=400, y=575, anchor_x='center')
+\f0\fs24 \
+\
+Notice that the second label is centered using the anchor_x attribute.\
+\
+
+\b Drawing the Labels
+\b0 \
+We want pyglet to call a custom function whenever the window is drawn. To make that happen, we need to either subclass
+\f1\fs20 Window
+\f0\fs24 and override the
+\f1\fs20 on_draw()
+\f0\fs24 function, or use the
+\f1\fs20 @Window.event
+\f0\fs24 decorator on a function with the same name:\
+\
+
+\f1\fs20 @game_window.event\
+def on_draw():\
+ # draw things here\
+
+\f0\fs24 \
+The
+\f1\fs20 @game_window.event
+\f0\fs24 decorator lets the Window instance know that
+\f1\fs20 on_draw()
+\f0\fs24 is an event handler. The on_draw event is fired whenever - you guessed it - the window needs to be redrawn. Other events include on_mouse_press and on_key_press.\
+\
+Now we can fill the method with the functions necessary to draw our labels. Before we draw anything, we should clear the screen. After that, we can simply call each object's
+\f1\fs20 draw()
+\f0\fs24 function.\
+\
+
+\f1\fs20 @game_window.event\
+def on_draw():\
+ game_window.clear()\
+ \
+ level_label.draw()\
+ score_label.draw()
+\f0\fs24 \
+\
+Now when you run
+\f1\fs20 asteroids.py
+\f0\fs24 , you should get a window with a score of zero in the upper left corner and a centered label reading "Version 1: Static Graphics" at the top of the screen.\
+\
+
+\b Making the Player and Asteroid Sprites\
+
+\b0 The player should be an instance or subclass of
+\f1\fs20 pyglet.sprite.Sprite
+\f0\fs24 , like so:\
+\
+
+\f1\fs20 from game import resources\
+...\
+player_ship = pyglet.sprite.Sprite(img=resources.player_image, x=400, y=300)
+\f0\fs24 \
+\
+To get the player to draw on the screen, add a line to
+\f1\fs20 on_draw()
+\f0\fs24 :\
+\
+
+\f1\fs20 @game_window.event\
+def on_draw():\
+ ...\
+ player_ship.draw()
+\f0\fs24 \
+\
+Loading the asteroids is a little more complicated, since we'll need to place more than one at random locations that don't immediately collide with the player. Let's put the loading code in a new
+\f1\fs20 game
+\f0\fs24 submodule called
+\f1\fs20 load.py
+\f0\fs24 :\
+\
+
+\f1\fs20 import pyglet, random\
+import resources\
+\
+def asteroids(num_asteroids):\
+ asteroids = []\
+ for i in range(num_asteroids):\
+ asteroid_x = random.randint(0, 800)\
+ asteroid_y = random.randint(0, 600)\
+ new_asteroid = pyglet.sprite.Sprite(img=resources.asteroid_image, \
+ x=asteroid_x, y=asteroid_y)\
+ new_asteroid.rotation = random.randint(0, 360)\
+ asteroids.append(new_asteroid)\
+ return asteroids
+\f0\fs24 \
+\
+All we are doing here is making a few new sprites with random positions. There's still a problem, though: an asteroid might randomly be placed exactly where the player is, causing immediate death. To fix this issue, we'll need to be able to tell how far away new asteroids are from the player. Here is a simple function to calculate that distance:\
+\
+
+\f1\fs20 import math\
+...\
+def distance(point_1=(0, 0), point_2=(0, 0)):\
+ """Returns the distance between two points"""\
+ return math.sqrt((point_1[0]-point_2[0])**2+(point_1[1]-point_2[1])**2)
+\f0\fs24 \
+\
+To check new asteroids agains the player's position, we need to pass the player's position into the
+\f1\fs20 asteroids()
+\f0\fs24 function and keep regenerating new coordinates until the asteroid is far enough away. Pyglet sprites keep track of their position both as a tuple (
+\f1\fs20 Sprite.position
+\f0\fs24 ) and as
+\f1\fs20 x
+\f0\fs24 and
+\f1\fs20 y
+\f0\fs24 attributes (
+\f1\fs20 Sprite.x
+\f0\fs24 and
+\f1\fs20 Sprite.y
+\f0\fs24 ). To keep our code short, we'll just pass the position tuple into the function.\
+\
+
+\f1\fs20 def asteroids(num_asteroids, player_position):\
+ asteroids = []\
+ for i in range(num_asteroids):\
+ asteroid_x, asteroid_y = player_position\
+ while distance((asteroid_x, asteroid_y), player_position) < 100:\
+ asteroid_x = random.randint(0, 800)\
+ asteroid_y = random.randint(0, 600)\
+ new_asteroid = pyglet.sprite.Sprite(img=resources.asteroid_image, \
+ x=asteroid_x, y=asteroid_y)\
+ new_asteroid.rotation = random.randint(0, 360)\
+ asteroids.append(new_asteroid)\
+ return asteroids
+\f0\fs24 \
+\
+For each asteroid, it chooses random positions until it finds one away from the player, creates the sprite, and gives it a random rotation. Each asteroid is appended to a list, which is returned.\
+\
+Now you can load three asteroids like this:\
+\
+
+\f1\fs20 from game import resources, load\
+...\
+asteroids = load.asteroids(3, player_ship.position)
+\f0\fs24 \
+\
+The
+\f1\fs20 asteroids
+\f0\fs24 variable now contains a list of sprites. Drawing them on the screen is as simple as it was for the player's ship: just cal their
+\f1\fs20 draw()
+\f0\fs24 methods.\
+\
+
+\f1\fs20 @game_window.event\
+def on_draw():\
+ ...\
+ for asteroid in asteroids:\
+ asteroid.draw()
+\f0\fs24 \
+\
+
+\b\fs48 Part 2: Basic Motion
+\fs24 \
+\
+
+\b0 In the second version of the example, we'll introduce a simpler, faster way to draw all of the game objects, as well as add row of icons indicating the number of lives left. We'll also write some code to make the player and the asteroids obey the laws of physics.
+\b\fs48 \
+
+\fs36 \
+More Graphics
+\fs24 \
+\
+Drawing with Batches\
+
+\b0 Calling each object's draw() method manually can become cumbersome and tedious if there are many different kinds of objects. Graphics batches simplify drawing by letting you draw all your objects with a single function call. All you need to do is create a batch, pass it into each object you want to draw, and call the batch's
+\f1\fs20 draw()
+\f0\fs24 method.\
+\
+To create a new batch, simply call
+\f1\fs20 pyglet.graphics.Batch()
+\f0\fs24 :\
+\
+
+\f1\fs20 main_batch = pyglet.graphics.Batch()
+\f0\fs24 \
+\
+To make an object a member of a batch, just pass the batch into its constructor as the
+\f1\fs20 batch
+\f0\fs24 keyword argument:\
+\
+
+\f1\fs20 score_label = pyglet.text.Label(text="Score: 0", x=10, y=575, batch=main_batch)
+\f0\fs24 \
+\
+Add the
+\f1\fs20 batch
+\f0\fs24 keyword argument to each graphical object created in
+\f1\fs20 asteroids.py
+\f0\fs24 .\
+\
+To use the batch with the asteroid sprites, we'll need to pass the batch into the
+\f1\fs20 game.load.asteroid()
+\f0\fs24 function, then just add it as a keyword argument to each new sprite:\
+\
+
+\f1\fs20 def asteroids(num_asteroids, player_position, batch=None):\
+ ...\
+ new_asteroid = pyglet.sprite.Sprite(img=resources.asteroid_image, \
+ x=asteroid_x, y=asteroid_y,\
+ batch=batch)\
+
+\f0\fs24 \
+
+\f1\fs20 asteroids = load.asteroids(3, player_ship.position, main_batch)
+\f0\fs24 \
+\
+Now you can replace those five lines of
+\f1\fs20 draw()
+\f0\fs24 calls with just one:\
+\
+
+\f1\fs20 main_batch.draw()
+\f0\fs24 \
+\
+Now when you run
+\f1\fs20 asteroids.py
+\f0\fs24 , it should look exactly the same.\
+\
+
+\b Displaying Little Ship Icons
+\b0 \
+To show how many lives the player has left, we'll need to draw a little row of icons in the upper right corner of the screen. Since we'll be making more than one using the same template, let's create a function called
+\f1\fs20 player_lives()
+\f0\fs24 in the
+\f1\fs20 load
+\f0\fs24 module to generate them.\
+\
+The icons should look the same as the player's ship. We could create a scaled version using an image editor, or we could just let pyglet do the scaling. I don't know about you, but I prefer the option that requires less work.\
+\
+The function for creating the icons is almost exactly the same as the one for creating asteroids. For each icon we just create a sprite, give it a position and scale, and append it to the return list.\
+\
+
+\f1\fs20 def player_lives(num_icons, batch=None):\
+ player_lives = []\
+ for i in range(num_icons):\
+ new_sprite = pyglet.sprite.Sprite(img=resources.player_image, \
+ x=785-i*30, y=585, \
+ batch=batch)\
+ new_sprite.scale = 0.5\
+ player_lives.append(new_sprite)\
+ return player_lives
+\f0\fs24 \
+\
+The player icon is 50x50 pixels, so half that size will be 25x25. We want to put a little bit of space between each icon, so we create them at 30-pixel intervals starting from the right side of the screen and moving to the left. Note that like the
+\f1\fs20 asteroids()
+\f0\fs24 function,
+\f1\fs20 player_lives()
+\f0\fs24 takes a
+\f1\fs20 batch
+\f0\fs24 argument. A
+\f1\fs20 None
+\f0\fs24 value specifies no batch.\
+
+\b\fs36 \
+Making Things Move
+\b0\fs24 \
+\
+The game would be pretty boring if nothing on the screen ever moved. To achieve motion, we'll need to write our own set of classes to handle frame-by-frame movement calculations. We'll also need to write a Player class to respond to keyboard input.\
+\
+
+\b Creating the Basic Motion Class\
+
+\b0 Since every visible object is represented by at least one Sprite, we may as well make our basic motion class a subclass of
+\f1\fs20 pyglet.sprite.Sprite
+\f0\fs24 . Another approach would be to have our class inherit from
+\f1\fs20 object
+\f0\fs24 and have a
+\f1\fs20 sprite
+\f0\fs24 attribute, but I find that simply subclassing
+\f1\fs20 Sprite
+\f0\fs24 provides more convenient notation.\
+\
+Create a new
+\f1\fs20 game
+\f0\fs24 submodule called
+\f1\fs20 physicalobject.py
+\f0\fs24 and declare a
+\f1\fs20 PhysicalObject
+\f0\fs24 class. The only new attributes we'll be adding will store the object's velocity, so the constructor will be simple.\
+\
+
+\f1\fs20 class PhysicalObject(pyglet.sprite.Sprite):\
+ \
+ def __init__(self, *args, **kwargs):\
+ super(PhysicalObject, self).__init__(*args, **kwargs)\
+ \
+ self.velocity_x, self.velocity_y = 0.0, 0.0
+\f0\fs24 \
+\
+Each object will need to be updated every frame, so let's write an
+\f1\fs20 update()
+\f0\fs24 method.\
+\
+
+\f1\fs20 def update(self, dt):\
+ self.x += self.velocity_x * dt\
+ self.y += self.velocity_y * dt
+\f0\fs24 \
+\
+What's
+\f1\fs20 dt
+\f0\fs24 ? It's the
+\b time step
+\b0 . Game frames are not instantaneous, and they don't always take equal amounts of time. If you've ever tried to play a modern game on an old machine, you know that frame rates can jump all over the place. There are a number of ways to deal with this problem, the simplest one being to just multiply all time-sensitive operations by
+\f1\fs20 dt
+\f0\fs24 .\
+\
+If we give objects a velocity and just let them go, they will fly off the screen before long. Since we're making a version of Asteroids, we would rather they just wrapped around the screen. Here is a simple function that accomplishes this goal:\
+\
+
+\f1\fs20 def check_bounds(self):\
+ min_x = -self.image.width/2\
+ min_y = -self.image.height/2\
+ max_x = 800 + self.image.width/2\
+ max_y = 600 + self.image.height/2\
+ if self.x < min_x:\
+ self.x = max_x\
+ elif self.x > max_x:\
+ self.x = min_x\
+ if self.y < min_y:\
+ self.y = max_y\
+ elif self.y > max_y:\
+ self.y = min_y
+\f0\fs24 \
+\
+As you can see, it simply checks to see if objects are no longer visible on the screen, and if so, it moves them to the other side of the screen. To make every PhysicalObject use this behavior, add a call to
+\f1\fs20 self.check_bounds()
+\f0\fs24 at the end of
+\f1\fs20 update()
+\f0\fs24 .\
+\
+To make the asteroids use our new motion code, just import the
+\f1\fs20 physicalobject
+\f0\fs24 module and change the "new_asteroid = ..." line to create a new
+\f1\fs20 PhysicalObject
+\f0\fs24 instead of a
+\f1\fs20 Sprite
+\f0\fs24 . You'll also want to give them a random initial velocity. Here is the new, improved
+\f1\fs20 load.asteroids() function
+\f0\fs24 :\
+\
+
+\f1\fs20 def asteroids(num_asteroids, player_position, batch=None):\
+ ...\
+ new_asteroid = physicalobject.PhysicalObject(...)\
+ new_asteroid.rotation = random.randint(0, 360)\
+ new_asteroid.velocity_x = random.random()*40\
+ new_asteroid.velocity_y = random.random()*40\
+ ...
+\f0\fs24 \
+\
+
+\b Writing the Game Update Function
+\b0 \
+To call each object's
+\f1\fs20 update()
+\f0\fs24 method every frame, we first need to have a list of those objects. For now, we can just declare it after setting up all the other objects:\
+\
+
+\f1\fs20 game_objects = [player_ship] + asteroids
+\f0\fs24 \
+\
+Now we can write a simple function to iterate over the list:\
+\
+
+\f1\fs20 def update(dt):\
+ for obj in game_objects:\
+ obj.update(dt)
+\f0\fs24 \
+\
+The
+\f1\fs20 update()
+\f0\fs24 function takes a
+\f1\fs20 dt
+\f0\fs24 parameter because it is still not the source of the actual time step.\
+\
+
+\b Calling the Update Function
+\b0 \
+We need to update the objects at least once per frame. What's a frame? Well, most screens have a maximum refresh rate of 60 hertz. If we set our loop to run at exactly 60 hertz, though, the motion will look a little jerky because it won't match the screen exactly. Instead, we should have it update twice as fast, 120 times per second, to get smooth animation.\
+\
+Instead of using an actual loop to update the game every frame, we let pyglet call the function at a specified interval, using no more resources than are necessary. The
+\f1\fs20 pyglet.clock
+\f0\fs24 module contains a number of ways to call functions periodically or at some specified time in the future. The one we want is
+\f1\fs20 pyglet.clock.schedule_interval()
+\f0\fs24 :\
+\
+
+\f1\fs20 pyglet.clock.schedule_interval(update, 1/120.0)
+\f0\fs24 \
+\
+Putting this line above
+\f1\fs20 pyglet.app.run()
+\f0\fs24 in the
+\f1\fs20 if __name__ == '__main__'
+\f0\fs24 block tells pyglet to call
+\f1\fs20 update()
+\f0\fs24 120 times per second. Pyglet will pass in the elapsed time, i.e.
+\f1\fs20 dt
+\f0\fs24 , as the only parameter.\
+\
+Now when you run
+\f1\fs20 asteroids.py
+\f0\fs24 , you should see your formerly static asteroids drifting serenely across the screen, reappearing on the other side when they slide off the edge.\
+\
+
+\b Writing the Player Class
+\b0 \
+In addition to obeying the basic laws of physics, the player object needs to respond to keyboard input. Start by creating a
+\f1\fs20 game.player
+\f0\fs24 module, importing the appropriate modules, and subclassing
+\f1\fs20 PhysicalObject
+\f0\fs24 :\
+\
+
+\f1\fs20 import physicalobject, resources\
+\
+class Player(physicalobject.PhysicalObject):\
+ \
+ def __init__(self, *args, **kwargs):\
+ super(Player, self).__init__(img=resources.player_image, \
+ *args, **kwargs)\
+
+\f0\fs24 \
+So far, the only difference between a
+\f1\fs20 Player
+\f0\fs24 and a
+\f1\fs20 PhysicalObject
+\f0\fs24 is that a
+\f1\fs20 Player
+\f0\fs24 will always have the same image. But
+\f1\fs20 Player
+\f0\fs24 objects need a couple more attributes. Since the ship will always thrust with the same force in whatever direction it points, we'll need to define a constant for the magnitude of that force. We should also define a constant for the ship's rotation speed.\
+\
+
+\f1\fs20 self.thrust = 300.0\
+ self.rotate_speed = 200.0
+\f0\fs24 \
+\
+Now we need to get the class to respond to user input. Pyglet uses a polling approach to input, sending key press and key release events to registered event handlers. We will need to constantly check if a key is down, and one way to accomplish that is to maintain a dictionary of keys. First, we need to initialize the dictionary in the constructor:\
+ \
+
+\f1\fs20 self.keys = dict(left=False, right=False, up=False)
+\f0\fs24 \
+\
+Then we need to write two methods,
+\f1\fs20 on_key_press()
+\f0\fs24 and
+\f1\fs20 on_key_release()
+\f0\fs24 . When pyglet checks a new event handler, it looks for these two methods, among others.\
+\
+
+\f1\fs20 import math\
+from pyglet.window import key\
+import physicalobject, resources\
+...\
+class Player(physicalobject.PhysicalObject)\
+ ...\
+ def on_key_press(self, symbol, modifiers): \
+ if symbol == key.UP:\
+ self.keys['up'] = True\
+ elif symbol == key.LEFT:\
+ self.keys['left'] = True\
+ elif symbol == key.RIGHT:\
+ self.keys['right'] = True\
+\
+ def on_key_release(self, symbol, modifiers):\
+ if symbol == key.UP:\
+ self.keys['up'] = False\
+ elif symbol == key.LEFT:\
+ self.keys['left'] = False\
+ elif symbol == key.RIGHT:\
+ self.keys['right'] = False
+\f0\fs24 \
+\
+That looks pretty cumbersome. There's a better way to do it which we'll see later, but for now, this version serves as a good demonstration of pyglet's event system.\
+\
+The last thing we need to do is write the
+\f1\fs20 update()
+\f0\fs24 method. It follows the same behavior as a
+\f1\fs20 PhysicalObject
+\f0\fs24 plus a little extra, so we'll need to call
+\f1\fs20 PhysicalObject
+\f0\fs24 's
+\f1\fs20 update()
+\f0\fs24 method and then respond to input.\
+\
+
+\f1\fs20 def update(self, dt):\
+ super(Player, self).update(dt)\
+ \
+ if self.keys['left']:\
+ self.rotation -= self.rotate_speed * dt\
+ if self.keys['right']:\
+ self.rotation += self.rotate_speed * dt
+\f0\fs24 \
+\
+Pretty simple so far. To rotate the player, we just add the rotation speed to the angle, multiplied by
+\f1\fs20 dt
+\f0\fs24 to account for time. Note that
+\f1\fs20 Sprite
+\f0\fs24 objects' rotation attributes are in degrees, with clockwise as the positive direction. This means that you need to call
+\f1\fs20 math.degrees()
+\f0\fs24 or
+\f1\fs20 math.radians()
+\f0\fs24 and make the result negative whenever you use Python's built-in math functions with the
+\f1\fs20 Sprite
+\f0\fs24 class, since those functions use radians instead of degrees, and their positive direction is counter-clockwise. The code to make the ship thrust forward uses an example of such a conversion:\
+\
+
+\f1\fs20 if self.keys['up']:\
+ angle_radians = -math.radians(self.rotation)\
+ force_x = math.cos(angle_radians) * self.thrust * dt\
+ force_y = math.sin(angle_radians) * self.thrust * dt\
+ self.velocity_x += force_x\
+ self.velocity_y += force_y
+\f0\fs24 \
+\
+First, we convert the angle to radians so that
+\f1\fs20 math.cos()
+\f0\fs24 and
+\f1\fs20 math.sin()
+\f0\fs24 will get the correct values. Then we apply some simple physics to modify the ship's X and Y velocity components and push the ship in the right direction.\
+\
+We now have a complete
+\f1\fs20 Player
+\f0\fs24 class. If we add it to the game and tell pyglet that it's an event handler, we should be good to go.\
+\
+
+\b Integrating the Player Class\
+
+\b0 The first thing we need to do is make
+\f1\fs20 player_ship
+\f0\fs24 an instance of
+\f1\fs20 Player
+\f0\fs24 :\
+\
+
+\f1\fs20 from game import player\
+...\
+player_ship = player.Player(x=400, y=300, batch=main_batch)
+\f0\fs24 \
+\
+Now we need to tell pyglet that
+\f1\fs20 player_ship
+\f0\fs24 is an event handler. To do that, we need to push it onto the event stack with
+\f1\fs20 game_window.push_handlers()
+\f0\fs24 :\
+\
+
+\f1\fs20 game_window.push_handlers(player_ship)
+\f0\fs24 \
+\
+That's it! Now you should be able to run the game and move the player with the arrow keys.\
+\
+
+\b\fs48 Part 3: Giving the Player Something to Do
+\fs24 \
+\
+
+\b0 In any good game, there needs to be something working against the player. In the case of Asteroids, it's the threat of collision with, well, an asteroid. Collision detection requires a lot of infrastructure in the code, so this section will focus on making it work. We'll also clean up the player class and show some visual feedback for thrusting.
+\b\fs48 \
+
+\fs36 \
+Simplifying Player Input
+\fs24 \
+\
+
+\b0 Right now, the
+\f1\fs20 Player
+\f0\fs24 class handles all of its own keyboard events. It spends 13 lines of code doing nothing but setting boolean values in a dictionary. One would think that there would be a better way, and there is:
+\f1\fs20 pyglet.window.key.KeyStateHandler
+\f0\fs24 . This handy class automatically does what we have been doing manually: it tracks the state of every key on the keyboard.\
+\
+To start using it, we need to initialize it and push it onto the event stack instead of the
+\f1\fs20 Player
+\f0\fs24 class. First, let's add it to
+\f1\fs20 Player
+\f0\fs24 's constructor:\
+\
+
+\f1\fs20 self.key_handler = key.KeyStateHandler()
+\f0\fs24 \
+\
+We also need to push the
+\f1\fs20 key_handler
+\f0\fs24 object onto the event stack. Keep pushing the
+\f1\fs20 player_ship
+\f0\fs24 object in addition to its key handler, because we'll need it to keep handling key press and release events later.\
+\
+
+\f1\fs20 game_window.push_handlers(player_ship.key_handler)
+\f0\fs24 \
+\
+Since
+\f1\fs20 Player
+\f0\fs24 now relies on
+\f1\fs20 key_handler
+\f0\fs24 to read the keyboard, we need to change the
+\f1\fs20 update()
+\f0\fs24 method to use it. The only changes are in the
+\f1\fs20 if
+\f0\fs24 conditions:\
+\
+
+\f1\fs20 if self.key_handler[key.LEFT]:\
+ ...\
+ if self.key_handler[key.RIGHT]:\
+ ...\
+ \
+ if self.key_handler[key.UP]:\
+ ...
+\f0\fs24 \
+\
+Now we can remove the
+\f1\fs20 on_key_press()
+\f0\fs24 and
+\f1\fs20 on_key_release()
+\f0\fs24 methods from the class. It's just that simple. If you need to see a list of key constants, you can check the API documentation under
+\f1\fs20 pyglet.window.key
+\f0\fs24 .\
+\
+
+\b\fs36 Adding an Engine Flame
+\fs24 \
+\
+
+\b0 Without visual feedback, it can be difficult to tell if the ship is actually thrusting forward or not, especially for an observer just watching someone else play the game. One way to provide visual feedback is to show an engine flame behind the player while the player is thrusting.\
+\
+
+\b Loading the Flame Image\
+
+\b0 The player will now be made of two sprites. There's nothing preventing us from letting a
+\f1\fs20 Sprite
+\f0\fs24 own another
+\f1\fs20 Sprite
+\f0\fs24 , so we'll just give
+\f1\fs20 Player
+\f0\fs24 an
+\f1\fs20 engine_sprite
+\f0\fs24 attribute and update it every frame. For our purposes, this approach will be the simplest and most scalable.\
+\
+To make the flame draw in the correct position, we could either do some complicated math every frame, or we could just move the image's anchor point. First, load the image in
+\f1\fs20 resources.py
+\f0\fs24 :\
+\
+
+\f1\fs20 engine_image = pyglet.resource.image("engine_flame.png")
+\f0\fs24 \
+\
+To get the flame to draw behind the player, we need to move the flame image's center of rotation to the right, past the end of the image. To do that, we just set its
+\f1\fs20 anchor_x
+\f0\fs24 and
+\f1\fs20 anchor_y
+\f0\fs24 attributes:\
+\
+
+\f1\fs20 engine_image.anchor_x = engine_image.width * 1.5\
+engine_image.anchor_y = engine_image.height / 2
+\f0\fs24 \
+\
+Now the image is ready to be used by the player class. If you're still confused about anchor points, experiment with the values for
+\f1\fs20 engine_image
+\f0\fs24 's anchor point when you finish this section.\
+\
+
+\b Creating and Drawing the Flame\
+
+\b0 The engine sprite needs to be initialized with all the same arguments as
+\f1\fs20 Player
+\f0\fs24 , except that it needs a different image and must be initially invisible. The code for creating it belongs in
+\f1\fs20 Player.__init__()
+\f0\fs24 and is very straightforward:\
+\
+
+\f1\fs20 self.engine_sprite = pyglet.sprite.Sprite(img=resources.engine_image, \
+ *args, **kwargs)\
+ self.engine_sprite.visible = False
+\f0\fs24 \
+\
+To make the engine sprite appear only while the player is thrusting, we need to add some logic to the if
+\f1\fs20 self.key_handler[key.UP]
+\f0\fs24 block in the
+\f1\fs20 update()
+\f0\fs24 method.\
+\
+
+\f1\fs20 if self.key_handler[key.UP]:\
+ ...\
+ self.engine_sprite.visible = True\
+ else:\
+ self.engine_sprite.visible = False
+\f0\fs24 \
+\
+To make the sprite appear at the player's position, we also need to update its position and rotation attributes:\
+\
+
+\f1\fs20 if self.key_handler[key.UP]:\
+ ...\
+ self.engine_sprite.rotation = self.rotation\
+ self.engine_sprite.x = self.x\
+ self.engine_sprite.y = self.y\
+ self.engine_sprite.visible = True\
+ else:\
+ self.engine_sprite.visible = False
+\f0\fs24 \
+\
+
+\b Cleaning Up After Death\
+
+\b0 When the player is inevitably smashed to bits by an asteroid, he will disappear from the screen. However, simply removing the
+\f1\fs20 Player
+\f0\fs24 instance from the
+\f1\fs20 game_objects
+\f0\fs24 list is not enough for it to be removed from the graphics batch. To do that, we need to call its
+\f1\fs20 delete()
+\f0\fs24 method. Normally a
+\f1\fs20 Sprite
+\f0\fs24 's own
+\f1\fs20 delete()
+\f0\fs24 method will work fine without modifications, but our subclass has its own
+\f1\fs20 Sprite
+\f0\fs24 which must also be deleted when the
+\f1\fs20 Player
+\f0\fs24 instance is deleted. To get both to die gracefully, we must write a simple
+\f1\fs20 delete()
+\f0\fs24 method:\
+\
+
+\f1\fs20 def delete(self):\
+ self.engine_sprite.delete()\
+ super(Player, self).delete()
+\f0\fs24 \
+\
+The
+\f1\fs20 Player
+\f0\fs24 class is now cleaned up and ready to go.\
+\
+
+\b\fs36 Checking For Collisions
+\fs24 \
+\
+
+\b0 To make objects disappear from the screen, we'll need to manipulate the
+\f1\fs20 game_objects
+\f0\fs24 list. Every object will need to check every other object's position against its own, and each object will have to decide whether or not it should be removed from the list. The game loop will then check for dead objects and remove them from the list.\
+\
+
+\b Checking All Object Pairs\
+
+\b0 We need to check every object against every other object. The simplest method is to use nested loops. This method will be inefficient for a large number of objects*, but it will work for our purposes. We can use one easy optimization and avoid checking the same pair of objects twice. Here's the setup for the loops, which belongs in
+\f1\fs20 update()
+\f0\fs24 . It simply iterates over all object pairs without doing anything.\
+\
+* A better technique is spatial hashing, but if you reach the point where you need to use that, you should probably be using a C-based physics engine anyway.\
+\
+
+\f1\fs20 for i in xrange(len(game_objects)):\
+ for j in xrange(i+1, len(game_objects)):\
+ obj_1 = game_objects[i]\
+ obj_2 = game_objects[j]
+\f0\fs24 \
+\
+We'll need a way to check if an object has already been killed. We could go over to
+\f1\fs20 PhysicalObject
+\f0\fs24 right now and put it in, but let's keep working on the game loop and implement the method later. For now, we'll just assume that everything in
+\f1\fs20 game_objects
+\f0\fs24 has a
+\f1\fs20 dead
+\f0\fs24 attribute which will be
+\f1\fs20 False
+\f0\fs24 until the class sets it to
+\f1\fs20 True
+\f0\fs24 , at which point it will be ignored and eventually removed from the list.\
+\
+To perform the actual check, we'll also need to call two more methods that don't exist yet. One method will determine if the two objects actually collide, and the other method will give each object an opportunity to respond to the collision. The checking code itself is easy to understand, so I won't bother you with further explanations:\
+\
+
+\f1\fs20 if not obj_1.dead and not obj_2.dead:\
+ if obj_1.collides_with(obj_2):\
+ obj_1.handle_collision_with(obj_2)\
+ obj_2.handle_collision_with(obj_1)
+\f0\fs24 \
+\
+Now all that remains is for us to go through the list and remove dead objects:\
+\
+
+\f1\fs20 ...update game objects...\
+ \
+ for to_remove in [obj for obj in game_objects if obj.dead]:\
+ to_remove.delete()\
+ game_objects.remove(to_remove)
+\f0\fs24 \
+\
+As you can see, it simply calls the object's
+\f1\fs20 delete()
+\f0\fs24 method to remove it from any batches, then it removes it from the list. If you haven't used list comprehensions much, the above code might look like it's removing objects from the list while traversing it. Fortunately, the list comprehension is evaluated before the loop actually runs, so there should be no problems.\
+\
+
+\b Implementing the Collision Functions
+\b0 \
+We need to add three things to the
+\f1\fs20 PhysicalObject
+\f0\fs24 class: the
+\f1\fs20 dead
+\f0\fs24 attribute, the
+\f1\fs20 collides_with()
+\f0\fs24 method, and the
+\f1\fs20 handle_collision_with()
+\f0\fs24 method. The
+\f1\fs20 collides_with()
+\f0\fs24 method will need to use the
+\f1\fs20 distance()
+\f0\fs24 function, so let's start by moving that function into its own submodule of
+\f1\fs20 game
+\f0\fs24 , called
+\f1\fs20 util.py
+\f0\fs24 :\
+\
+
+\f1\fs20 import pyglet, math\
+\
+def distance(point_1=(0, 0), point_2=(0, 0)):\
+ return math.sqrt((point_1[0]-point_2[0])**2+(point_1[1]-point_2[1])**2)
+\f0\fs24 \
+\
+Remember to call
+\f1\fs20 from util import distance
+\f0\fs24 in
+\f1\fs20 load.py
+\f0\fs24 . Now we can write
+\f1\fs20 PhysicalObject.collides_with()
+\f0\fs24 without duplicating code.\
+\
+Some fancy-pants games use polygon-based or even pixel-perfect collision detection, but this ain't one of those high-falutin' triple-A games, so we'll just pretend everything is shaped like a circle with a radius of half the image width. Circle-to-circle collision detection is very simple: if the centers of the two objects are closer than
+\f1\fs20 radius_1 + radius_2
+\f0\fs24 , then they are overlapping. Knowing this, we can write the
+\f1\fs20 collides_with()
+\f0\fs24 method:\
+\
+
+\f1\fs20 def collides_with(self, other_object):\
+ collision_distance = self.image.width/2 + other_object.image.width/2\
+ actual_distance = util.distance(self.position, other_object.position)\
+ \
+ return (actual_distance <= collision_distance)
+\f0\fs24 \
+\
+The collision handler function is even simpler, since for now we just want every object to die as soon as it touches another object:\
+\
+
+\f1\fs20 def handle_collision_with(self, other_object):\
+ self.dead = True
+\f0\fs24 \
+\
+One last thing: set
+\f1\fs20 self.dead = False
+\f0\fs24 in
+\f1\fs20 PhysicalObject.__init__()
+\f0\fs24 .\
+\
+And that's it! You should be able to zip around the screen, engine blazing away. If you hit something, both you and the thing you collided with should disappear from the screen. There's still no game, but we are clearly making progress.\
+\
+
+\b\fs48 Part 4: Collision Response
+\fs24 \
+\
+
+\b0 In this section, we'll add bullets. This new feature will require us to start adding things to the
+\f1\fs20 game_objects
+\f0\fs24 list during the game, as well as have objects check each others' types to make a decision about whether or not they should die.\
+\
+
+\b\fs36 Adding Objects During Play
+\fs24 \
+\
+How?\
+
+\b0 We handled object removal with a boolean flag. Adding objects will be a little bit more complicated. For one thing, an object can't just say "Add me to the list!" It has to come from somewhere. For another thing, an object might want to add more than one other object at a time.\
+\
+There are a few ways to solve this problem. To avoid circular references, keep our constructors nice and short, and avoid adding extra modules, we'll have each object keep a list of new child objects to be added to
+\f1\fs20 game_objects
+\f0\fs24 .\
+\
+
+\b Tweaking the Game Loop\
+
+\b0 The simplest way to check objects for children and add those children to the list is to add two lines of code to the
+\f1\fs20 game_objects
+\f0\fs24 loop. We haven't implemented the
+\f1\fs20 new_objects
+\f0\fs24 attribute yet, but when we do, it will be a list of objects to add.\
+\
+
+\f1\fs20 for obj in game_objects:\
+ obj.update(dt)\
+ game_objects.extend(obj.new_objects)\
+ obj.new_objects = []
+\f0\fs24 \
+\
+Unfortunately, this simple solution is problematic. It's generally a bad idea to modify a list while iterating over it. The fix is to simply add new objects to a separate list, then add the objects in the separate list to
+\f1\fs20 game_objects
+\f0\fs24 after we have finished iterating over it.\
+\
+Declare a
+\f1\fs20 to_add
+\f0\fs24 list just below the loop and add new objects to it instead. At the very bottom of
+\f1\fs20 update()
+\f0\fs24 , after the object removal code, add the objects in
+\f1\fs20 to_add
+\f0\fs24 to
+\f1\fs20 game_objects
+\f0\fs24 .
+\f1\fs20 \
+ \
+ ...collision...\
+ \
+ to_add = []\
+ \
+ for obj in game_objects:\
+ obj.update(dt)\
+ to_add.extend(obj.new_objects)\
+ obj.new_objects = []\
+ \
+ ...removal...\
+ \
+ game_objects.extend(to_add)
+\f0\fs24 \
+\
+
+\b Putting the Attribute in PhysicalObject\
+
+\b0 As mentioned before, all we have to do is declare a
+\f1\fs20 new_objects
+\f0\fs24 attribute in the
+\f1\fs20 PhysicalObject
+\f0\fs24 class:\
+\
+
+\f1\fs20 def __init__(self, *args, **kwargs):\
+ ....\
+ self.new_objects = []
+\f0\fs24 \
+\
+To add a new object, all we have to do is put something in
+\f1\fs20 new_objects
+\f0\fs24 , and the main loop will see it, add it to the
+\f1\fs20 game_objects
+\f0\fs24 list, and clear
+\f1\fs20 new_objects
+\f0\fs24 .\
+
+\b\fs36 \
+Adding Bullets
+\fs24 \
+\
+Writing the Bullet Class\
+
+\b0 For the most part, bullets act like any other
+\f1\fs20 PhysicalObject
+\f0\fs24 , but they have two differences, at least in this game: they only collide with some objects, and they disappear from the screen after a couple of seconds to prevent the player from flooding the screen with bullets.\
+\
+First, make a new submodule of
+\f1\fs20 game
+\f0\fs24 called
+\f1\fs20 bullet.py
+\f0\fs24 and start a simple subclass of
+\f1\fs20 PhysicalObject
+\f0\fs24 .\
+\
+
+\f1\fs20 import pyglet\
+import physicalobject, resources\
+\
+class Bullet(physicalobject.PhysicalObject):\
+ """Bullets fired by the player"""\
+ \
+ def __init__(self, *args, **kwargs):\
+ super(Bullet, self).__init__(resources.bullet_image, *args, **kwargs)
+\f0\fs24 \
+\
+To get bullets to disappear after a time, we could keep track of our own
+\f1\fs20 age
+\f0\fs24 and
+\f1\fs20 lifespan
+\f0\fs24 attributes, or we could let pyglet do all the work for us. I don't know about you, but I prefer the second option. First, we need to write a function to call at the end of a bullet's life:\
+\
+
+\f1\fs20 def die(self, dt):\
+ self.dead = True
+\f0\fs24 \
+\
+Now we need to tell pyglet to call it after half a second or so. We can do this as soon as the object is initialized by adding a call to
+\f1\fs20 pyglet.clock.schedule_once()
+\f0\fs24 to the constructor:\
+\
+
+\f1\fs20 def __init__(self, *args, **kwargs):\
+ super(Bullet, self).__init__(resources.bullet_image, *args, **kwargs)\
+ pyglet.clock.schedule_once(self.die, 0.5)
+\f0\fs24 \
+\
+There's still more work to be done on the
+\f1\fs20 Bullet
+\f0\fs24 class, but before we do any more work on the class itself, let's get them on the screen.\
+\
+
+\b Firing Bullets\
+
+\b0 The
+\f1\fs20 Player
+\f0\fs24 class will be the only class that fires bullets, so let's open it up, import the
+\f1\fs20 bullet
+\f0\fs24 module, and add a
+\f1\fs20 bullet_speed
+\f0\fs24 attribute to its constructor:\
+\
+
+\f1\fs20 ...\
+import bullet\
+\
+class Player(physicalobject.PhysicalObject):\
+ def __init__(self, *args, **kwargs):\
+ super(Player, self).__init__(img=resources.player_image, *args, **kwargs)\
+ ....\
+ self.bullet_speed = 700.0
+\f0\fs24 \
+\
+Now we can write the code to create a new bullet and send it hurling off into space. First, we need to resurrect the
+\f1\fs20 on_key_press()
+\f0\fs24 event handler:\
+\
+
+\f1\fs20 def on_key_press(self, symbol, modifiers):\
+ if symbol == key.SPACE:\
+ self.fire()
+\f0\fs24 \
+\
+The
+\f1\fs20 fire()
+\f0\fs24 method itself will be a bit more complicated. Most of the calculations will be very similar to the ones for thrusting, but there will be some differences. We'll need to spawn the bullet out at the nose of the ship, not at its center. We'll also need to add the ship's existing velocity to the bullet's new velocity, or the bullets will end up going slower than the ship if the player gets going fast enough.\
+\
+As usual, convert to radians and reverse the direction:\
+\
+
+\f1\fs20 def fire(self):\
+ angle_radians = -math.radians(self.rotation)\
+
+\f0\fs24 \
+Next, calculate the bullet's position and instantiate it:\
+\
+
+\f1\fs20 ship_radius = self.image.width/2\
+ bullet_x = self.x + math.cos(angle_radians) * ship_radius\
+ bullet_y = self.y + math.sin(angle_radians) * ship_radius\
+ new_bullet = bullet.Bullet(bullet_x, bullet_y, batch=self.batch)
+\f0\fs24 \
+\
+Set its velocity using almost the same equations:\
+\
+
+\f1\fs20 bullet_vx = self.velocity_x + math.cos(angle_radians) * self.bullet_speed\
+ bullet_vy = self.velocity_y + math.sin(angle_radians) * self.bullet_speed\
+ new_bullet.velocity_x, new_bullet.velocity_y = bullet_vx, bullet_vy
+\f0\fs24 \
+\
+Finally, add it to the
+\f1\fs20 new_objects
+\f0\fs24 list so that the main loop will pick it up and add it to
+\f1\fs20 game_objects
+\f0\fs24 .\
+\
+
+\f1\fs20 self.new_objects.append(new_bullet)
+\f0\fs24 \
+\
+At this point, you should be able to fire bullets out of the front of your ship. There's just one problem: as soon as you fire, your ship disappears. You may have noticed earlier that asteroids also disappear when they touch each other. To fix this problem, we'll need to start customizing each class's
+\f1\fs20 handle_collision_with()
+\f0\fs24 method.\
+\
+
+\b\fs36 Customizing Collision Behavior
+\fs24 \
+\
+
+\b0 There are five kinds of collisions in the current version of the game: bullet-asteroid, bullet-player, asteroid-player, bullet-bullet, and asteroid-asteroid. There would be many more in a more complex game.\
+\
+In general, objects of the same type should not be destroyed when they collide, so we can generalize that behavior in
+\f1\fs20 PhysicalObject
+\f0\fs24 . Other interactions will require a little more work.
+\b \
+\
+Letting Twins Ignore Each Other\
+
+\b0 To let two asteroids or two bullets pass each other by without a word of acknowledgement (or a dramatic explosion), we just need to check if their classes are equal in the
+\f1\fs20 PhysicalObject.handle_collision_with()
+\f0\fs24 method:\
+\
+
+\f1\fs20 def handle_collision_with(self, other_object):\
+ if other_object.__class__ == self.__class__:\
+ self.dead = False\
+ else:\
+ self.dead = True
+\f0\fs24 \
+\
+
+\b Customizing Bullet Collisions\
+
+\b0 Since bullet collision behavior can vary so wildly across objects, let's add a
+\f1\fs20 reacts_to_bullets
+\f0\fs24 attribute to
+\f1\fs20 PhysicalObjects
+\f0\fs24 which the
+\f1\fs20 Bullet
+\f0\fs24 class can check to determine if it should register a collision or not. We should also add an
+\f1\fs20 is_bullet
+\f0\fs24 attribute so we can check the collision properly from both objects.\
+\
+First, initialize the
+\f1\fs20 reacts_to_bullets
+\f0\fs24 attribute to
+\f1\fs20 True
+\f0\fs24 in the
+\f1\fs20 PhysicalObject
+\f0\fs24 constructor.\
+\
+
+\f1\fs20 class PhysicalObject(pyglet.sprite.Sprite):
+\f0\fs24 \
+
+\f1\fs20 def __init__(self, *args, **kwargs):\
+ ...\
+ self.reacts_to_bullets = True\
+ self.is_bullet = False\
+ ...\
+\
+class Bullet(physicalobject.PhysicalObject):\
+ def __init__(self, *args, **kwargs):\
+ ...\
+ self.is_bullet = True
+\f0\fs24 \
+\
+Then, insert a bit of code in
+\f1\fs20 PhysicalObject.collides_with()
+\f0\fs24 to ignore bullets under the right circumstances:\
+\
+
+\f1\fs20 def collides_with(self, other_object):\
+ if not self.reacts_to_bullets and other_object.is_bullet:\
+ return False\
+ if self.is_bullet and not other_object.reacts_to_bullets:\
+ return False\
+ ...
+\f0\fs24 \
+\
+Finally, set
+\f1\fs20 self.reacts_to_bullets = False
+\f0\fs24 in
+\f1\fs20 Player.__init__()
+\f0\fs24 . The
+\f1\fs20 Bullet
+\f0\fs24 class is completely finished! Now let's make something happen when a bullet hits an asteroid.\
+\
+
+\b\fs36 Making Asteroids Explode
+\fs24 \
+\
+
+\b0 Asteroids is challenging to players because every time you shoot an asteroid, it turns into more asteroids. We need to mimic that behavior if we want our game to be any fun. We've already done most of the hard parts. All that remains is to make another subclass of
+\f1\fs20 PhysicalObject
+\f0\fs24 and write a custom
+\f1\fs20 handle_collision_with()
+\f0\fs24 method, along with a couple of maintenance tweaks.\
+\
+
+\b Writing the Asteroid Class\
+
+\b0 Create a new submodule of
+\f1\fs20 game
+\f0\fs24 called
+\f1\fs20 asteroid.py
+\f0\fs24 . Write the usual constructor to pass a specific image to the superclass, passing along any other parameters.\
+\
+
+\f1\fs20 import pyglet\
+import resources, physicalobject\
+
+\f0\fs24 \
+
+\f1\fs20 class Asteroid(physicalobject.PhysicalObject):\
+ def __init__(self, *args, **kwargs):\
+ super(Asteroid, self).__init__(resources.asteroid_image, *args, **kwargs)
+\f0\fs24 \
+\
+Now we need to write a new
+\f1\fs20 handle_collision_with()
+\f0\fs24 method. It should create a random number of new, smaller asteroids with random velocities. However, it should only do that if it's big enough. An asteroid should divide at most twice, and if we scale it down by half each time, then an asteroid should stop dividing when it's 1/4 the size of a new asteroid.\
+\
+We want to keep the old behavior of ignoring other asteroids, so start the method with a call to the superclass's method:\
+\
+
+\f1\fs20 def handle_collision_with(self, other_object):\
+ super(Asteroid, self).handle_collision_with(other_object)
+\f0\fs24 \
+\
+Now we can say that if it's supposed to die, and it's big enough, then we should create two or three new asteroids with random rotations and velocities. We should add the old asteroid's velocity to the new ones to make it look like they come from the same object.\
+\
+
+\f1\fs20 import random\
+...\
+ if self.dead and self.scale > 0.25:\
+ num_asteroids = random.randint(2, 3)\
+ for i in xrange(num_asteroids):\
+ new_asteroid = Asteroid(x=self.x, y=self.y, batch=self.batch)\
+ new_asteroid.rotation = random.randint(0, 360)\
+ new_asteroid.velocity_x = random.random()*70 + self.velocity_x\
+ new_asteroid.velocity_y = random.random()*70 + self.velocity_y\
+ new_asteroid.scale = self.scale * 0.5\
+ self.new_objects.append(new_asteroid)
+\f0\fs24 \
+\
+While we're here, let's add a small graphical touch to the asteroids by making them rotate a little. To do that, we'll add a
+\f1\fs20 rotate_speed
+\f0\fs24 attribute and give it a random value. Then we'll write an
+\f1\fs20 update()
+\f0\fs24 method to apply that rotation every frame.\
+\
+Add the attribute in the constructor:\
+\
+
+\f1\fs20 def __init__(self, *args, **kwargs):\
+ super(Asteroid, self).__init__(resources.asteroid_image, *args, **kwargs)\
+ self.rotate_speed = random.random() * 100.0 - 50.0
+\f0\fs24 \
+\
+Then write the
+\f1\fs20 update()
+\f0\fs24 method:\
+\
+
+\f1\fs20 def update(self, dt):\
+ super(Asteroid, self).update(dt)\
+ self.rotation += self.rotate_speed * dt
+\f0\fs24 \
+\
+The last thing we need to do is go over to
+\f1\fs20 load.py
+\f0\fs24 and have the
+\f1\fs20 asteroid()
+\f0\fs24 method create a new
+\f1\fs20 Asteroid
+\f0\fs24 instead of a
+\f1\fs20 PhysicalObject
+\f0\fs24 .\
+\
+
+\f1\fs20 import asteroid\
+
+\f0\fs24 \
+
+\f1\fs20 def asteroids(num_asteroids, player_position, batch=None):\
+ ...\
+ for i in range(num_asteroids):\
+ ...\
+ new_asteroid = asteroid.Asteroid(x=asteroid_x, y=asteroid_y, batch=batch)\
+ ...\
+ return asteroids
+\f0\fs24 \
+\
+Now we're looking at something resembling a game. There are just a few more things left to do before we can pat ourselves on the back.\
+\
+
+\b\fs48 Part 5: Bringing it All Together
+\fs24 \
+\
+
+\b0 We stop here.}
\ No newline at end of file
diff --git a/pyglet/mygame/asteroids.py b/pyglet/mygame/asteroids.py
new file mode 100644
index 0000000..0bedc27
--- /dev/null
+++ b/pyglet/mygame/asteroids.py
@@ -0,0 +1,163 @@
+import pyglet, random, math
+from game import asteroid, load, player, resources
+
+# Set up a window
+game_window = pyglet.window.Window(800, 600)
+
+main_batch = pyglet.graphics.Batch()
+
+# Set up the two top labels
+score_label = pyglet.text.Label(text="Score: 0", x=10, y=575, batch=main_batch)
+level_label = pyglet.text.Label(text="Version 5: It's a Game!",
+ x=400, y=575, anchor_x='center', batch=main_batch)
+
+# Set up the game over label offscreen
+game_over_label = pyglet.text.Label(text="GAME OVER",
+ x=400, y=-300, anchor_x='center',
+ batch=main_batch, font_size=48)
+
+counter = pyglet.clock.ClockDisplay()
+
+player_ship = None
+player_lives = []
+score = 0
+num_asteroids = 3
+game_objects = []
+
+# We need to pop off as many event stack frames as we pushed on
+# every time we reset the level.
+event_stack_size = 0
+
+
+def init():
+ global score, num_asteroids
+
+ score = 0
+ score_label.text = "Score: " + str(score)
+
+ num_asteroids = 3
+ reset_level(2)
+
+
+def reset_level(num_lives=2):
+ global player_ship, player_lives, game_objects, event_stack_size
+
+ # Clear the event stack of any remaining handlers from other levels
+ while event_stack_size > 0:
+ game_window.pop_handlers()
+ event_stack_size -= 1
+
+ for life in player_lives:
+ life.delete()
+
+ # Initialize the player sprite
+ player_ship = player.Player(x=400, y=300, batch=main_batch)
+
+ # Make three sprites to represent remaining lives
+ player_lives = load.player_lives(num_lives, main_batch)
+
+ # Make some asteroids so we have something to shoot at
+ asteroids = load.asteroids(num_asteroids, player_ship.position, main_batch)
+
+ # Store all objects that update each frame in a list
+ game_objects = [player_ship] + asteroids
+
+ # Add any specified event handlers to the event handler stack
+ for obj in game_objects:
+ for handler in obj.event_handlers:
+ game_window.push_handlers(handler)
+ event_stack_size += 1
+
+
+@game_window.event
+def on_draw():
+ game_window.clear()
+ main_batch.draw()
+ counter.draw()
+
+
+def update(dt):
+ global score, num_asteroids
+
+ player_dead = False
+ victory = False
+
+ # To avoid handling collisions twice, we employ nested loops of ranges.
+ # This method also avoids the problem of colliding an object with itself.
+ for i in xrange(len(game_objects)):
+ for j in xrange(i + 1, len(game_objects)):
+
+ obj_1 = game_objects[i]
+ obj_2 = game_objects[j]
+
+ # Make sure the objects haven't already been killed
+ if not obj_1.dead and not obj_2.dead:
+ if obj_1.collides_with(obj_2):
+ obj_1.handle_collision_with(obj_2)
+ obj_2.handle_collision_with(obj_1)
+
+ # Let's not modify the list while traversing it
+ to_add = []
+
+ # Check for win condition
+ asteroids_remaining = 0
+
+ for obj in game_objects:
+ obj.update(dt)
+
+ to_add.extend(obj.new_objects)
+ obj.new_objects = []
+
+ # Check for win condition
+ if isinstance(obj, asteroid.Asteroid):
+ asteroids_remaining += 1
+
+ if asteroids_remaining == 0:
+ # Don't act on victory until the end of the time step
+ victory = True
+
+ # Get rid of dead objects
+ for to_remove in [obj for obj in game_objects if obj.dead]:
+ if to_remove == player_ship:
+ player_dead = True
+ # If the dying object spawned any new objects, add those to the
+ # game_objects list later
+ to_add.extend(to_remove.new_objects)
+
+ # Remove the object from any batches it is a member of
+ to_remove.delete()
+
+ # Remove the object from our list
+ game_objects.remove(to_remove)
+
+ # Bump the score if the object to remove is an asteroid
+ if isinstance(to_remove, asteroid.Asteroid):
+ score += 1
+ score_label.text = "Score: " + str(score)
+
+ # Add new objects to the list
+ game_objects.extend(to_add)
+
+ # Check for win/lose conditions
+ if player_dead:
+ # We can just use the length of the player_lives list as the number of lives
+ if len(player_lives) > 0:
+ reset_level(len(player_lives) - 1)
+ else:
+ game_over_label.y = 300
+ elif victory:
+ num_asteroids += 1
+ player_ship.delete()
+ score += 10
+ reset_level(len(player_lives))
+
+
+if __name__ == "__main__":
+ # Start it up!
+ init()
+
+ # Update the game 120 times per second
+ pyglet.clock.schedule_interval(update, 1 / 120.0)
+
+ # Tell pyglet to do its thing
+ pyglet.app.run()
diff --git a/pyglet/mygame/game/__init__.py b/pyglet/mygame/game/__init__.py
new file mode 100644
index 0000000..ac35b17
--- /dev/null
+++ b/pyglet/mygame/game/__init__.py
@@ -0,0 +1 @@
+import load, player, resources
diff --git a/pyglet/mygame/game/asteroid.py b/pyglet/mygame/game/asteroid.py
new file mode 100644
index 0000000..96ff33f
--- /dev/null
+++ b/pyglet/mygame/game/asteroid.py
@@ -0,0 +1,30 @@
+import random
+import physicalobject, resources
+
+
+class Asteroid(physicalobject.PhysicalObject):
+ """An asteroid that divides a little before it dies"""
+
+ def __init__(self, *args, **kwargs):
+ super(Asteroid, self).__init__(resources.asteroid_image, *args, **kwargs)
+
+ # Slowly rotate the asteroid as it moves
+ self.rotate_speed = random.random() * 100.0 - 50.0
+
+ def update(self, dt):
+ super(Asteroid, self).update(dt)
+ self.rotation += self.rotate_speed * dt
+
+ def handle_collision_with(self, other_object):
+ super(Asteroid, self).handle_collision_with(other_object)
+
+ # Superclass handles deadness already
+ if self.dead and self.scale > 0.25:
+ num_asteroids = random.randint(2, 3)
+ for i in xrange(num_asteroids):
+ new_asteroid = Asteroid(x=self.x, y=self.y, batch=self.batch)
+ new_asteroid.rotation = random.randint(0, 360)
+ new_asteroid.velocity_x = random.random() * 70 + self.velocity_x
+ new_asteroid.velocity_y = random.random() * 70 + self.velocity_y
+ new_asteroid.scale = self.scale * 0.5
+ self.new_objects.append(new_asteroid)
diff --git a/pyglet/mygame/game/bullet.py b/pyglet/mygame/game/bullet.py
new file mode 100644
index 0000000..55b583c
--- /dev/null
+++ b/pyglet/mygame/game/bullet.py
@@ -0,0 +1,18 @@
+import pyglet
+import physicalobject, resources
+
+
+class Bullet(physicalobject.PhysicalObject):
+ """Bullets fired by the player"""
+
+ def __init__(self, *args, **kwargs):
+ super(Bullet, self).__init__(resources.bullet_image, *args, **kwargs)
+
+ # Bullets shouldn't stick around forever
+ pyglet.clock.schedule_once(self.die, 0.5)
+
+ # Flag as a bullet
+ self.is_bullet = True
+
+ def die(self, dt):
+ self.dead = True
diff --git a/pyglet/mygame/game/load.py b/pyglet/mygame/game/load.py
new file mode 100644
index 0000000..c8caa84
--- /dev/null
+++ b/pyglet/mygame/game/load.py
@@ -0,0 +1,29 @@
+import pyglet, random
+import asteroid, resources, util
+
+
+def player_lives(num_icons, batch=None):
+ """Generate sprites for player life icons"""
+ player_lives = []
+ for i in range(num_icons):
+ new_sprite = pyglet.sprite.Sprite(img=resources.player_image,
+ x=785 - i * 30, y=585,
+ batch=batch)
+ new_sprite.scale = 0.5
+ player_lives.append(new_sprite)
+ return player_lives
+
+
+def asteroids(num_asteroids, player_position, batch=None):
+ """Generate asteroid objects with random positions and velocities, not close to the player"""
+ asteroids = []
+ for i in range(num_asteroids):
+ asteroid_x, asteroid_y = player_position
+ while util.distance((asteroid_x, asteroid_y), player_position) < 100:
+ asteroid_x = random.randint(0, 800)
+ asteroid_y = random.randint(0, 600)
+ new_asteroid = asteroid.Asteroid(x=asteroid_x, y=asteroid_y, batch=batch)
+ new_asteroid.rotation = random.randint(0, 360)
+ new_asteroid.velocity_x, new_asteroid.velocity_y = random.random() * 40, random.random() * 40
+ asteroids.append(new_asteroid)
+ return asteroids
diff --git a/pyglet/mygame/game/physicalobject.py b/pyglet/mygame/game/physicalobject.py
new file mode 100644
index 0000000..4292ab3
--- /dev/null
+++ b/pyglet/mygame/game/physicalobject.py
@@ -0,0 +1,74 @@
+import pyglet
+import util
+
+
+class PhysicalObject(pyglet.sprite.Sprite):
+ """A sprite with physical properties such as velocity"""
+
+ def __init__(self, *args, **kwargs):
+ super(PhysicalObject, self).__init__(*args, **kwargs)
+
+ # Velocity
+ self.velocity_x, self.velocity_y = 0.0, 0.0
+
+ # Flags to toggle collision with bullets
+ self.reacts_to_bullets = True
+ self.is_bullet = False
+
+ # Flag to remove this object from the game_object list
+ self.dead = False
+
+ # List of new objects to go in the game_objects list
+ self.new_objects = []
+
+ # Tell the game handler about any event handlers
+ # Only applies to things with keyboard/mouse input
+ self.event_handlers = []
+
+ def update(self, dt):
+ """This method should be called every frame."""
+
+ # Update position according to velocity and time
+ self.x += self.velocity_x * dt
+ self.y += self.velocity_y * dt
+
+ # Wrap around the screen if necessary
+ self.check_bounds()
+
+ def check_bounds(self):
+ """Use the classic Asteroids screen wrapping behavior"""
+ min_x = -self.image.width / 2
+ min_y = -self.image.height / 2
+ max_x = 800 + self.image.width / 2
+ max_y = 600 + self.image.height / 2
+ if self.x < min_x:
+ self.x = max_x
+ if self.y < min_y:
+ self.y = max_y
+ if self.x > max_x:
+ self.x = min_x
+ if self.y > max_y:
+ self.y = min_y
+
+ def collides_with(self, other_object):
+ """Determine if this object collides with another"""
+
+ # Ignore bullet collisions if we're supposed to
+ if not self.reacts_to_bullets and other_object.is_bullet:
+ return False
+ if self.is_bullet and not other_object.reacts_to_bullets:
+ return False
+
+ # Calculate distance between object centers that would be a collision,
+ # assuming square resources
+ collision_distance = self.image.width * 0.5 * self.scale \
+ + other_object.image.width * 0.5 * other_object.scale
+
+ # Get distance using position tuples
+ actual_distance = util.distance(self.position, other_object.position)
+
+ return (actual_distance <= collision_distance)
+
+ def handle_collision_with(self, other_object):
+ if other_object.__class__ is not self.__class__:
+ self.dead = True
diff --git a/pyglet/mygame/game/player.py b/pyglet/mygame/game/player.py
new file mode 100644
index 0000000..3252b51
--- /dev/null
+++ b/pyglet/mygame/game/player.py
@@ -0,0 +1,83 @@
+import pyglet, math
+from pyglet.window import key
+import bullet, physicalobject, resources
+
+
+class Player(physicalobject.PhysicalObject):
+ """Physical object that responds to user input"""
+
+ def __init__(self, *args, **kwargs):
+ super(Player, self).__init__(img=resources.player_image, *args, **kwargs)
+
+ # Create a child sprite to show when the ship is thrusting
+ self.engine_sprite = pyglet.sprite.Sprite(img=resources.engine_image, *args, **kwargs)
+ self.engine_sprite.visible = False
+
+ # Set some easy-to-tweak constants
+ self.thrust = 300.0
+ self.rotate_speed = 200.0
+ self.bullet_speed = 700.0
+
+ # Player should not collide with own bullets
+ self.reacts_to_bullets = False
+
+ # Tell the game handler about any event handlers
+ self.key_handler = key.KeyStateHandler()
+ self.event_handlers = [self, self.key_handler]
+
+ def update(self, dt):
+ # Do all the normal physics stuff
+ super(Player, self).update(dt)
+
+ if self.key_handler[key.LEFT]:
+ self.rotation -= self.rotate_speed * dt
+ if self.key_handler[key.RIGHT]:
+ self.rotation += self.rotate_speed * dt
+
+ if self.key_handler[key.UP]:
+ # Note: pyglet's rotation attributes are in "negative degrees"
+ angle_radians = -math.radians(self.rotation)
+ force_x = math.cos(angle_radians) * self.thrust * dt
+ force_y = math.sin(angle_radians) * self.thrust * dt
+ self.velocity_x += force_x
+ self.velocity_y += force_y
+
+ # If thrusting, update the engine sprite
+ self.engine_sprite.rotation = self.rotation
+ self.engine_sprite.x = self.x
+ self.engine_sprite.y = self.y
+ self.engine_sprite.visible = True
+ else:
+ # Otherwise, hide it
+ self.engine_sprite.visible = False
+
+ def on_key_press(self, symbol, modifiers):
+ if symbol == key.SPACE:
+ self.fire()
+
+ def fire(self):
+ # Note: pyglet's rotation attributes are in "negative degrees"
+ angle_radians = -math.radians(self.rotation)
+
+ # Create a new bullet just in front of the player
+ ship_radius = self.image.width / 2
+ bullet_x = self.x + math.cos(angle_radians) * ship_radius
+ bullet_y = self.y + math.sin(angle_radians) * ship_radius
+ new_bullet = bullet.Bullet(bullet_x, bullet_y, batch=self.batch)
+
+ # Give it some speed
+ bullet_vx = self.velocity_x + math.cos(angle_radians) * self.bullet_speed
+ bullet_vy = self.velocity_y + math.sin(angle_radians) * self.bullet_speed
+ new_bullet.velocity_x, new_bullet.velocity_y = bullet_vx, bullet_vy
+
+ # Add it to the list of objects to be added to the game_objects list
+ self.new_objects.append(new_bullet)
+
+ # Play the bullet sound
+ resources.bullet_sound.play()
+
+ def delete(self):
+ # We have a child sprite which must be deleted when this object
+ # is deleted from batches, etc.
+ self.engine_sprite.delete()
+ super(Player, self).delete()
diff --git a/pyglet/mygame/game/resources.py b/pyglet/mygame/game/resources.py
new file mode 100644
index 0000000..bfbd25f
--- /dev/null
+++ b/pyglet/mygame/game/resources.py
@@ -0,0 +1,32 @@
+import pyglet
+
+
+def center_image(image):
+ """Sets an image's anchor point to its center"""
+ image.anchor_x = image.width / 2
+ image.anchor_y = image.height / 2
+
+
+# Tell pyglet where to find the resources
+pyglet.resource.path = ['resources']
+pyglet.resource.reindex()
+
+# Load the three main resources and get them to draw centered
+player_image = pyglet.resource.image("player.png")
+center_image(player_image)
+
+bullet_image = pyglet.resource.image("bullet.png")
+center_image(bullet_image)
+
+asteroid_image = pyglet.resource.image("asteroid.png")
+center_image(asteroid_image)
+
+# The engine flame should not be centered on the ship. Rather, it should be shown
+# behind it. To achieve this effect, we just set the anchor point outside the
+# image bounds.
+engine_image = pyglet.resource.image("engine_flame.png")
+engine_image.anchor_x = engine_image.width * 1.5
+engine_image.anchor_y = engine_image.height / 2
+
+# Load the bullet sound _without_ streaming so we can play it more than once at a time
+bullet_sound = pyglet.resource.media("bullet.wav", streaming=False)
diff --git a/pyglet/mygame/game/util.py b/pyglet/mygame/game/util.py
new file mode 100644
index 0000000..d1c3faf
--- /dev/null
+++ b/pyglet/mygame/game/util.py
@@ -0,0 +1,12 @@
+import pyglet, math
+
+
+def distance(point_1=(0, 0), point_2=(0, 0)):
+ """Returns the distance between two points"""
+ return math.sqrt((point_1[0] - point_2[0]) ** 2 + (point_1[1] - point_2[1]) ** 2)
+
+
+def center_image(image):
+ """Sets an image's anchor point to its center"""
+ image.anchor_x = image.width / 2
+ image.anchor_y = image.height / 2
diff --git a/pyglet/mygame/resources/asteroid.png b/pyglet/mygame/resources/asteroid.png
new file mode 100644
index 0000000..7ca669c
Binary files /dev/null and b/pyglet/mygame/resources/asteroid.png differ
diff --git a/pyglet/mygame/resources/bullet.png b/pyglet/mygame/resources/bullet.png
new file mode 100644
index 0000000..56a609f
Binary files /dev/null and b/pyglet/mygame/resources/bullet.png differ
diff --git a/pyglet/mygame/resources/bullet.wav b/pyglet/mygame/resources/bullet.wav
new file mode 100644
index 0000000..05da01e
Binary files /dev/null and b/pyglet/mygame/resources/bullet.wav differ
diff --git a/pyglet/mygame/resources/engine_flame.png b/pyglet/mygame/resources/engine_flame.png
new file mode 100644
index 0000000..9b00300
Binary files /dev/null and b/pyglet/mygame/resources/engine_flame.png differ
diff --git a/pyglet/mygame/resources/player.png b/pyglet/mygame/resources/player.png
new file mode 100644
index 0000000..0e2fa84
Binary files /dev/null and b/pyglet/mygame/resources/player.png differ
diff --git a/pyglet/play_mp3.py b/pyglet/play_mp3.py
new file mode 100644
index 0000000..94db6a4
--- /dev/null
+++ b/pyglet/play_mp3.py
@@ -0,0 +1,6 @@
+import pyglet
+
+music = pyglet.resource.media('a_little_story.wav')
+music.play()
+
+pyglet.app.run()
diff --git a/pygments/simple.py b/pygments/simple.py
new file mode 100644
index 0000000..de0bff5
--- /dev/null
+++ b/pygments/simple.py
@@ -0,0 +1,6 @@
+from pygments import highlight
+from pygments.lexers import PythonLexer
+from pygments.formatters import HtmlFormatter
+
+code = 'print "Hello World"'
+print highlight(code, PythonLexer(), HtmlFormatter())
diff --git a/redis/redismq/elect.py b/redis/redismq/elect.py
new file mode 100644
index 0000000..26203dc
--- /dev/null
+++ b/redis/redismq/elect.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import redis
+
+rc = redis.StrictRedis(host='localhost', port=6379, db=0)
+local_selector = 0
+
+
+def master():
+ global local_selector
+ master_selector = rc.incr('master_selector')
+ if master_selector == 1:
+ # initial / restarted
+ local_selector = master_selector
+ else:
+ if local_selector > 0:
+ # I'm the master before
+ if local_selector > master_selector:
+ # lost, maybe the db is fail-overed.
+ local_selector = 0
+ else:
+ # continue to be the master
+ local_selector = master_selector
+ if local_selector > 0:
+ # I'm the current master
+ rc.expire('master_selector', 20)
+ return local_selector > 0
diff --git a/redis/redismq/redismq.py b/redis/redismq/redismq.py
new file mode 100644
index 0000000..a0c2eb1
--- /dev/null
+++ b/redis/redismq/redismq.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import redis
+
+rc = redis.StrictRedis(host='localhost', port=6379, db=0)
+
+
+def fifo_push(q, data):
+ rc.lpush(q, data)
+
+
+def fifo_pop(q):
+ return rc.rpop(q)
+
+
+def filo_push(q, data):
+ rc.lpush(q, data)
+
+
+def filo_pop(q):
+ return rc.lpop(q)
+
+
+def safe_fifo_push(q, data):
+ rc.lpush(q, data)
+
+
+def safe_fifo_pop(q, cache):
+ msg = rc.rpoplpush(q, cache)
+ # check and do something on msg
+ rc.lrem(cache, 1) # remove the msg in cache list.
+ return msg
diff --git a/redis/redismq/signal_wait.py b/redis/redismq/signal_wait.py
new file mode 100644
index 0000000..612b71e
--- /dev/null
+++ b/redis/redismq/signal_wait.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import redis, time, random
+
+rc = redis.StrictRedis(host='localhost', port=6379, db=0)
+
+
+def wait(wait_for):
+ ps = rc.pubsub()
+ ps.subscribe(wait_for)
+ ps.get_message()
+ wait_msg = None
+ while True:
+ msg = ps.get_message()
+ if msg and msg['type'] == 'message':
+ wait_msg = msg
+ break
+ time.sleep(0.001)
+ ps.close()
+ return wait_msg
+
+
+def signal_broadcast(wait_in, data):
+ wait_count = rc.publish(wait_in, data)
+ return wait_count
+
+
+single_cast_script = """
+ local channels = redis.call('pubsub', 'channels', ARGV[1]..'*');
+ if #channels == 0 then
+ return 0;
+ end;
+ local index = math.mod(math.floor(tonumber(ARGV[2])), #channels) + 1;
+ return redis.call('publish', channels[index], ARGV[3]);
+"""
+
+
+def wait_single(channel, myid):
+ return wait(channel + myid)
+
+
+def signal_single(channel, data):
+ rand_num = int(random.random() * 65535)
+ return rc.eval(single_cast_script, 0, channel, str(rand_num), str(data))
diff --git a/tornado/hello.py b/tornado/hello.py
new file mode 100644
index 0000000..39abfca
--- /dev/null
+++ b/tornado/hello.py
@@ -0,0 +1,16 @@
+import tornado.ioloop
+import tornado.web
+
+class MainHandler(tornado.web.RequestHandler):
+ def get(self):
+ self.write("Hello, world")
+
+def make_app():
+ return tornado.web.Application([
+ (r"/", MainHandler),
+ ])
+
+if __name__ == "__main__":
+ app = make_app()
+ app.listen(8888)
+ tornado.ioloop.IOLoop.current().start()
diff --git a/tqdm/hello.py b/tqdm/hello.py
new file mode 100644
index 0000000..6a014be
--- /dev/null
+++ b/tqdm/hello.py
@@ -0,0 +1,12 @@
+
+import time
+from tqdm import *
+
+for i in tqdm(range(100), desc="Akagi201", leave=True):
+ time.sleep(0.01)
+
+for i in trange(100):
+ time.sleep(0.01)
+
+for i in tqdm(xrange(100)):
+ time.sleep(0.01)
\ No newline at end of file
diff --git a/trips/README.md b/trips/README.md
new file mode 100644
index 0000000..5e2e29d
--- /dev/null
+++ b/trips/README.md
@@ -0,0 +1,13 @@
+* 可变默认参数,闭包陷阱:
+* 浮点数相关问题,好多语言都这样,如果不这样实现性能会大打折扣。 list 和 class 的引用可以算俩坑。列表楼上易经说了,类循环引用会造成内存泄漏。看看这个就知道了 不过其他语言里也有呀。
+* 默认参数不是每次都初始化
+* lambda 只能一行且不能出现 statement
+* python2 弱类型: 2 >"WTF" => False
+* py2 多返回值: a, b = 1,2,3 会报错
+* StandardError 经常 catch 不到东西,大多数都得上 Exception
+* 没 switch, 大段 if 真的很丑
+* 推荐 format 方法来格式化,但是 log 中却还是旧的字符串格式化
+* 还有个比较坑的地方是 os.path.join 和 str.join 用法不一样, str.join 接受 iterable 做参数, os.path.join 可以接受可变参数。。。。。用错也没提示,真坑。
+* urljoin 和预期不同,不能接受多个参数,必须一个个嵌套,而且第一个参数如果格式错误也会返回很奇怪的结果
+* 列表解析里的变量作用域外泄
+*
diff --git a/trips/append.py b/trips/append.py
new file mode 100644
index 0000000..5a4cc00
--- /dev/null
+++ b/trips/append.py
@@ -0,0 +1,6 @@
+def test(a=[]):
+ a.append(1)
+ return a
+
+print(test())
+print(test())
diff --git a/trips/class.py b/trips/class.py
new file mode 100644
index 0000000..7aaf6c4
--- /dev/null
+++ b/trips/class.py
@@ -0,0 +1,11 @@
+class Test(object):
+ def test(self):
+ pass
+
+a = Test()
+
+b = Test()
+
+print(a.test is b.test) // False
+
+print(id(a.test) == id(b.test)) // True
diff --git a/trips/division.py b/trips/division.py
new file mode 100644
index 0000000..c085b1a
--- /dev/null
+++ b/trips/division.py
@@ -0,0 +1,11 @@
+from __future__ import division
+a = 123456789012345678901234567890123456789012345678901234567890
+a /= 2
+print(a)
+print(a%2 == 0)
+
+# from __future__ import division
+a = 123456789012345678901234567890123456789012345678901234567890
+a /= 2
+print(a)
+print(a%2 == 0)
diff --git a/trips/float.py b/trips/float.py
new file mode 100644
index 0000000..1df8277
--- /dev/null
+++ b/trips/float.py
@@ -0,0 +1,2 @@
+
+print(0.1 + 0.2 == 0.3) // False
diff --git a/trips/id.py b/trips/id.py
new file mode 100644
index 0000000..88f978c
--- /dev/null
+++ b/trips/id.py
@@ -0,0 +1,12 @@
+a = [1, 2]
+print(id(a))
+b = a
+print(id(b))
+c = a[:]
+print(id(c))
+d = list(a)
+print(id(d))
+
+import copy
+e = copy.copy(a)
+print(id(e))
diff --git a/trips/nan.py b/trips/nan.py
new file mode 100644
index 0000000..092536b
--- /dev/null
+++ b/trips/nan.py
@@ -0,0 +1,7 @@
+a = float('nan')
+
+print(a) // nan
+
+print('a is a:', a is a) // True
+
+print('a == a:', a == a) // False
diff --git a/trips/ordereddict.py b/trips/ordereddict.py
new file mode 100644
index 0000000..2df9b9c
--- /dev/null
+++ b/trips/ordereddict.py
@@ -0,0 +1,6 @@
+
+import collections
+
+print(collections.OrderedDict({2: '2', 1: '1'}))
+
+print(collections.OrderedDict(b=1, a=2))
diff --git a/v2ex/sign.py b/v2ex/sign.py
new file mode 100644
index 0000000..d0fd498
--- /dev/null
+++ b/v2ex/sign.py
@@ -0,0 +1,29 @@
+# coding:utf-8
+
+import re
+import requests
+
+session = requests.Session()
+
+# 领取 X 铜币
+# 每日登录奖励已领取
+
+base_headers = {
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.71 Safari/537.36 OPR/35.0.2066.23 (Edition beta)', 'Referer': 'http://v2ex.com/signin'}
+
+session.headers = base_headers
+
+resp = session.get('http://v2ex.com/signin')
+u, p = re.findall(r'class="sl" name="([0-9A-Za-z]{64})"', resp.text)
+once_code = re.search(r'value="(\d+)" name="once"', resp.text).group(1)
+
+resp = session.post('http://v2ex.com/signin',
+ {u: 'username', p: 'password', 'once': once_code, 'next': '/'})
+resp = session.get('http://v2ex.com/mission/daily')
+
+if u'每日登录奖励已领取' in resp.text:
+ print('Already got it.')
+else:
+ resp = session.get(
+ 'http://v2ex.com' + re.search(r'/mission/daily/redeem\?once=\d+', resp.text).group())
+ print(resp.ok)
diff --git a/wsgiref/simple/hello.py b/wsgiref/simple/hello.py
new file mode 100644
index 0000000..c0ba668
--- /dev/null
+++ b/wsgiref/simple/hello.py
@@ -0,0 +1,7 @@
+# hello.py
+
+def application(environ, start_response):
+ start_response('200 OK', [('Content-Type', 'text/html')])
+ # return [b'Hello, web!
']
+ body = 'Hello, %s!
' % (environ['PATH_INFO'][1:] or 'web')
+ return [body.encode('utf-8')]
diff --git a/wsgiref/simple/server.py b/wsgiref/simple/server.py
new file mode 100644
index 0000000..eb3da7c
--- /dev/null
+++ b/wsgiref/simple/server.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+# -*- coding:utf-8 -*-
+
+# server.py
+# 从 wsgiref 模块导入
+from wsgiref.simple_server import make_server
+# 导入我们自己编写的 application 函数
+from hello import application
+
+# 创建一个服务器, IP 地址为空, 端口是 8000, 处理函数是 application
+httpd = make_server('', 8000, application)
+print('Serving HTTP on port 8000...')
+
+# 开始监听 HTTP 请求
+httpd.serve_forever()
diff --git a/xkcd/README.md b/xkcd/README.md
new file mode 100644
index 0000000..55b0308
--- /dev/null
+++ b/xkcd/README.md
@@ -0,0 +1,12 @@
+# xkcd 下载器
+
+## Install
+* Use python3.
+* `pip install -r requirements.txt`
+
+## Run
+* 单线程版本: `python single_xkcd.py`
+* 多线程版本: `python multi_xkcd.py`
+
+## Output
+* 下载的图片在 `xkcd` 目录下面.
diff --git a/xkcd/multi_xkcd.py b/xkcd/multi_xkcd.py
new file mode 100644
index 0000000..dba3313
--- /dev/null
+++ b/xkcd/multi_xkcd.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+
+import requests, os, threading
+from bs4 import BeautifulSoup as bs
+
+""" XKCD Comics Downloader using threading which downloads multiple comics at a time. """
+
+url = 'http://xkcd.com'
+
+""" Check if the Folder xkcd exist or not. If not then create a xkcd folder."""
+if not os.path.exists('xkcd'):
+ os.makedirs('xkcd')
+
+""" Download Each page untill end of url has # is reached and is between page number startComic and endComic. """
+
+
+def downloadXkcd(startComic, endComic):
+ for urlNumber in range(startComic, endComic):
+ print('Downloading page http://xkcd.com/%s...' % urlNumber)
+ res = requests.get('http://xkcd.com/%s' % urlNumber)
+ res.raise_for_status()
+
+ soup = bs(res.text, "html.parser")
+ """ Select the img tag with comic id to download ."""
+ comicElem = soup.select('#comic img')
+ if comicElem == []:
+ print('Could not find comic image.')
+ else:
+
+ comicUrl = comicElem[0].get('src')
+ print('Downloading image %s...' % comicUrl)
+ res = requests.get('https:' + comicUrl)
+ res.raise_for_status() # Check for url status
+ """ Check if File already exist in xkcd folder or not ."""
+ if not os.path.isfile(os.path.join('xkcd', os.path.basename(comicUrl))):
+ # os.path.basename(comicUrl) takes the last part of the url.
+ imageFile = open(os.path.join('xkcd', os.path.basename(comicUrl)), 'wb')
+ # Downloading chunks of file data and saving it.
+ for chunk in res.iter_content(100000):
+ imageFile.write(chunk)
+ imageFile.close()
+
+
+downloadThreads = []
+# Downloading page from 0 to 1400 at difference of 100 pages.
+for i in range(0, 1400, 100):
+ downloadThread = threading.Thread(target=downloadXkcd, args=(i, i + 99))
+ downloadThreads.append(downloadThread)
+ downloadThread.start()
+
+for downloadThread in downloadThreads:
+ downloadThread.join()
+
+print('Done')
diff --git a/xkcd/requirements.txt b/xkcd/requirements.txt
new file mode 100644
index 0000000..d779dbe
--- /dev/null
+++ b/xkcd/requirements.txt
@@ -0,0 +1,2 @@
+bs4
+requests
\ No newline at end of file
diff --git a/xkcd/single_xkcd.py b/xkcd/single_xkcd.py
new file mode 100644
index 0000000..d685776
--- /dev/null
+++ b/xkcd/single_xkcd.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+
+import requests, os
+from bs4 import BeautifulSoup as bs
+
+""" XKCD Comics Downloader using BeautifulSoup which downloads comics and save to xkcd folder. """
+
+url = 'http://xkcd.com'
+
+""" Check if the Folder xkcd exist or not. If not then create a xkcd folder."""
+if not os.path.exists('xkcd'):
+ os.makedirs('xkcd')
+
+""" Download Each page untill end of url has # is reached """
+while not url.endswith('#'):
+
+ print('Downloading page %s...' % url)
+ res = requests.get(url)
+ res.raise_for_status()
+
+ soup = bs(res.text, "html.parser")
+
+ comicElem = soup.select('#comic img')
+ """ Select the img tag with comic id to download ."""
+ if comicElem == []:
+ print('Could not find comic image.')
+ else:
+
+ try:
+ comicUrl = 'http:' + comicElem[0].get('src')
+ print('Downloading image %s...' % comicUrl)
+ res = requests.get(comicUrl)
+ res.raise_for_status() # Check for url status
+
+ except requests.exceptions.MissingSchema:
+ prevLink = soup.select('a[rel="prev"]')[0]
+ url = 'http://xkcd.com' + prevLink.get('href')
+ continue
+ """ Check if File already exist in xkcd folder or not ."""
+ if not os.path.isfile(os.path.join('xkcd', os.path.basename(comicUrl))):
+ # os.path.basename(comicUrl) takes the last part of the url.
+ imageFile = open(os.path.join('xkcd', os.path.basename(comicUrl)), 'wb')
+ # Downloading chunks of file data and saving it.
+ for chunk in res.iter_content(100000):
+ imageFile.write(chunk)
+ imageFile.close()
+
+ """ Find prev link and continue Downloading. """
+ prevLink = soup.select('a[rel="prev"]')[0]
+ url = 'http://xkcd.com' + prevLink.get('href')
+
+print('Done')