Contents
Developing with python was a refreshing and pleasant experience. After workingwith Java for a while, you may forget how verbose and clumsy this language sometimes is. But Python shows how simple and powerful at the same time a programming language can be. Let me show you some examples.
TL;DRWhat makes Python so cool?
Concise and powerful syntax. It’s almost like pseudo-code. Powerful collection support. Awesome list comprehension. That’s my personal highlight. Named and default parameter. Rich ecosystem and an active community. Incredible speed when it comes to IO or database operations. Functions are first-class citizens.What makes a Java developer feel home?
Pip for dependency management, PyPI as the central artifact repository and PyBuilder for project setup, test execution and build management. Type Hinting improves IDE support (up to a certain extend) Python code is also compiled. But it usually happens on-the-fly so you won’t notice.But Python is still a dynamically typed language. That means:
You spend much time for goggling API IDE support simply can’t be that good. But IntelliJ does its best. Refactorings can bedangerousand error-prone. You’ll need more tests, because errors will only come up at runtime. No encapsulation and information hiding because every thing is public.Python is awesome for advanced scripting and small applications, but I wouldn’t use it for bigger applications that require long-term maintainability and sustainability.
Basics # You don’t need {} for method bodies (use intend instead), no semicolon, no () in if conditions. def divide(a, b): if b is 0: raise ValueError("Dude, you can't divide {} by {}".format(a, b)) return a / b # more intuitive than Java's ternary operator parameter = "Peter" name = "Unknown" if parameteris None else parameter # multi-line strings. praise the lord! description = """This is my multi-line string. """ # chained comparison if 200 <= status_code < 300: print("success") CollectionsPython is just awesome when it comes to collections.
# nice literals for list, tuple, sets, dicts my_list = [1, 2, 3] my_tuple = (1, 2) my_set = {1, 2, 2} my_dict = {"a": 1, "b": 2} # this collection literals makes dealing with JSON a pleasure. # this is also the reason why the Python driver for MongoDB makes definitely more fun. # contains contains_element = 1 in my_list# True contains_key = "a" not in my_dict# False # access value = my_list[0] value2 = my_dict["a"] # iteration for elementin my_list: print(element) for index, elementin enumerate(my_list):# foreach with index! print(index, element) for key, valuein my_dict.items():# how cool is that?! print(key, value) # list can be used as stacks... print(my_list.pop())# 3 (remove and return element) # ...and as queues print(my_list.pop(0))# 1 (remove and return first element) # == List Comprehension == # That's my personal kick-ass feature of Python # It's like map() and filter() of the Java 8 Stream API, but much better. # syntax: [<map_function> for <element> in <collection> if <condition>] # example: names = ["peter", "paul", "florian", "albert"] # filter for names starting with "p" (filter()) and upper case them (map()) result = [name.upper() for namein namesif name.startswith("p")] print(result)# ["PETER", "PAUL"] # and it returns... a new list! no annoying collect(Collectors.toList()) boilerplate. # I really love this powerful and concise syntax. # slice syntax for extracting parts of a collection # syntax: collection[startIndex:stopIndex(:step)] # startIndex defaults to 0; stopIndex defaults to len(col); step defaults to 1, negative step reverses direction of iteration print(names[1:2])# paul print(names[1:])# all except the first: paul, florian, albert print(names[:1])# get first element: peter print(names[:])# copy whole collection print(names[::-1])# reverse list: ['albert', 'florian', 'paul', 'peter'] # works also for strings print("hello nice world"[6:10])# nice Functions def copy(source_file, target_file, override): pass# imagine some code here... # unclear what the parameters mean: copy("~/file.txt", "~/file2.txt", True) # named parameters make method calls readable! copy(source_file="~/file.txt", target_file="~/file2.txt", override=True) # it's also more secure, because an error is thrown, if the argument name doesn't exist # default parameters! no silly constructor chaining. def copy2(source_file, target_file, override = True): pass# imagine some code here... copy2(source_file="~/file.txt", target_file="~/file2.txt") # functions are first class citizens. You can assign them to variables, return and pass them around my_copy = copy2 # lambdas get_year = lambda date: date.year import datetime today = datetime.date.today() some_day = datetime.date(2010, 9, 15) for datein [today, some_day]: print(get_year(date))# 2016, 2010 # multiple return values via automatic tuple packing and unpacking def multiple_return(): return 1, 2, True# will be packed to a tuple print(multiple_return())# (1, 2, True) first, second, third = multiple_return()# unpacking print(first, second, third)# 1 2 True Classes # let's define a User class with the properties name and age class User: def __init__(self, name, age): self.name = name self.age = age def introduce_yourself(self): print("Hi, I'm {}, {} years old".format(self.name, self.age)) # create a User user = User("Hauke", 28) print(user.name)# Hauke user.introduce_yourself()# Hi, I'm Hauke, 28 years old # by the way there is also Inheritance and Polymorphism Operator Overloading import datetime today = datetime.date.today() some_day = datetime.date(2016, 9, 15) print(today - some_day)# "17 days, 0:00:00". difference between dates. set1 = {1, 2, 3} set2 = {3, 4, 5} print(set2 - set1)# {4, 5}. difference between sets # Let's define our own overloading # Therefore, we use Protocols. Protocols define method signatures. If you implement these methods, you can use certain operators. # e.g. for "==" we need to implement "__eq__" class User: def __init__(self, name, age): self.name = name self.age = age def __eq__(self, other): return self.nameis other.nameand self.ageis other.age print(User("Hauke", 28) is User("Peter", 30))# False # e.g. for "list[element]" we need to implement "__getitem__" class UserAgeFinder: def __init__(self): self.user_list = [User("Hauke", 28), User("Peter", 30), User("Hugo", 55)] def __getitem__(self, name): return [user.agefor user in self.user_listif user.nameis name] finder = UserAgeFinder() print(finder["Hauke"])# [28] Type Hinting + IntelliJ PyCharmPython 3.5 introduced type hints . It’s important to note that they are just hints . The Python interpreter won’t complain about invalid methods and arguments. It just for tooling and documentation.
IntelliJ PyCharm provides nice auto completion based on type hints. In the following example PyCharmshows us the methods of a string (str).

The auto completion works also for our custom classes.
Moreover, PyCharmtells us when we invoke an invalid method or