2

I am fairly new to python, I come from a strong C background however, and I was trying to figure out how this works: How can I use a SOCKS 4/5 proxy with urllib2?

The part I am having trouble understanding is that they overwrite socket.socket yet socket.socket is a 'type' as told by running type(socket.socket). So I am confused about how you are capable of overwriting a type like that, or is socket.socket in this case actually a function they are redefining hence actually returning a different type? Normally if I run type on a function it returns that its a function or a method or whatever.

I guess what I am really trying to understand is what is happening under the covers?

Community
  • 1
  • 1
csteifel
  • 2,854
  • 6
  • 35
  • 61

2 Answers2

4

I guess what I am really trying to understand is what is happening under the covers?

This is a great question.

Storing a variable in another namespace like this is called "monkey patching".

The code example isn't actually overwriting the type. Instead, it updates the socket variable in the socket module namespace to point at a socks 4/5 class. Then, when urllib2 looks-up the socket.socket variable, it now uses the SocksiPy module instead of native sockets.

The import thing to know is that socket.socket is a variable that is initially set to point at the built-in socket type. That variable can be updated to point at a new 4/5 socket type. When urllib2 looks up the variable, it uses the substitute instead of the original.

Conceptually, what is going on is roughly akin to this:

>>> socket = 'old_native_socket'
>>> def urllib2(url):
         return 'Looking up', url, 'using', socket

>>> socket = 'new_4_5_socket'
>>> urllib2('http://www.python.org')
Looking up http://www.python.org using new_4_5_socket

And here is a simple monkey patch example for the math module:

>>> import math
>>> def area(radius):
        return math.pi * radius ** 2.0

>>> math.pi = 3.1          # monkey patch
>>> area(10)
310.0
Raymond Hettinger
  • 216,523
  • 63
  • 388
  • 485
  • I don't understand how socket.socket is actually a variable though, cause then shouldn't it return back that it is a socket type instead of just type? – csteifel May 30 '14 at 03:54
  • 1
    you are shadowing the class ... at the module level classes are just variables ... – Joran Beasley May 30 '14 at 03:56
  • 1
    Interesting ok. I am so used to C where once a type is set it is set in stone that this just broke all conventions for me. I didn't realize this was possible in python – csteifel May 30 '14 at 04:02
1

consider the following

class SomeClass:
     def __init__(self):
         print "I am some class!"

class SomeOtherClass:
     def __init__(self):
         print "I am some other class!!"

c1 = SomeClass()
c2 = SomeOtherClass()
SomeClass = SomeOtherClass #shadows the other class
c3 = SomeClass()

this is just hapening at the module level socket

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179