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

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
  • 135,795
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.