I am following this explanation, and I don't quite get how Python interpreter arrives at the following. In the first example, is Python seeing #implementer(IAmericanSocket) is not implemented by UKSocket, then it decides to make it a AdaptToAmericanSocket because that is the only implementation of IAmericanSocket with one argument? What if there is another class instance implementing IAmericanSocket with one argument? In the second example, why is IAmericanSocket not overriding AmericanSocket's voltage method?
>>> IAmericanSocket(uk)
<__main__.AdaptToAmericanSocket instance at 0x1a5120>
>>> IAmericanSocket(am)
<__main__.AmericanSocket instance at 0x36bff0>
with the code below:
from zope.interface import Interface, implementer
from twisted.python import components
class IAmericanSocket(Interface):
def voltage():
"""
Return the voltage produced by this socket object, as an integer.
"""
#implementer(IAmericanSocket)
class AmericanSocket:
def voltage(self):
return 120
class UKSocket:
def voltage(self):
return 240
#implementer(IAmericanSocket)
class AdaptToAmericanSocket:
def __init__(self, original):
self.original = original
def voltage(self):
return self.original.voltage() / 2
components.registerAdapter(
AdaptToAmericanSocket,
UKSocket,
IAmericanSocket)
You can see the full documentation for zope.interface here: http://docs.zope.org/zope.interface/ - it may provide a more thorough introduction than Twisted's quick tutorial.
To answer your specific question, the registerAdapter call at the end there changes the behavior of calling IAmericanSocket.
When you call an Interface, it first checks to see if its argument provides itself. Since the class AmericanSocket implements IAmericanSocket, instances of AmericanSocket provide IAmericanSocket. This means that when you call IAmercianSocket with an argument of an AmericanSocket instance, you just get the instance back.
However, when the argument does not provide the interface already, the interface then searches for adapters which can convert something that the argument does provide to the target interface. ("Searches for adapters" is a huge oversimplification, but Twisted's registerAdapter exists specifically to allow for this type of simplification.)
So when IAmericanSocket is called with an instance of a UKSocket, it finds a registered adapter from instances of UKSocket. The adapter itself is a 1-argument callable that takes an argument of the type being adapted "from" (UKSocket) and returns a value of the type being adapted "to" (provider of IAmericanSocket). AdaptToAmericanSocket is a class, but classes are themselves callable, and since its constructor takes a UKSocket, it fits the contract of thing-that-takes-1-argument-of-type-UKSocket-and-returns-an-IAmericanSocket.
The existence of another class would not make a difference, unless it were registered as an adapter. If you register two adapters which might both be suitable their interactions are complicated, but since they both do the job, in theory you shouldn't care which one gets used.
Related
So I'm looking through some old python 2 code and I see this function
def manage_addMapSamlPlugin(self, id, title='', delegate_path='', REQUEST=None):
""" Factory method to instantiate a MapSamlPlugin """
# Make sure we really are working in our container (the
# PluggableAuthService object)
self = self.this()
# Instantiate the adapter object
lmp = MapSamlPlugin(id, title=title, delegate_path=delegate_path )
self._setObject(id, lmp)
if REQUEST is not None:
REQUEST.RESPONSE.redirect('%s/manage_main' % self.absolute_url())
Now this function is outside of a class, the code compiles and doesn't give any errors. My understanding is that the self keyword in this case is just anything that gets passed in, but self.this() and self._setObject(id, lmp) that shouldn't be a thing right? Shouldn't the compiler throw an error? The code is run on a terminal in a ssh server I don't know what compiler it uses.
At the end of the file this is where the function gets called.
def initialize(context):
registerMultiPlugin(MapSamlPlugin.meta_type)
context.registerClass(
MapSamlPlugin,
constructors=(manage_addMapSamlPluginForm, manage_addMapSamlPlugin),
permission=ManageUsers,
icon=os.path.join(mgr_dir, "saml_icon.png"),
visibility=None,
)
And this is also a standalone function "context" isn't derived from any imports or class.
The comment is an important clue:
def manage_addMapSamlPlugin(self, id, title='', delegate_path='', REQUEST=None):
""" Factory method to instantiate a MapSamlPlugin """
# Make sure we really are working in our container (the
# PluggableAuthService object)
self = self.this()
self is expected to be an object which has a this() method -- it sounds like that method returns a PluggableAuthService object. If you grep the rest of the code for def this you'll probably find it. Looking for class PluggableAuthService might also shed some light.
If you call this function and pass it a self that doesn't implement the expected interface, you'll get an AttributeError at runtime. Since there are no type annotations here, there's not really a way to catch errors statically (at "compile time" -- although typically compiling Python doesn't in itself enforce any static type checks).
My suspicion is that this function was originally a method of that class, and got refactored out of it for some reason (maybe as the first step in some larger refactor that was never finished). A class method works just fine if you yank it out of a class, provided that you explicitly provide the self parameter when you call it.
In a nutshell, I receive json events via an API and recently I've been learning a lot more about classes. One of the recommended ways to use classes is to implement getters, setters etc.. However, my classes aren't too sophisticated all they're doing is parsing data from a json object and passing better formatted data onto further ETL processes.
Below is a simple example of what I've encountered.
data = {'status': 'ready'}
class StatusHandler:
def __init__(self, data):
self.status = data.get('status', None)
class StatusHandler2:
def __init__(self, data):
self._status = data.get('status', None)
#property
def status(self):
return self._status
without_getter = StatusHandler(data)
print(without_getter.status)
with_getter = StatusHandler2(data)
print(with_getter.status)
Is there anything wrong with me using the class StatusHandler and referencing a status instance variable and using that to pass information forward to other bits of code? I'm just wondering if further down the line as my project gets more complicated that this would be an issue as it doesn't seem to be standard although I could be wrong...
The point of getters/setters is to avoid replacing plain attributes access with computed ones without breaking client code if and when you have to change your implementation. This only make sense for languages that have no support for computed attributes.
Python has a quite strong support for computed attributes thru the descriptor protocol, including the generic builtin property type, so you don't need explicit getters/setters - if you have to change your implementation, just replace affected public attributes by computed ones.
Just make sure to not abuse computed attributes - they should not make any heavy computation, external resource access or so. No one expects what looks like an attribute to have a high cost or raise IOErrors or so ;-)
EDIT
With regard to your example: computed attributes are a way to control attribute access, and making an attribute read-only (not providing a setter for your property) IS a perfectly valid use case - IF you have a reason to make it read-only of course.
I am a beginner in Python, so please be... kind?
Anyway, I need use a static method to call another method, which requires the use of "self" (and thus, a normal method I believe). I am working with Telethon, a Python implementation of Telegram. I have tried other questions on SO, but I just can't seem to find a solution to my problem.
An overview of the program (please correct me if I'm wrong):
1) interactive_telegram_client is a child class of telegram_client, and it creates an instance.
#interactive_telegram_client.py
class InteractiveTelegramClient(TelegramClient):
super().__init__(session_user_id, api_id, api_hash, proxy)
2) When the InteractiveTelegramClient runs, it adds an update_handler self.add_update_handler(self.update_handler) to constantly check for messages received/sent, and prints it to screen
#telegram_client.py
def add_update_handler(self, handler):
"""Adds an update handler (a function which takes a TLObject,
an update, as its parameter) and listens for updates"""
if not self.sender:
raise RuntimeError(
"You should connect at least once to add update handlers.")
self.sender.add_update_handler(handler)
#interactive_telegram_client.py
#staticmethod
def update_handler(update_object):
try:
if type(update_object) is UpdateShortMessage:
if update_object.out:
print('You sent {} to user #{}'.format(update_object.message,
update_object.user_id))
else:
print('[User #{} sent {}]'.format(update_object.user_id,
update_object.message))
Now, my aim here is to send back an auto-reply message upon receiving a message. Thus, I think that adding a call to method InteractiveTelegramClient.send_ack(update_object) in the update_handler method would serve my needs.
#interactive_telegram_client.py
def send_ack(self, update_object):
entity = update_object.user_id
message = update_object.message
msg, entities = parse_message_entities(message)
msg_id = utils.generate_random_long()
self.invoke(SendMessageRequest(peer=get_input_peer(entity),
message=msg,random_id=msg_id,entities=entities,no_webpage=False))
However, as you can see, I require the self to invoke this function (based on the readme, where I assume client to refer to the same thing as self). Since the method update_handler is a static one, self is not passed through, and as such I cannot invoke the call as such.
My possible strategies which have failed include:
1) Instantiating a new client for the auto-reply
- Creating a new client/conversation for each reply...
2) Making all the methods non-static
- Involves a tremendous amount of work since other methods modified as well
3) Observer pattern (sounds like a good idea, I tried, but due to a lack of skills, not succeeded)
I was wondering if there's any other way to tackle this problem? Or perhaps it's actually easy, just that I have some misconception somewhere?
Forgot to mention that due to some restrictions on my project, I can only use Telethon, as opposed to looking at other alternatives. Adopting another library (like an existing auto-reply one) is allowed, though I did not really look into that since merging that and Telethon may be too difficult for me...
based on the readme, where I assume client to refer to the same thing as self
Correct, since the InteractiveTelegramClient subclasses the TelegramClient and hence, self is an instance of the extended client.
Instantiating a new client for the auto-reply - Creating a new client/conversation for each reply
This would require you to create another authorization and send another code request to login, because you can't work with the same *.session at the same time.
Making all the methods non-static - Involves a tremendous amount of work since other methods modified as well
It doesn't require such amount of work. Consider the following example:
class Example:
def __init__(self, a):
self.a = a
def do_something(self):
Example.other_method()
#staticmethod
def other_method():
print('hello, world!')
Is equivalent to:
class Example:
def __init__(self, a):
self.a = a
def do_something(self):
self.other_method()
#staticmethod
def other_method():
print('hello, world!')
It doesn't matter whether you use self. or the class name to refer to a static method from within the class. Since the InteractiveClientExample already uses self., all you would have to do would be changing:
#staticmethod
def update_handler(update_object):
for
def update_handler(self, update_object):
For more on the #staticmethod decorator, you can refer to the docs.
I have some working code (library) that, in some situations, I only need a small subset of its functional.
Thinking of a simpler case, the code (library) is a class that takes a few parameters when initializing.
For my limited use case, many of those parameters are not vital as they are not directly used in the internal calculation (some parameters are only used when I call particular methods of the object), while it is very hard to prepare those parameters properly.
So, I am wondering, if there is any easy way to know what parameters are essential without fully analyzing the library code (which is too complicated). For example, I may pass fake parameters to the api, And it would raise an exception only if they are actually used.
For example, I can pass in some_parameter = None for some_parameter that I guess won't be used. So whenever the library tries to access some_parameter.some_field an exception would be raised thus I can further look into the issue and replace it by the actually parameter. However, it would change the behavior of the library if the code itself accepts None as a parameter.
Are there any established approach to this problem? I don't mind false positive as I can always look into the problem and manually check if the usage of the fake parameters by the library is trivial.
For those suggestions on reading documentation and code, I don't have documentations! And the code is legacy code left by previous developers.
Update
#sapi:
Yes I would like to use the proxy pattern / object: I will further investigate on such topic.
"A virtual proxy is a placeholder for "expensive to create" objects. The real object is only created when a client first requests/accesses the object."
I am assuming all classes in question are new-style. This is always the case if you are using Python 3; in Python 2, they must extend from object. You can check a class with isinstance(MyClass, type). For the remainder of my answer, I will assume Python 3, since it was not specified. If you are using Python 2, make sure to extend from object where no other base class is specified.
If those conditions hold, you can write a descriptor that raises an exception whenever it is accessed:
class ParameterUsed(Exception):
pass
class UsageDescriptor:
def __init__(self, name):
super(UsageDescriptor, self).__init__()
self.name = name
def __get__(self, instance, owner):
raise ParameterUsed(self.name)
def __set__(self, instance, value):
# Ignore sets if the value is None.
if value is not None:
raise ParameterUsed(self.name)
def __delete__(self, instance):
# Ignore deletes.
pass
I will assume we are using this class as an example:
class Example:
def __init__(self, a, b):
self.a = a
self.b = b
def use_a(self):
print(self.a)
def use_b(self):
print(self.b)
If we want to see if a is used anywhere, extend the class and put an instance of our descriptor on the class:
class ExtExample(Example):
a = UsageDescriptor('a')
Now if we were to try to use the class, we can see which methods use a:
>>> example = ExtExample(None, None)
>>> example.use_a()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ParameterUsed: a
>>> example.use_b()
None
Here, we can see that use_a tried to use a (raising an exception because it did), but use_b did not (it completed successfully).
This approach works more generally than sapi’s does: in particular, sapi’s approach will only detect an attribute being accessed on the object. But there are plenty of things you can do that do not access attributes on that object. This approach, rather than detecting attributes being accessed on that object, detects the object itself being accessed.
Depending on what you're looking to achieve, you may be able to pass in a proxy object which throws an exception when accessed.
For example:
class ObjectUsedException(Exception):
pass
class ErrorOnUseProxy(object):
def __getattr__(self, name):
raise ObjectUsedException('Tried to access %s'%name)
Of course, that approach will fail in two pretty common situations:
if the library itself checks if the attribute exists (eg, to provide some default value)
if it's treated as a primitive (float, string etc), though you could modify this approach to take that into account
I belive the simplest and least intrusive way is to turn the parameters into properties:
class Foo(object):
def __init__(self):
pass
#property
def a(self):
print >>sys.stderr, 'Accesing parameter a'
return 1
bar = Foo()
print bar.a == 1
Will print True in stdout, and Accesing parameter a to stderr. You would have to tweak it to allow the class to change it.
I would like to construct a class in python that supports dynamic updating of methods from user supplied source code.
Instances of class Agent have a method go. At the time an instance is constructed, its .go() method does nothing. For example, if we do a=Agent(), and then a.go() we should get a NotImplementedError or something like that. The user then should be able to interactively define a.go() by supplying source code. A simple source code example would be
mySourceString = "print('I learned how to go!')"
which would be injected into a like this
a.update(mySourceString)
Further invokations of a.go() would then result in "I learned how to go!" being printed to the screen.
I have partially figured out how to do this with the following code:
import types
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class NotImplementedError(Error):
pass
class Agent(object):
def go(self):
raise NotImplementedError()
def update(self,codeString):
#Indent each line of user supplied code
codeString = codeString.replace('\n','\n ')
#Turn code into a function called func
exec "def func(self):\n"+' '+codeString
#Make func a bound method on this instance
self.go = types.MethodType(func, self)
QUESTIONS
Is this implementation sensible?
Will this implementation incur unexpected scope issues?
Is there an obvious way to sandbox the user supplied code to prevent it from touching external objects? I can think of ways to do this by supplying sets of allowed external objects, but this seems not pythonic.
Possibly useful SO posts
What's the difference between eval, exec, and compile in Python?
Adding a Method to an Existing Object
(I am working in python 2.6)