2

I started learning Python yesterday and I ran into a problem. I like to hear some thoughts on it.

As an exercise, I decided to build a chatserver. As part of the exercise, I wanted to write some inheritance code.

Class A
  def foo
    print "foo"

Class B(A)
  def bar
    print "bar"

c = B()
c.foo()
>>> prints: foo

okay, to me that seems like very normal basic inheritance (please let me know if you disagree). So to get back to my chatserver, I thought it would be nice to extend the socket and make it into a chat socket. The first thing I wanted to do is add an attribute called nickname (important in a chat). Oh, and I thought about using select as a threading solution because it seemed to come highly recommended, so you need an array of sockets (I also like to hear your thoughts on this). Now, the problem you get is, that socket, instantiates sockets, so

s = socket.socket(family, type,..)

in stead of

s = Socket()

so what I wanted todo is

class ChatSocket(Socket)
  def getNickname()
    return "bob" # obviously an example for simplicity

s = ChatSocket() 

First question: Why does it work this way and doesn't it have a 'normal' instantiation?

Second question: What is in your opinion an elegant solution to this challenge?

I hope this makes sense... Any thoughts are very welcome

Erik Ros
  • 54
  • 6
  • Python doesn't have a `new` operator. Constructors calls look like an ordinary function call. You want `c = B()`, not `c = new B()`. – amon Oct 01 '15 at 20:09
  • Oh, yes, of course, I will change it, sorry I only started yesterday... – Erik Ros Oct 01 '15 at 20:10
  • @amon: And yet the first line of code at the first code example in [this page](https://docs.python.org/2/library/socket.html) is `s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)`. – Robert Harvey Oct 01 '15 at 20:11
  • @ErikRos: In most other languages, that method call would read something like `socket.newSocket()` or `socket.Create()`. – Robert Harvey Oct 01 '15 at 20:12
  • I know the pattern exists, I just can't think of an application where I would prefer it, because it hinders inheritance, if I'm not mistaken – Erik Ros Oct 01 '15 at 20:15
  • The pythonic way is often different from C#/C++ and java. it will take some time to become pythonic in your approach – Michael Shaw Oct 02 '15 at 12:00
  • Why would you inherit socket in this case? Does it bring anything to the table? Remember, favour composition over inheritance and the problem goes away. – Esben Skov Pedersen Oct 15 '15 at 11:50
  • @Esben thank you for that question. Basically, I wanted to associate a nickname with a socket. It was just a very simple learning exercise. since so very little extra was added (one attribute called nickname with a getter and a setter -or without given it is Python-). That does seem like a very valid case for inheritance to me. Anyway, I am very interested in hearing others peoples thought on this modelling question. – Erik Ros Oct 15 '15 at 14:53

2 Answers2

3
s = socket.socket(family, type,..)

in stead of

s = Socket()

Why does it work this way and doesn't it have a 'normal' instantiation?

But that is normal initalization! socket is a module (or namespace), and socket.socket is the socket class in the socket namespace, and socket.socket(family, type) invokes that constructor. This might be clearer if you import that module under a custom name:

import socket as socketmodule
# then:
s = socketmodule.socket(...)

Or you could alias the name of the class:

Socket = socket.socket
s = Socket(...)

In Python, modules and classes are ordinary values that are passed around at runtime, so we can use ordinary variables to name them.

You can subclass the built-in socket to provide custom behaviour. For example:

class ChatSocket(socket.SocketType):
  def __init__(self):
    super(socket.SocketType, self).__init__(family, type) # assuming Python 2.x
    other_initalization()

  def nickname(self):
    return "bob"

(The names socket.socket and socket.SocketType are the same class.)

However, subclassing a class you have no control over and that is not intended for subclassing might not be a good idea. Instead, stuff the socket into a member variable and wrap any methods you want to expose:

class ChatSocket(object):
  def __init__(self):
    self.socket = socket.socket()

  def nickname(self):
    return "bob"

  def accept(self):
    return self.socket.accept()

  ...

This lets you control more precisely what interface your class offers.

amon
  • 132,749
  • 27
  • 279
  • 375
0

As someone stated befor a python file is basically a module so if you have a class called Socket in a file socket.py and you use the import statement like

import socket 

you have to refer to the Socket calls (for instanciation) like

s = socket.Socket()

You could also use the from statement to import a special function or class fro the module like

from socket import Socket, ChatSocket 

This is python 2.x syntax if you using python 3.x you might need to be more specific with your refernces in the import statements. And in your example you used old style classes thats considered bad style. Since 2.5 (if I remember right ) you should inherite your class from object like

class A(object):

in python everything is basically an object.

  • Hi Markus, thanks for your response. The concept of files being equal to modules hadn't sunk in yet when I wrote the question. It was after my first day of learning.. anyway, thank you for your clarification. – Erik Ros Oct 15 '15 at 14:46
  • no problem, you're welcom;) no one can all things from the begin so at some point I had to read and look around for stuff like this too –  Oct 15 '15 at 19:16
  • since there are selfproclaimed editors around who delete smiley ... here the rest of my post without a smiley "if some of the stuff have been mentioned befor ... I'm sorry I tend to scam off ppl " –  Oct 16 '15 at 08:06